├── .babelrc ├── .gitignore ├── .npmignore ├── README.md ├── module-helpers.js ├── module-loader.js ├── package.json ├── src ├── module-helpers │ ├── config.js │ ├── controller.js │ ├── decorator.js │ ├── directive.js │ ├── factory.js │ ├── filter.js │ ├── index.js │ ├── injectable.js │ ├── provider.js │ ├── runner.js │ └── service.js ├── module-loader.js └── utils.js └── test ├── index.html ├── lib ├── src ├── index.js └── specs │ ├── loader.spec.js │ └── module-helpers │ ├── config.spec.js │ ├── controller.spec.js │ ├── decorator.spec.js │ ├── directive.spec.js │ ├── factory.spec.js │ ├── filter.spec.js │ ├── injectable.spec.js │ ├── provider.spec.js │ ├── runner.spec.js │ └── service.spec.js └── webpack.config.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "stage-0"] 3 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | npm-debug.log 4 | test/dist -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | test -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Angular-Ecmascript 2 | 3 | `angular-ecmascript` is a utility library which will help you write an [AngularJS](https://angularjs.org) app using `ES6`'s class system. 4 | As for now there is no official way to do so, however using `ES6` syntax is recommended, hence this library was created. 5 | 6 | In addition, `angular-ecmascript` provides us with some very handy features, like auto-injection without using any pre-processors like [ng-annotate](https://github.com/olov/ng-annotate). For more information about `angular-ecmascript`'s API and features please read the following [docs](#docs). 7 | 8 | ## Docs 9 | 10 | `angular-ecmascript` provides us with some base `module-helpers` classes which we should inherit from while writing our helpers. These are the available helpers: 11 | 12 | - [Provider](#provider) 13 | - [Service](#service) 14 | - [Factory](#factory) 15 | - [Controller](#controller) 16 | - [Directive](#directive) 17 | - [Decorator](#decorator) 18 | - [Filter](#filter) 19 | - [Config](#config) 20 | - [Runner](#runner) 21 | 22 | Each helper can be defined with a static `$inject` property which will be responsible for dependencies injection, and a static `$name` property, which is responsible for specifying the helper's name and defaults to the class'es name. 23 | 24 | ```js 25 | import { Service, Controller } from 'angular-ecmascript/module-helpers'; 26 | 27 | class DateService extends Service { 28 | static $name = '$date' 29 | 30 | now() { 31 | return new Date().getTime(); 32 | } 33 | } 34 | 35 | class MyController extends Controller { 36 | static $inject = ['$date'] 37 | 38 | constructor(...args) { 39 | super(...args); 40 | 41 | this.createdAt = this.$date.now(); 42 | } 43 | } 44 | ``` 45 | 46 | To interface with these helpers we will need to use a `module-loader` provided by `angular-ecmascript`. Just create a new `AngularJS` module wrapped by the loader and use it like so: 47 | 48 | ```js 49 | // libs 50 | import Angular from 'angular'; 51 | import Loader from 'angular-ecmascript/module-loader'; 52 | // module-helpers 53 | import MyCtrl from './controllers/my.ctrl'; 54 | import MyDirective from './directives/my.directive'; 55 | import MyService from './services/my.service'; 56 | 57 | // app 58 | App = Angular.module('my-app', [ 59 | 'module1', 60 | 'module2', 61 | 'module3' 62 | ]); 63 | 64 | // loader 65 | new Loader(App) 66 | .load(MyCtrl) 67 | .load(MyDirective) 68 | .load(MyService); 69 | ``` 70 | 71 | - `Loader()` can take a module name as the first argument and an optional dependencies array if you'd like to load a module by name. 72 | - `Loader.load()` can take an array of several module-helpers instead of chaining them one-by-one. 73 | - `Loader.load()` can take a string as the first argument representing the provider type and its value as the second argument, just like the [$provide](https://docs.angularjs.org/api/auto/service/$provide) service. 74 | 75 | ### Provider 76 | 77 | Used to define a new [provider](https://docs.angularjs.org/guide/providers). 78 | 79 | ```js 80 | import { Provider } from 'angular-ecmascript/module-helpers'; 81 | 82 | class MomentProvider extends Provider { 83 | static $name = '$now' 84 | 85 | $get() { 86 | return new Date().getTime(); 87 | } 88 | } 89 | ``` 90 | 91 | ### Service 92 | 93 | Used to define a new [service](https://docs.angularjs.org/guide/services). 94 | 95 | ```js 96 | import { Service } from 'angular-ecmascript/module-helpers'; 97 | 98 | class DateService extends Service { 99 | static $name = '$date' 100 | 101 | now() { 102 | return new Date().getTime(); 103 | } 104 | } 105 | ``` 106 | 107 | ### Factory 108 | 109 | Used to define a new `factory`. 110 | 111 | - Note that the `create` method must be implemented, otherwise an error will be thrown during load time. 112 | 113 | ```js 114 | import { Factory } from 'angular-ecmascript/module-helpers'; 115 | 116 | class MomentFactory extends Factory { 117 | static $name = 'now' 118 | 119 | create() { 120 | return new Date().getTime(); 121 | } 122 | } 123 | ``` 124 | 125 | ### Controller 126 | 127 | Used to define a new [controller](https://docs.angularjs.org/guide/controller). 128 | 129 | - `$scope` will be injected automatically so no need to specify it. 130 | - When using [angular-meteor](https://github.com/Urigo/angular-meteor) the controller will be set as the view model automatically. 131 | 132 | ```js 133 | import { Controller } from 'angular-ecmascript/module-helpers'; 134 | 135 | class MyController extends Controller { 136 | constructor(...args) { 137 | super(...args); 138 | 139 | this.createdAt = new Date().getTime(); 140 | } 141 | 142 | logCreationTime() { 143 | console.log(`created at: ${this.createdAy}`); 144 | } 145 | } 146 | ``` 147 | 148 | ### Directive 149 | 150 | Used to define a new [directive](https://docs.angularjs.org/guide/directive). 151 | 152 | ```js 153 | import { Directive } from 'angular-ecmascript/module-helpers'; 154 | 155 | class MyDirective extends Directive { 156 | templateUrl: 'my-template.html' 157 | restrict = 'E' 158 | transclude = true 159 | scope = {} 160 | 161 | link(scope) { 162 | scope.foo = 'foo'; 163 | scope.bar = 'bar'; 164 | } 165 | } 166 | ``` 167 | 168 | ### Decorator 169 | 170 | Used to define a new [decorator](https://docs.angularjs.org/guide/decorators). 171 | 172 | - `$delegate` will be injected automatically so no need to specify it. 173 | - Note that the `decorate` method must be implemented, otherwise an error will be thrown during load time. 174 | - No need to return the `$delegate` object, it should be handled automatically. 175 | 176 | ```js 177 | import { Decorator } from 'angular-ecmascript/module-helpers'; 178 | 179 | class MyDecorator extends Decorator { 180 | static $name = 'myService' 181 | 182 | helperFn() { 183 | // an additional fn to add to the service 184 | } 185 | 186 | decorate() { 187 | this.$delegate.aHelpfulAddition = this.helperFn; 188 | } 189 | } 190 | ``` 191 | 192 | ### Filter 193 | 194 | Used to define a new [filter](https://docs.angularjs.org/guide/filter). 195 | 196 | - Note that the `filter` method must be implemented, otherwise an error will be thrown during load time. 197 | 198 | ```js 199 | import { Filter } from 'angular-ecmascript/module-helpers'; 200 | 201 | class MyFilter extends Filter { 202 | filter(input = '', uppercase) { 203 | let out = ''; 204 | 205 | for (let i = 0; i < input.length; i++) { 206 | out = input.charAt(i) + out; 207 | } 208 | 209 | // conditional based on optional argument 210 | if (uppercase) { 211 | out = out.toUpperCase(); 212 | } 213 | 214 | return out; 215 | } 216 | } 217 | ``` 218 | 219 | ### Config 220 | 221 | Used to define a new `config`. 222 | 223 | - Note that the `configure` method must be implemented, otherwise an error will be thrown during load time. 224 | 225 | ```js 226 | import { Config } from 'angular-ecmascript/module-helpers'; 227 | 228 | class RoutesCfg extends Config { 229 | static $inject = ['$routeProvider'] 230 | 231 | constructor(...args) { 232 | super(...args); 233 | 234 | this.fetchUser = ['http', this::this.fetchUser]; 235 | } 236 | 237 | configure() { 238 | this.$routeProvider 239 | .when('/', { 240 | template: '', 241 | resolve: { 242 | user: this.fetchUser 243 | } 244 | }); 245 | } 246 | 247 | fetchUser($http) { 248 | return $http.get('...'); 249 | } 250 | } 251 | ``` 252 | 253 | ### Runner 254 | 255 | Used to define a new `run block`. 256 | 257 | - Note that the `run` method must be implemented, otherwise an error will be thrown during load time. 258 | 259 | ```js 260 | import { Runner } from 'angular-meteor/module-helpers'; 261 | 262 | class RoutesRunner extends Runner { 263 | static $inject = ['$rootScope', '$state'] 264 | 265 | run() { 266 | this.$rootScope.$on('$stateChangeError', (...args) => { 267 | const [,,, err] = args; 268 | 269 | if (err === 'AUTH_REQUIRED') { 270 | this.$state.go('login'); 271 | } 272 | }); 273 | } 274 | } 275 | ``` 276 | 277 | ## Download 278 | 279 | The source is available for download from [GitHub](http://github.com/DAB0mB/angular-ecmascript). Alternatively, you can install using Node Package Manager (`npm`): 280 | 281 | npm install angular-ecmascript 282 | -------------------------------------------------------------------------------- /module-helpers.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./dist/module-helpers'); 2 | -------------------------------------------------------------------------------- /module-loader.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./dist/module-loader'); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-ecmascript", 3 | "description": "Build an AngularJS app using ES6's class system", 4 | "version": "0.0.3", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/DAB0mB/angular-ecmascript.git" 8 | }, 9 | "scripts": { 10 | "build": "babel src/ -d dist/ --source-maps", 11 | "build:watch": "babel src/ -d dist/ --source-maps --watch", 12 | "test": "xdg-open ./test/index.html", 13 | "test:build": "npm run build && webpack --config ./test/webpack.config.js", 14 | "test:build:watch": "npm run build:watch & webpack --config ./test/webpack.config.js --watch", 15 | "prepublish": "npm run build" 16 | }, 17 | "peerDependencies": { 18 | "angular": "^1.5.0" 19 | }, 20 | "devDependencies": { 21 | "angular": "^1.5.0", 22 | "babel-cli": "^6.8.0", 23 | "babel-core": "^6.7.6", 24 | "babel-loader": "^6.2.4", 25 | "babel-plugin-add-module-exports": "^0.1.2", 26 | "babel-preset-es2015": "^6.6.0", 27 | "babel-preset-stage-0": "^6.5.0", 28 | "jasmine-core": "^2.4.0", 29 | "webpack": "^1.13.0" 30 | }, 31 | "keywords": [ 32 | "angular", 33 | "ecmascript", 34 | "angular-ecmascript" 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /src/module-helpers/config.js: -------------------------------------------------------------------------------- 1 | import Injectable from './injectable'; 2 | 3 | export default class Config extends Injectable { 4 | configure() { 5 | throw Error('Config#configure() must be implemented'); 6 | } 7 | } -------------------------------------------------------------------------------- /src/module-helpers/controller.js: -------------------------------------------------------------------------------- 1 | import Injectable from './injectable'; 2 | import * as Utils from '../utils'; 3 | 4 | export default class Controller extends Injectable { 5 | constructor(...args) { 6 | super(...args); 7 | 8 | const createViewModel = this.$scope && 9 | (this.$scope.$viewModel || this.$scope.viewModel); 10 | 11 | if (Utils.isFunction(createViewModel)) { 12 | this.$scope::createViewModel(this); 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /src/module-helpers/decorator.js: -------------------------------------------------------------------------------- 1 | import Injectable from './injectable'; 2 | 3 | export default class Decorator extends Injectable { 4 | decorate() { 5 | throw Error('Decorator#decorate() must be implemented'); 6 | } 7 | } -------------------------------------------------------------------------------- /src/module-helpers/directive.js: -------------------------------------------------------------------------------- 1 | import Injectable from './injectable'; 2 | 3 | export default class Directive extends Injectable { 4 | compile() { 5 | return this.link.bind(this); 6 | } 7 | } -------------------------------------------------------------------------------- /src/module-helpers/factory.js: -------------------------------------------------------------------------------- 1 | import Injectable from './injectable'; 2 | 3 | export default class Factory extends Injectable { 4 | create() { 5 | throw Error('Factory#create() must be implemented'); 6 | } 7 | } -------------------------------------------------------------------------------- /src/module-helpers/filter.js: -------------------------------------------------------------------------------- 1 | import Injectable from './injectable'; 2 | 3 | export default class Filter extends Injectable { 4 | filter() { 5 | throw Error('Filter#filter() must be implemented'); 6 | } 7 | } -------------------------------------------------------------------------------- /src/module-helpers/index.js: -------------------------------------------------------------------------------- 1 | export Injectable from './injectable'; 2 | export Directive from './directive'; 3 | export Controller from './controller'; 4 | export Filter from './filter'; 5 | export Config from './config'; 6 | export Factory from './factory'; 7 | export Service from './service'; 8 | export Provider from './provider'; 9 | export Runner from './runner'; 10 | export Decorator from './decorator'; 11 | -------------------------------------------------------------------------------- /src/module-helpers/injectable.js: -------------------------------------------------------------------------------- 1 | export default class Injectable { 2 | constructor(...args) { 3 | this.constructor.$inject.forEach((name, i) => { 4 | this[name] = args[i]; 5 | }); 6 | } 7 | } -------------------------------------------------------------------------------- /src/module-helpers/provider.js: -------------------------------------------------------------------------------- 1 | import Injectable from './injectable'; 2 | 3 | export default class Provider extends Injectable {} -------------------------------------------------------------------------------- /src/module-helpers/runner.js: -------------------------------------------------------------------------------- 1 | import Injectable from './injectable'; 2 | 3 | export default class Runner extends Injectable { 4 | run() { 5 | throw Error('Runner#run() must be implemented'); 6 | } 7 | } -------------------------------------------------------------------------------- /src/module-helpers/service.js: -------------------------------------------------------------------------------- 1 | import Injectable from './injectable'; 2 | 3 | export default class Service extends Injectable {} -------------------------------------------------------------------------------- /src/module-loader.js: -------------------------------------------------------------------------------- 1 | import Angular from 'angular'; 2 | import * as Helpers from './module-helpers'; 3 | import * as Utils from './utils'; 4 | 5 | export default class Loader { 6 | constructor(ngModule, dependencies) { 7 | if (Utils.isString(ngModule)) { 8 | ngModule = Angular.module(ngModule, dependencies); 9 | } 10 | 11 | this.module = ngModule; 12 | } 13 | 14 | load(Helper, ...args) { 15 | if (Utils.isFunction(Helper)) { 16 | const proto = Helper.prototype; 17 | Helper.$name = Helper.$name || Helper.name; 18 | Helper.$inject = Helper.$inject || []; 19 | 20 | if (proto instanceof Helpers.Provider) 21 | this.loadProvider(Helper); 22 | else if (proto instanceof Helpers.Service) 23 | this.loadService(Helper); 24 | else if (proto instanceof Helpers.Controller) 25 | this.loadController(Helper); 26 | else if (proto instanceof Helpers.Directive) 27 | this.loadDirective(Helper); 28 | else if (proto instanceof Helpers.Decorator) 29 | this.loadDecorator(Helper); 30 | else if (proto instanceof Helpers.Factory) 31 | this.loadFactory(Helper); 32 | else if (proto instanceof Helpers.Filter) 33 | this.loadFilter(Helper); 34 | else if (proto instanceof Helpers.Config) 35 | this.loadConfig(Helper); 36 | else if (proto instanceof Helpers.Runner) 37 | this.loadRunner(Helper); 38 | else 39 | throw Error('can\'t load unknown module-helper'); 40 | } 41 | else if (Utils.isArray(Helper)) { 42 | Helper.forEach(Helper => this.load(Helper)); 43 | } 44 | else if (Utils.isString(Helper)) { 45 | this.module[Helper](...args); 46 | } 47 | else { 48 | throw Error('`Helper` must be a function or a string'); 49 | } 50 | 51 | return this; 52 | } 53 | 54 | loadProvider(Provider) { 55 | this.module.provider(Provider.$name, Provider); 56 | } 57 | 58 | loadService(Service) { 59 | this.module.service(Service.$name, Service) 60 | } 61 | 62 | loadController(Controller) { 63 | const $inject = Controller.$inject; 64 | 65 | if (!Utils.hasValue($inject, '$scope')) { 66 | $inject.unshift('$scope'); 67 | } 68 | 69 | this.module.controller(Controller.$name, Controller); 70 | } 71 | 72 | loadDirective(Directive) { 73 | const helper = (...args) => { 74 | return new Directive(...args); 75 | } 76 | 77 | helper.$inject = Directive.$inject; 78 | this.module.directive(Directive.$name, helper); 79 | } 80 | 81 | loadDecorator(Decorator) { 82 | let decorator; 83 | const $inject = Decorator.$inject; 84 | 85 | const helper = (...args) => { 86 | decorator = new Decorator(...args); 87 | return decorate; 88 | } 89 | 90 | const decorate = (...args) => { 91 | decorator.decorate(...args); 92 | return decorator.$delegate; 93 | } 94 | 95 | if (!Utils.hasValue($inject, '$delegate')) { 96 | $inject.unshift('$delegate'); 97 | } 98 | 99 | this.module.decorator(Decorator.$name, helper); 100 | } 101 | 102 | loadFactory(Factory) { 103 | const helper = (...args) => { 104 | const factory = new Factory(...args); 105 | return factory::factory.create; 106 | } 107 | 108 | helper.$inject = Factory.$inject; 109 | this.module.factory(Factory.$name, helper); 110 | } 111 | 112 | loadFilter(Filter) { 113 | const helper = (...args) => { 114 | const filter = new Filter(...args); 115 | return filter::filter.filter; 116 | } 117 | 118 | helper.$inject = Filter.$inject; 119 | this.module.filter(Filter.$name, helper); 120 | } 121 | 122 | loadConfig(Config) { 123 | const helper = (...args) => { 124 | const config = new Config(...args); 125 | return config.configure(); 126 | } 127 | 128 | helper.$inject = Config.$inject; 129 | this.module.config(helper); 130 | } 131 | 132 | loadRunner(Runner) { 133 | const helper = (...args) => { 134 | const runner = new Runner(...args); 135 | return runner.run(); 136 | } 137 | 138 | helper.$inject = Runner.$inject; 139 | this.module.run(helper); 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /src/utils.js: -------------------------------------------------------------------------------- 1 | export function hasValue(obj, v) { 2 | return getValues(obj).indexOf(v) != -1; 3 | }; 4 | 5 | export function hasKey(obj, k) { 6 | return getKeys(obj).indexOf(k) != -1; 7 | }; 8 | 9 | export function getValues(obj) { 10 | return getKeys(obj).map(function(k) { 11 | return obj[k]; 12 | }); 13 | }; 14 | 15 | export function getKeys(obj) { 16 | return Object.keys(obj); 17 | }; 18 | 19 | export function isHash(obj) { 20 | return obj.__proto__ === Object.prototype; 21 | } 22 | 23 | export function isArray(arr) { 24 | return arr instanceof Array; 25 | } 26 | 27 | export function isString(str) { 28 | return typeof str == 'string'; 29 | } 30 | 31 | export function isFunction(fn) { 32 | return typeof fn == 'function'; 33 | } -------------------------------------------------------------------------------- /test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | angular-ecmascript test 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /test/lib: -------------------------------------------------------------------------------- 1 | ../node_modules/ -------------------------------------------------------------------------------- /test/src/index.js: -------------------------------------------------------------------------------- 1 | import Angular from 'angular'; 2 | import Loader from 'angular-ecmascript/module-loader'; 3 | 4 | import './specs/loader.spec.js'; 5 | import './specs/module-helpers/injectable.spec'; 6 | import './specs/module-helpers/directive.spec'; 7 | import './specs/module-helpers/controller.spec'; 8 | import './specs/module-helpers/filter.spec'; 9 | import './specs/module-helpers/config.spec'; 10 | import './specs/module-helpers/factory.spec'; 11 | import './specs/module-helpers/service.spec'; 12 | import './specs/module-helpers/provider.spec'; 13 | import './specs/module-helpers/runner.spec'; 14 | import './specs/module-helpers/decorator.spec'; 15 | 16 | beforeEach(function() { 17 | this.module = Angular.module('angular-ecmascript-test', []); 18 | this.loader = new Loader(this.module); 19 | }); -------------------------------------------------------------------------------- /test/src/specs/loader.spec.js: -------------------------------------------------------------------------------- 1 | import Angular from 'angular'; 2 | import Loader from 'angular-ecmascript/module-loader'; 3 | import * as Helpers from 'angular-ecmascript/module-helpers'; 4 | 5 | describe('Loader', function() { 6 | it('should create a new module if not specified', function() { 7 | spyOn(Angular, 'module'); 8 | 9 | const moduleName = 'custom-module'; 10 | const moduleDeps = ['module1', 'module2']; 11 | const loader = new Loader(moduleName, moduleDeps); 12 | const definition = Angular.module.calls.mostRecent() 13 | 14 | expect(definition.args).toEqual([moduleName, moduleDeps]); 15 | }); 16 | 17 | it('should load multiple helpers given an array', function() { 18 | spyOn(this.module, 'provider'); 19 | spyOn(this.module, 'service'); 20 | spyOn(this.module, 'controller'); 21 | 22 | class TestProvider extends Helpers.Provider {} 23 | class TestService extends Helpers.Service {} 24 | class TestCtrl extends Helpers.Controller {} 25 | 26 | this.loader.load([TestProvider, TestService, TestCtrl]); 27 | 28 | expect(this.module.provider).toHaveBeenCalledWith('TestProvider', TestProvider); 29 | expect(this.module.service).toHaveBeenCalledWith('TestService', TestService); 30 | expect(this.module.controller).toHaveBeenCalledWith('TestCtrl', TestCtrl); 31 | }); 32 | 33 | it('should load a custom helper given a string', function() { 34 | this.module.helper = jasmine.createSpy('helper'); 35 | const helper = Angular.noop; 36 | 37 | this.loader.load('helper', helper); 38 | const definition = this.module.helper.calls.mostRecent(); 39 | 40 | expect(definition.args).toEqual([helper]); 41 | }); 42 | }); -------------------------------------------------------------------------------- /test/src/specs/module-helpers/config.spec.js: -------------------------------------------------------------------------------- 1 | import { Config } from 'angular-ecmascript/module-helpers'; 2 | 3 | describe('Config', function() { 4 | beforeEach(function() { 5 | spyOn(this.module, 'config').and.callThrough(); 6 | }); 7 | 8 | it('should load a config helper', function() { 9 | const $dep = {}; 10 | const expectedResult = {}; 11 | const ctorSpy = jasmine.createSpy('ctor'); 12 | 13 | class TestConfig extends Config { 14 | static $inject = ['$dep'] 15 | 16 | constructor(...args) { 17 | super(...args); 18 | this::ctorSpy(...args); 19 | } 20 | 21 | configure(...args) { 22 | return expectedResult; 23 | } 24 | } 25 | 26 | this.loader.load(TestConfig); 27 | 28 | const load = this.module.config.calls.mostRecent(); 29 | const [helper] = load.args; 30 | 31 | const result = helper($dep); 32 | const config = ctorSpy.calls.mostRecent().object; 33 | 34 | expect(config).toEqual(jasmine.any(TestConfig)); 35 | expect(config.$dep).toEqual($dep); 36 | expect(result).toEqual(expectedResult); 37 | }); 38 | }); -------------------------------------------------------------------------------- /test/src/specs/module-helpers/controller.spec.js: -------------------------------------------------------------------------------- 1 | import { Controller } from 'angular-ecmascript/module-helpers'; 2 | 3 | describe('Controller', function() { 4 | beforeEach(function() { 5 | spyOn(this.module, 'controller').and.callThrough(); 6 | }); 7 | 8 | it('should set controller as the view model when using `angular-meteor`', function() { 9 | class TestController extends Controller { 10 | static $inject = ['$scope'] 11 | } 12 | 13 | const $scope = { 14 | $viewModel: jasmine.createSpy('$viewModel') 15 | }; 16 | 17 | const controller = new TestController($scope); 18 | expect($scope.$viewModel).toHaveBeenCalledWith(controller); 19 | }); 20 | 21 | it('should load a controller helper', function() { 22 | class TestController extends Controller { 23 | static $inject = ['$scope'] 24 | } 25 | 26 | this.loader.load(TestController); 27 | 28 | const load = this.module.controller.calls.mostRecent(); 29 | const [name, helper] = load.args; 30 | 31 | expect(name).toEqual('TestController'); 32 | expect(helper).toEqual(TestController); 33 | }); 34 | 35 | it('should load a controller with a custom name', function() { 36 | class TestController extends Controller { 37 | static $name = 'customControllerName' 38 | static $inject = ['$scope'] 39 | } 40 | 41 | this.loader.load(TestController); 42 | 43 | const load = this.module.controller.calls.mostRecent(); 44 | const [name, helper] = load.args; 45 | 46 | expect(name).toEqual('customControllerName'); 47 | expect(helper).toEqual(TestController); 48 | }); 49 | 50 | it('should inject a `$scope` dependency by default', function() { 51 | class TestController extends Controller { 52 | static $inject = ['$dep']; 53 | } 54 | 55 | this.loader.load(TestController); 56 | expect(TestController.$inject).toEqual(['$scope', '$dep']); 57 | 58 | const load = this.module.controller.calls.mostRecent(); 59 | const [name, helper] = load.args; 60 | 61 | expect(name).toEqual('TestController'); 62 | expect(helper).toEqual(TestController); 63 | }); 64 | }); -------------------------------------------------------------------------------- /test/src/specs/module-helpers/decorator.spec.js: -------------------------------------------------------------------------------- 1 | import { Decorator } from 'angular-ecmascript/module-helpers'; 2 | 3 | describe('Decorator', function() { 4 | beforeEach(function() { 5 | spyOn(this.module, 'decorator').and.callThrough(); 6 | }); 7 | 8 | it('should load a decorator helper', function() { 9 | const $delegate = {}; 10 | const ctorSpy = jasmine.createSpy('ctor'); 11 | const methodSpy = jasmine.createSpy('method'); 12 | 13 | class TestDecorator extends Decorator { 14 | static $inject = ['$delegate'] 15 | 16 | constructor(...args) { 17 | super(...args); 18 | this::ctorSpy(...args); 19 | } 20 | 21 | decorate(...args) { 22 | this::methodSpy(...args); 23 | } 24 | } 25 | 26 | this.loader.load(TestDecorator); 27 | 28 | const load = this.module.decorator.calls.mostRecent(); 29 | const [name, helper] = load.args; 30 | 31 | expect(name).toEqual('TestDecorator'); 32 | 33 | const method = helper($delegate); 34 | const result = method(); 35 | const expectedDecorator = ctorSpy.calls.mostRecent().object; 36 | const decorator = methodSpy.calls.mostRecent().object; 37 | 38 | expect(expectedDecorator).toEqual(jasmine.any(Decorator)); 39 | expect(decorator).toEqual(expectedDecorator); 40 | expect(decorator.$delegate).toEqual($delegate); 41 | expect(result).toEqual($delegate); 42 | }); 43 | 44 | it('should load a decorator with a custom name', function() { 45 | const $delegate = {}; 46 | const ctorSpy = jasmine.createSpy('ctor'); 47 | const methodSpy = jasmine.createSpy('method'); 48 | 49 | class TestDecorator extends Decorator { 50 | static $inject = ['$delegate'] 51 | static $name = 'customDecoratorName' 52 | 53 | constructor(...args) { 54 | super(...args); 55 | this::ctorSpy(...args); 56 | } 57 | 58 | decorate(...args) { 59 | this::methodSpy(...args); 60 | } 61 | } 62 | 63 | this.loader.load(TestDecorator); 64 | 65 | const load = this.module.decorator.calls.mostRecent(); 66 | const [name, helper] = load.args; 67 | 68 | expect(name).toEqual('customDecoratorName'); 69 | 70 | const method = helper($delegate); 71 | const result = method(); 72 | const expectedDecorator = ctorSpy.calls.mostRecent().object; 73 | const decorator = methodSpy.calls.mostRecent().object; 74 | 75 | expect(expectedDecorator).toEqual(jasmine.any(TestDecorator)); 76 | expect(decorator).toEqual(expectedDecorator); 77 | expect(result).toEqual($delegate); 78 | }); 79 | 80 | it('should inject a `$delegate` dependency by default', function() { 81 | const $delegate = {}; 82 | const $dep = {}; 83 | const ctorSpy = jasmine.createSpy('ctor'); 84 | const methodSpy = jasmine.createSpy('method'); 85 | 86 | class TestDecorator extends Decorator { 87 | static $inject = ['$dep'] 88 | 89 | constructor(...args) { 90 | super(...args); 91 | this::ctorSpy(...args); 92 | } 93 | 94 | decorate(...args) { 95 | this::methodSpy(...args); 96 | } 97 | } 98 | 99 | this.loader.load(TestDecorator); 100 | expect(TestDecorator.$inject).toEqual(['$delegate', '$dep']); 101 | 102 | const load = this.module.decorator.calls.mostRecent(); 103 | const [name, helper] = load.args; 104 | 105 | expect(name).toEqual('TestDecorator'); 106 | 107 | const method = helper($delegate, $dep); 108 | const result = method(); 109 | const expectedDecorator = ctorSpy.calls.mostRecent().object; 110 | const decorator = methodSpy.calls.mostRecent().object; 111 | 112 | expect(expectedDecorator).toEqual(jasmine.any(TestDecorator)); 113 | expect(decorator).toEqual(expectedDecorator); 114 | expect(decorator.$dep).toEqual($dep); 115 | expect(result).toEqual($delegate); 116 | }); 117 | }); -------------------------------------------------------------------------------- /test/src/specs/module-helpers/directive.spec.js: -------------------------------------------------------------------------------- 1 | import { Directive } from 'angular-ecmascript/module-helpers'; 2 | 3 | describe('Directive', function() { 4 | beforeEach(function() { 5 | spyOn(this.module, 'directive').and.callThrough(); 6 | }); 7 | 8 | it('should load a directive helper', function() { 9 | const $dep = {}; 10 | const expectedResult = {}; 11 | const ctorSpy = jasmine.createSpy('ctor'); 12 | 13 | class TestDirective extends Directive { 14 | static $inject = ['$dep'] 15 | 16 | constructor(...args) { 17 | super(...args); 18 | this::ctorSpy(...args); 19 | } 20 | } 21 | 22 | this.loader.load(TestDirective); 23 | 24 | const load = this.module.directive.calls.mostRecent(); 25 | const [name, helper] = load.args; 26 | 27 | expect(name).toEqual('TestDirective'); 28 | 29 | const create = helper($dep); 30 | const directive = ctorSpy.calls.mostRecent().object; 31 | 32 | expect(directive).toEqual(jasmine.any(TestDirective)); 33 | expect(directive.$dep).toEqual($dep); 34 | }); 35 | 36 | it('should load a directive with a custom name', function() { 37 | const $dep = {}; 38 | const expectedResult = {}; 39 | const ctorSpy = jasmine.createSpy('ctor'); 40 | 41 | class TestDirective extends Directive { 42 | static $inject = ['$dep'] 43 | static $name = 'customDirectiveName' 44 | 45 | constructor(...args) { 46 | super(...args); 47 | this::ctorSpy(...args); 48 | } 49 | } 50 | 51 | this.loader.load(TestDirective); 52 | 53 | const load = this.module.directive.calls.mostRecent(); 54 | const [name, helper] = load.args; 55 | 56 | expect(name).toEqual('customDirectiveName'); 57 | 58 | const create = helper($dep); 59 | const directive = ctorSpy.calls.mostRecent().object; 60 | 61 | expect(directive).toEqual(jasmine.any(TestDirective)); 62 | expect(directive.$dep).toEqual($dep); 63 | }); 64 | }); -------------------------------------------------------------------------------- /test/src/specs/module-helpers/factory.spec.js: -------------------------------------------------------------------------------- 1 | import { Factory } from 'angular-ecmascript/module-helpers'; 2 | 3 | describe('Factory', function() { 4 | beforeEach(function() { 5 | spyOn(this.module, 'factory').and.callThrough(); 6 | }); 7 | 8 | it('should load a factory helper', function() { 9 | const $dep = {}; 10 | const expectedResult = {}; 11 | const ctorSpy = jasmine.createSpy('ctor'); 12 | const methodSpy = jasmine.createSpy('method'); 13 | 14 | class TestFactory extends Factory { 15 | static $inject = ['$dep'] 16 | 17 | constructor(...args) { 18 | super(...args); 19 | this::ctorSpy(...args); 20 | } 21 | 22 | create(...args) { 23 | this::methodSpy(...args); 24 | return expectedResult; 25 | } 26 | } 27 | 28 | this.loader.load(TestFactory); 29 | 30 | const load = this.module.factory.calls.mostRecent(); 31 | const [name, helper] = load.args; 32 | 33 | expect(name).toEqual('TestFactory'); 34 | 35 | const method = helper($dep); 36 | const result = method(); 37 | const expectedFactory = ctorSpy.calls.mostRecent().object; 38 | const factory = methodSpy.calls.mostRecent().object; 39 | 40 | expect(expectedFactory).toEqual(jasmine.any(TestFactory)); 41 | expect(factory).toEqual(expectedFactory); 42 | expect(factory.$dep).toEqual($dep); 43 | expect(result).toEqual(expectedResult); 44 | }); 45 | 46 | it('should load a factory with a custom name', function() { 47 | const $dep = {}; 48 | const expectedResult = {}; 49 | const ctorSpy = jasmine.createSpy('ctor'); 50 | const methodSpy = jasmine.createSpy('method'); 51 | 52 | class TestFactory extends Factory { 53 | static $inject = ['$dep'] 54 | static $name = 'customFactoryName' 55 | 56 | constructor(...args) { 57 | super(...args); 58 | this::ctorSpy(...args); 59 | } 60 | 61 | create(...args) { 62 | this::methodSpy(...args); 63 | return expectedResult; 64 | } 65 | } 66 | 67 | this.loader.load(TestFactory); 68 | 69 | const load = this.module.factory.calls.mostRecent(); 70 | const [name, helper] = load.args; 71 | 72 | expect(name).toEqual('customFactoryName'); 73 | 74 | const method = helper($dep); 75 | const result = method(); 76 | const expectedFactory = ctorSpy.calls.mostRecent().object; 77 | const factory = methodSpy.calls.mostRecent().object; 78 | 79 | expect(expectedFactory).toEqual(jasmine.any(TestFactory)); 80 | expect(factory).toEqual(expectedFactory); 81 | expect(factory.$dep).toEqual($dep); 82 | expect(result).toEqual(expectedResult); 83 | }); 84 | }); -------------------------------------------------------------------------------- /test/src/specs/module-helpers/filter.spec.js: -------------------------------------------------------------------------------- 1 | import { Filter } from 'angular-ecmascript/module-helpers'; 2 | 3 | describe('Filter', function() { 4 | beforeEach(function() { 5 | spyOn(this.module, 'filter').and.callThrough(); 6 | }); 7 | 8 | it('should load a filter helper', function() { 9 | const $dep = {}; 10 | const expectedResult = {}; 11 | const ctorSpy = jasmine.createSpy('ctor'); 12 | const methodSpy = jasmine.createSpy('method'); 13 | 14 | class TestFilter extends Filter { 15 | static $inject = ['$dep'] 16 | 17 | constructor(...args) { 18 | super(...args); 19 | this::ctorSpy(...args); 20 | } 21 | 22 | filter(...args) { 23 | this::methodSpy(...args); 24 | return expectedResult; 25 | } 26 | } 27 | 28 | this.loader.load(TestFilter); 29 | 30 | const load = this.module.filter.calls.mostRecent(); 31 | const [name, helper] = load.args; 32 | 33 | expect(name).toEqual('TestFilter'); 34 | 35 | const method = helper($dep); 36 | const result = method(); 37 | const expectedFilter = ctorSpy.calls.mostRecent().object; 38 | const filter = methodSpy.calls.mostRecent().object; 39 | 40 | expect(expectedFilter).toEqual(jasmine.any(TestFilter)); 41 | expect(filter).toEqual(expectedFilter); 42 | expect(filter.$dep).toEqual($dep); 43 | expect(result).toEqual(expectedResult); 44 | }); 45 | 46 | it('should load a filter with a custom name', function() { 47 | const $dep = {}; 48 | const expectedResult = {}; 49 | const ctorSpy = jasmine.createSpy('ctor'); 50 | const methodSpy = jasmine.createSpy('method'); 51 | 52 | class TestFilter extends Filter { 53 | static $inject = ['$dep'] 54 | static $name = 'customFilterName' 55 | 56 | constructor(...args) { 57 | super(...args); 58 | this::ctorSpy(...args); 59 | } 60 | 61 | filter(...args) { 62 | this::methodSpy(...args); 63 | return expectedResult; 64 | } 65 | } 66 | 67 | this.loader.load(TestFilter); 68 | 69 | const load = this.module.filter.calls.mostRecent(); 70 | const [name, helper] = load.args; 71 | 72 | expect(name).toEqual('customFilterName'); 73 | 74 | const method = helper($dep); 75 | const result = method(); 76 | const expectedFilter = ctorSpy.calls.mostRecent().object; 77 | const filter = methodSpy.calls.mostRecent().object; 78 | 79 | expect(expectedFilter).toEqual(jasmine.any(TestFilter)); 80 | expect(filter).toEqual(expectedFilter); 81 | expect(filter.$dep).toEqual($dep); 82 | expect(result).toEqual(expectedResult); 83 | }); 84 | }); -------------------------------------------------------------------------------- /test/src/specs/module-helpers/injectable.spec.js: -------------------------------------------------------------------------------- 1 | import { Injectable } from 'angular-ecmascript/module-helpers'; 2 | 3 | describe('Injectable', function() { 4 | it('should define injected dependencies on instance', function() { 5 | const $dep1 = {}; 6 | const $dep2 = {}; 7 | const $dep3 = {}; 8 | 9 | class TestInjectable extends Injectable { 10 | static $inject = ['$dep1', '$dep2', '$dep3']; 11 | } 12 | 13 | var injectable = new TestInjectable($dep1, $dep2, $dep3); 14 | expect(injectable.$dep1).toEqual($dep1); 15 | expect(injectable.$dep2).toEqual($dep2); 16 | expect(injectable.$dep3).toEqual($dep3); 17 | }); 18 | }); -------------------------------------------------------------------------------- /test/src/specs/module-helpers/provider.spec.js: -------------------------------------------------------------------------------- 1 | import { Provider } from 'angular-ecmascript/module-helpers'; 2 | 3 | describe('Provider', function() { 4 | beforeEach(function() { 5 | spyOn(this.module, 'provider').and.callThrough(); 6 | }); 7 | 8 | it('should load a proider helper', function() { 9 | class TestProvider extends Provider {} 10 | 11 | this.loader.load(TestProvider); 12 | 13 | const load = this.module.provider.calls.mostRecent(); 14 | const [name, helper] = load.args; 15 | 16 | expect(name).toEqual('TestProvider'); 17 | expect(helper).toEqual(TestProvider); 18 | }); 19 | 20 | it('should load a provider with a custom name', function() { 21 | class TestProvider extends Provider { 22 | static $name = 'customProviderName' 23 | } 24 | 25 | this.loader.load(TestProvider); 26 | 27 | const load = this.module.provider.calls.mostRecent(); 28 | const [name, helper] = load.args; 29 | 30 | expect(name).toEqual('customProviderName'); 31 | expect(helper).toEqual(TestProvider); 32 | }); 33 | }); -------------------------------------------------------------------------------- /test/src/specs/module-helpers/runner.spec.js: -------------------------------------------------------------------------------- 1 | import { Runner } from 'angular-ecmascript/module-helpers'; 2 | 3 | describe('Runner', function() { 4 | beforeEach(function() { 5 | spyOn(this.module, 'run').and.callThrough(); 6 | }); 7 | 8 | it('should load a runner helper', function() { 9 | const $dep = {}; 10 | const expectedResult = {}; 11 | const ctorSpy = jasmine.createSpy('ctor'); 12 | 13 | class TestRunner extends Runner { 14 | static $inject = ['$dep'] 15 | 16 | constructor(...args) { 17 | super(...args); 18 | this::ctorSpy(...args); 19 | } 20 | 21 | run(...args) { 22 | return expectedResult; 23 | } 24 | } 25 | 26 | this.loader.load(TestRunner); 27 | 28 | const load = this.module.run.calls.mostRecent(); 29 | const [helper] = load.args; 30 | 31 | const result = helper($dep); 32 | const runner = ctorSpy.calls.mostRecent().object; 33 | 34 | expect(runner).toEqual(jasmine.any(TestRunner)); 35 | expect(runner.$dep).toEqual($dep); 36 | expect(result).toEqual(expectedResult); 37 | }); 38 | }); -------------------------------------------------------------------------------- /test/src/specs/module-helpers/service.spec.js: -------------------------------------------------------------------------------- 1 | import { Service } from 'angular-ecmascript/module-helpers'; 2 | 3 | describe('Service', function() { 4 | beforeEach(function() { 5 | spyOn(this.module, 'service').and.callThrough(); 6 | }); 7 | 8 | it('should load a service helper', function() { 9 | class TestService extends Service {} 10 | 11 | this.loader.load(TestService); 12 | 13 | const load = this.module.service.calls.mostRecent(); 14 | const [name, helper] = load.args; 15 | 16 | expect(name).toEqual('TestService'); 17 | expect(helper).toEqual(TestService); 18 | }); 19 | 20 | it('should load a service with a custom', function() { 21 | class TestService extends Service { 22 | static $name = 'customServiceName' 23 | } 24 | 25 | this.loader.load(TestService); 26 | 27 | const load = this.module.service.calls.mostRecent(); 28 | const [name, helper] = load.args; 29 | 30 | expect(name).toEqual('customServiceName'); 31 | expect(helper).toEqual(TestService); 32 | }); 33 | }); -------------------------------------------------------------------------------- /test/webpack.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | entry: [ 3 | __dirname + '/src/index.js' 4 | ], 5 | output: { 6 | path: __dirname + '/dist', 7 | filename: 'test.bundle.js' 8 | }, 9 | target: 'web', 10 | devtool: 'source-map', 11 | babel: { 12 | presets: ['es2015', 'stage-0'], 13 | plugins: ['add-module-exports'] 14 | }, 15 | module: { 16 | loaders: [{ 17 | test: /test\/src\/.*\.js$/, 18 | loader: 'babel' 19 | }] 20 | }, 21 | resolve: { 22 | moduleDirectories: ['lib'], 23 | extensions: ['', '.js'] 24 | } 25 | }; --------------------------------------------------------------------------------