├── .travis.yml ├── src ├── writers.js ├── tests │ ├── frameworks.js │ └── angular.js ├── decorators │ ├── providers │ │ ├── provider.js │ │ ├── service.js │ │ ├── controller.js │ │ ├── factory.js │ │ ├── filter.js │ │ ├── directive.js │ │ ├── animation.js │ │ ├── component.js │ │ ├── directive.spec.js │ │ ├── service.spec.js │ │ ├── animation.spec.js │ │ ├── filter.spec.js │ │ ├── controller.spec.js │ │ ├── component.spec.js │ │ └── factory.spec.js │ ├── component │ │ ├── transclude.js │ │ ├── require.js │ │ ├── transclude.spec.js │ │ ├── view.js │ │ ├── require.spec.js │ │ └── view.spec.js │ ├── inject.js │ └── inject.spec.js ├── util │ ├── decorator-factory.js │ ├── parse-selector.spec.js │ ├── parse-selector.js │ ├── decorate.spec.js │ ├── parse-properties.spec.js │ ├── decorate.js │ ├── parse-properties.js │ ├── decorate-directive.js │ └── decorate-directive.spec.js ├── index.js ├── index.d.ts ├── module.js └── module.spec.js ├── .eslintrc ├── dist ├── decorators │ ├── component │ │ ├── transclude.js │ │ ├── require.js │ │ ├── view.js │ │ ├── transclude.spec.js │ │ ├── require.spec.js │ │ └── view.spec.js │ ├── inject.js │ ├── providers │ │ ├── service.js │ │ ├── provider.js │ │ ├── controller.js │ │ ├── directive.js │ │ ├── filter.js │ │ ├── component.js │ │ ├── factory.js │ │ ├── animation.js │ │ ├── directive.spec.js │ │ ├── animation.spec.js │ │ ├── filter.spec.js │ │ ├── controller.spec.js │ │ ├── service.spec.js │ │ ├── component.spec.js │ │ └── factory.spec.js │ └── inject.spec.js ├── util │ ├── decorator-factory.js │ ├── decorate.spec.js │ ├── parse-selector.js │ ├── parse-selector.spec.js │ ├── parse-properties.spec.js │ ├── parse-properties.js │ ├── decorate.js │ ├── decorate-directive.js │ └── decorate-directive.spec.js ├── writers.js ├── tests │ ├── frameworks.js │ └── angular.js ├── index.d.ts ├── index.js ├── module.spec.js ├── module.js └── angular-decorators.js ├── karma.conf.js ├── gulpfile.js ├── .gitignore ├── bower.json ├── package.json ├── changelog.md └── README.md /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "0.12" 4 | - "0.11" 5 | - "iojs" 6 | - "iojs-v1.0.4" -------------------------------------------------------------------------------- /src/writers.js: -------------------------------------------------------------------------------- 1 | import Metawriter from 'metawriter'; 2 | 3 | export let baseWriter = new Metawriter('$ng-decs'); 4 | export let providerWriter = new Metawriter('provider', baseWriter); 5 | export let componentWriter = new Metawriter('component', baseWriter); -------------------------------------------------------------------------------- /src/tests/frameworks.js: -------------------------------------------------------------------------------- 1 | import chai from 'chai'; 2 | import sinonChai from 'sinon-chai'; 3 | import sinon from 'sinon'; 4 | 5 | chai.use(sinonChai); 6 | 7 | chai.should(); 8 | 9 | let expect = chai.expect; 10 | 11 | export default chai; 12 | export {expect, sinon}; -------------------------------------------------------------------------------- /src/decorators/providers/provider.js: -------------------------------------------------------------------------------- 1 | import Module from '../../module'; 2 | import decoratorFactory from '../../util/decorator-factory'; 3 | 4 | const TYPE = 'provider'; 5 | 6 | export const Provider = decoratorFactory(TYPE); 7 | 8 | Module.addProvider(TYPE, (provider, name, injects, ngModule) => { 9 | ngModule.provider(name, [...injects, provider]); 10 | }); -------------------------------------------------------------------------------- /src/decorators/providers/service.js: -------------------------------------------------------------------------------- 1 | import Module from '../../module'; 2 | import decoratorFactory from '../../util/decorator-factory'; 3 | 4 | const TYPE = 'service'; 5 | 6 | export const Service = decoratorFactory(TYPE); 7 | 8 | Module.addProvider(TYPE, (provider, name, injects, ngModule) => { 9 | ngModule.service(name, [...injects, provider]); 10 | }); -------------------------------------------------------------------------------- /src/decorators/component/transclude.js: -------------------------------------------------------------------------------- 1 | import {componentWriter} from '../../writers'; 2 | 3 | export const Transclude = maybeT => { 4 | if(typeof maybeT === 'string' || typeof maybeT === 'boolean') 5 | { 6 | return t => componentWriter.set('transclude', maybeT, t); 7 | } 8 | else 9 | { 10 | componentWriter.set('transclude', true, maybeT); 11 | } 12 | }; -------------------------------------------------------------------------------- /src/decorators/providers/controller.js: -------------------------------------------------------------------------------- 1 | import Module from '../../module'; 2 | import decoratorFactory from '../../util/decorator-factory'; 3 | 4 | const TYPE = 'controller'; 5 | 6 | export const Controller = decoratorFactory(TYPE); 7 | 8 | Module.addProvider(TYPE, (provider, name, injects, ngModule) => { 9 | ngModule.controller(name, [...injects, provider]); 10 | }); -------------------------------------------------------------------------------- /src/decorators/inject.js: -------------------------------------------------------------------------------- 1 | import {baseWriter} from '../writers'; 2 | 3 | export const Inject = ( ...dependencies ) => t => { 4 | if(baseWriter.has('$inject', t)) 5 | { 6 | let parentInjects = baseWriter.get('$inject', t); 7 | baseWriter.set('$inject', [...dependencies, ...parentInjects], t); 8 | } 9 | else 10 | { 11 | baseWriter.set('$inject', dependencies, t); 12 | } 13 | } -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser" : "babel-eslint", 3 | "rules" : { 4 | "strict" : 0, 5 | "quotes" : [1, "single"], 6 | "new-cap" : 0, 7 | "eol-last" : 0, 8 | "no-shadow" : 0, 9 | "no-trailing-spaces" : 0, 10 | "no-underscore-dangle" : 0, 11 | "no-unused-vars" : [2, { 12 | "args" : "none" 13 | }] 14 | }, 15 | "globals" : { 16 | "window" : false, 17 | "require" : false 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/decorators/component/require.js: -------------------------------------------------------------------------------- 1 | import {componentWriter} from '../../writers'; 2 | 3 | export const Require = (...components) => t => { 4 | if(componentWriter.has('require', t)) 5 | { 6 | let oldRequires = componentWriter.get('require', t); 7 | componentWriter.set('require', [...oldRequires, ...components], t); 8 | } 9 | else 10 | { 11 | componentWriter.set('require', components, t); 12 | } 13 | } -------------------------------------------------------------------------------- /src/util/decorator-factory.js: -------------------------------------------------------------------------------- 1 | import {providerWriter} from '../writers'; 2 | 3 | export default type => maybeT => { 4 | if(typeof maybeT === 'string') 5 | { 6 | return t => { 7 | providerWriter.set('type', type, t); 8 | providerWriter.set('name', maybeT, t); 9 | }; 10 | } 11 | else 12 | { 13 | providerWriter.set('type', type, maybeT); 14 | providerWriter.set('name', maybeT.name, maybeT); 15 | } 16 | } -------------------------------------------------------------------------------- /src/tests/angular.js: -------------------------------------------------------------------------------- 1 | import {sinon} from '../tests/frameworks'; 2 | 3 | export let ngMocks = { 4 | factory: sinon.spy(), 5 | config: sinon.spy(), 6 | run: sinon.spy(), 7 | service: sinon.spy(), 8 | animation: sinon.spy(), 9 | directive: sinon.spy(), 10 | provider: sinon.spy(), 11 | filter: sinon.spy(), 12 | value: sinon.spy(), 13 | constant: sinon.spy() 14 | }; 15 | 16 | export let angular = { 17 | module: sinon.stub().returns(ngMocks) 18 | }; 19 | 20 | global.angular = angular; -------------------------------------------------------------------------------- /dist/decorators/component/transclude.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | 7 | var _writers = require('../../writers'); 8 | 9 | var Transclude = function Transclude(maybeT) { 10 | if (typeof maybeT === 'string' || typeof maybeT === 'boolean') { 11 | return function (t) { 12 | return _writers.componentWriter.set('transclude', maybeT, t); 13 | }; 14 | } else { 15 | _writers.componentWriter.set('transclude', true, maybeT); 16 | } 17 | }; 18 | exports.Transclude = Transclude; -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | module.exports = function(config) { 2 | config.set({ 3 | browsers: ['Chrome'], 4 | frameworks: ['jasmine'], 5 | files: [ 6 | 'src/**/*.js', 7 | 'test/**/*.js' 8 | ], 9 | preprocessors: { 10 | 'src/**/*.js': ['babel'], 11 | 'test/**/*.js': ['babel'] 12 | }, 13 | babelPreprocessor: { 14 | options: { 15 | sourceMap: 'inline' 16 | }, 17 | filename: function(file) { 18 | return file.originalPath.replace(/\.js$/, '.es5.js'); 19 | }, 20 | sourceFileName: function(file) { 21 | return file.originalPath; 22 | } 23 | } 24 | }); 25 | }; -------------------------------------------------------------------------------- /src/decorators/providers/factory.js: -------------------------------------------------------------------------------- 1 | import Module from '../../module'; 2 | import decoratorFactory from '../../util/decorator-factory'; 3 | 4 | const TYPE = 'factory'; 5 | 6 | export const Factory = decoratorFactory(TYPE); 7 | 8 | Module.addProvider(TYPE, (provider, name, injects, ngModule) => { 9 | let create = provider.create || function(dependencies, ...params){ 10 | return new provider(...dependencies, ...params); 11 | }; 12 | 13 | function factory(...dependencies){ 14 | return function(...params){ 15 | return create(dependencies, ...params); 16 | } 17 | } 18 | 19 | ngModule.factory(name, [...injects, factory]); 20 | }); -------------------------------------------------------------------------------- /dist/util/decorator-factory.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | 7 | var _writers = require('../writers'); 8 | 9 | exports['default'] = function (type) { 10 | return function (maybeT) { 11 | if (typeof maybeT === 'string') { 12 | return function (t) { 13 | _writers.providerWriter.set('type', type, t); 14 | _writers.providerWriter.set('name', maybeT, t); 15 | }; 16 | } else { 17 | _writers.providerWriter.set('type', type, maybeT); 18 | _writers.providerWriter.set('name', maybeT.name, maybeT); 19 | } 20 | }; 21 | }; 22 | 23 | module.exports = exports['default']; -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'); 2 | var babel = require('gulp-babel'); 3 | var mocha = require('gulp-mocha'); 4 | 5 | gulp.task('transpile', function () { 6 | return gulp.src('src/**/*.js') 7 | .pipe(babel({ 8 | stage: 0 9 | })) 10 | .pipe(gulp.dest('dist')); 11 | }); 12 | 13 | gulp.task('build', ['transpile'], function () { 14 | return gulp.src('src/index.d.ts') 15 | .pipe(gulp.dest('dist')); 16 | }); 17 | 18 | gulp.task('test', ['build'], function (done) { 19 | return gulp.src('dist/**/*.spec.js') 20 | .pipe(mocha({ reporter: 'spec' })); 21 | }); 22 | 23 | gulp.task('default', function(){ 24 | gulp.watch('./src/**/*.js', ['test']); 25 | }); 26 | -------------------------------------------------------------------------------- /dist/writers.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | 7 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 8 | 9 | var _metawriter = require('metawriter'); 10 | 11 | var _metawriter2 = _interopRequireDefault(_metawriter); 12 | 13 | var baseWriter = new _metawriter2['default']('$ng-decs'); 14 | exports.baseWriter = baseWriter; 15 | var providerWriter = new _metawriter2['default']('provider', baseWriter); 16 | exports.providerWriter = providerWriter; 17 | var componentWriter = new _metawriter2['default']('component', baseWriter); 18 | exports.componentWriter = componentWriter; -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # node-waf configuration 20 | .lock-wscript 21 | 22 | # Compiled binary addons (http://nodejs.org/api/addons.html) 23 | build/Release 24 | 25 | # Dependency directory 26 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 27 | node_modules 28 | bower_components 29 | 30 | # DS_Store 31 | .DS_Store 32 | -------------------------------------------------------------------------------- /src/decorators/providers/filter.js: -------------------------------------------------------------------------------- 1 | import Module from '../../module'; 2 | import decoratorFactory from '../../util/decorator-factory'; 3 | 4 | const TYPE = 'filter'; 5 | 6 | export const Filter = decoratorFactory(TYPE); 7 | 8 | Module.addProvider(TYPE, (provider, name, injects, ngModule) => { 9 | ngModule.filter(name, [...injects, (...dependencies) => { 10 | let filter = new provider(...dependencies); 11 | 12 | if(! filter.transform){ 13 | throw new Error('Filters must implement a transform method'); 14 | } 15 | 16 | return (input, ...params) => { 17 | if(filter.supports && ! filter.supports(input)){ 18 | throw new Error(`Filter ${name} does not support ${input}`); 19 | } 20 | 21 | return filter.transform(input, ...params); 22 | } 23 | }]); 24 | }); -------------------------------------------------------------------------------- /dist/tests/frameworks.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | 7 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 8 | 9 | var _chai = require('chai'); 10 | 11 | var _chai2 = _interopRequireDefault(_chai); 12 | 13 | var _sinonChai = require('sinon-chai'); 14 | 15 | var _sinonChai2 = _interopRequireDefault(_sinonChai); 16 | 17 | var _sinon = require('sinon'); 18 | 19 | var _sinon2 = _interopRequireDefault(_sinon); 20 | 21 | _chai2['default'].use(_sinonChai2['default']); 22 | 23 | _chai2['default'].should(); 24 | 25 | var expect = _chai2['default'].expect; 26 | 27 | exports['default'] = _chai2['default']; 28 | exports.expect = expect; 29 | exports.sinon = _sinon2['default']; -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-decorators", 3 | "version": "1.2.0", 4 | "homepage": "https://github.com/MikeRyan52/angular-decorators", 5 | "authors": [ 6 | "Mike Ryan " 7 | ], 8 | "description": "A collection of utilities and annotations that make it easier to write Angular 2 style code in AngularJS 1.x", 9 | "main": "./dist/angular-decorators.js", 10 | "moduleType": [ 11 | "node" 12 | ], 13 | "keywords": [ 14 | "angular", 15 | "angular2", 16 | "angularjs", 17 | "annotations", 18 | "decorators", 19 | "ecmascript6" 20 | ], 21 | "license": "MIT", 22 | "ignore": [ 23 | "**/.*", 24 | "node_modules", 25 | "bower_components", 26 | "test", 27 | "tests" 28 | ], 29 | "dependencies": { 30 | "reflect-metadata": "~0.1.1" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /dist/tests/angular.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | 7 | var _testsFrameworks = require('../tests/frameworks'); 8 | 9 | var ngMocks = { 10 | factory: _testsFrameworks.sinon.spy(), 11 | config: _testsFrameworks.sinon.spy(), 12 | run: _testsFrameworks.sinon.spy(), 13 | service: _testsFrameworks.sinon.spy(), 14 | animation: _testsFrameworks.sinon.spy(), 15 | directive: _testsFrameworks.sinon.spy(), 16 | provider: _testsFrameworks.sinon.spy(), 17 | filter: _testsFrameworks.sinon.spy(), 18 | value: _testsFrameworks.sinon.spy(), 19 | constant: _testsFrameworks.sinon.spy() 20 | }; 21 | 22 | exports.ngMocks = ngMocks; 23 | var angular = { 24 | module: _testsFrameworks.sinon.stub().returns(ngMocks) 25 | }; 26 | 27 | exports.angular = angular; 28 | global.angular = angular; -------------------------------------------------------------------------------- /src/decorators/component/transclude.spec.js: -------------------------------------------------------------------------------- 1 | import {Transclude} from './transclude'; 2 | import {componentWriter} from '../../writers'; 3 | import {expect} from '../../tests/frameworks'; 4 | 5 | describe('@Transclude Component decorator', function(){ 6 | it('should add the transclude key on the DDO', function(){ 7 | @Transclude 8 | class MyClass{ } 9 | 10 | componentWriter.has('transclude', MyClass).should.be.ok; 11 | componentWriter.get('transclude', MyClass).should.be.ok; 12 | }); 13 | 14 | it('should let you pass a string or boolean value to the decorator', function(){ 15 | @Transclude(true) 16 | class First{ } 17 | 18 | @Transclude('element') 19 | class Second{ } 20 | 21 | componentWriter.get('transclude', First).should.be.ok; 22 | componentWriter.get('transclude', Second).should.eql('element'); 23 | }); 24 | }); -------------------------------------------------------------------------------- /src/decorators/component/view.js: -------------------------------------------------------------------------------- 1 | import {componentWriter} from '../../writers'; 2 | 3 | export const View = config => t => { 4 | if( typeof config !== 'object' || ( !config.templateUrl && !config.template ) || t === undefined ) 5 | { 6 | throw new Error('Config object must be passed to the view decorator with either a view url or an inline template'); 7 | } 8 | 9 | if(config.templateUrl) 10 | { 11 | if(componentWriter.has('template', t)) 12 | { 13 | componentWriter.set('template', undefined, t); 14 | } 15 | 16 | componentWriter.set('templateUrl', config.templateUrl, t); 17 | } 18 | else if(config.template) 19 | { 20 | if(componentWriter.has('templateUrl', t)) 21 | { 22 | componentWriter.set('templateUrl', undefined, t); 23 | } 24 | 25 | componentWriter.set('template', config.template, t); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/decorators/providers/directive.js: -------------------------------------------------------------------------------- 1 | import decorateDirective from '../../util/decorate-directive'; 2 | import parseSelector from '../../util/parse-selector'; 3 | import {providerWriter, componentWriter} from '../../writers'; 4 | 5 | const TYPE = 'directive'; 6 | 7 | export const Directive = config => t => { 8 | if(! config.selector ) 9 | { 10 | throw new Error('Directive selector must be provided'); 11 | } 12 | 13 | let {name, type} = parseSelector(config.selector); 14 | 15 | if(type === 'E') 16 | { 17 | throw new Error('Directives cannot be elements. Perhaps you meant to use @Component?'); 18 | } 19 | 20 | providerWriter.set('name', name, t); 21 | providerWriter.set('type', TYPE, t); 22 | 23 | // Sensible defaults for attribute directives 24 | componentWriter.set('scope', false, t); 25 | componentWriter.set('restrict', type, t); 26 | 27 | decorateDirective(config, t); 28 | } 29 | -------------------------------------------------------------------------------- /src/util/parse-selector.spec.js: -------------------------------------------------------------------------------- 1 | import parseSelector from './parse-selector'; 2 | import chai from '../tests/frameworks'; 3 | 4 | describe('Component selector parser', function(){ 5 | it('should correctly parse element selectors', function(){ 6 | let info = parseSelector('my-component-selector'); 7 | 8 | info.should.have.property('name', 'myComponentSelector'); 9 | info.should.have.property('type', 'E'); 10 | 11 | info = parseSelector('component'); 12 | 13 | info.name.should.equal('component'); 14 | }); 15 | 16 | it('should correctly parse attribute selectors', function(){ 17 | let info = parseSelector('[my-attr]'); 18 | 19 | info.name.should.equal('myAttr'); 20 | info.type.should.equal('A'); 21 | }); 22 | 23 | it('should correctly parse class selectors', function(){ 24 | let info = parseSelector('.my-class'); 25 | 26 | info.name.should.equal('myClass'); 27 | info.type.should.equal('C'); 28 | }); 29 | }); -------------------------------------------------------------------------------- /dist/decorators/inject.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | 7 | function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; return arr2; } else { return Array.from(arr); } } 8 | 9 | var _writers = require('../writers'); 10 | 11 | var Inject = function Inject() { 12 | for (var _len = arguments.length, dependencies = Array(_len), _key = 0; _key < _len; _key++) { 13 | dependencies[_key] = arguments[_key]; 14 | } 15 | 16 | return function (t) { 17 | if (_writers.baseWriter.has('$inject', t)) { 18 | var parentInjects = _writers.baseWriter.get('$inject', t); 19 | _writers.baseWriter.set('$inject', [].concat(dependencies, _toConsumableArray(parentInjects)), t); 20 | } else { 21 | _writers.baseWriter.set('$inject', dependencies, t); 22 | } 23 | }; 24 | }; 25 | exports.Inject = Inject; -------------------------------------------------------------------------------- /src/util/parse-selector.js: -------------------------------------------------------------------------------- 1 | export default function(selector){ 2 | let selectorArray; 3 | let type; 4 | 5 | if( selector.match(/\[(.*?)\]/) !== null ) 6 | { 7 | selectorArray = selector.slice(1, selector.length - 1).split('-'); 8 | type = 'A'; 9 | } 10 | else if( selector[0] === '.' ) 11 | { 12 | selectorArray = selector.slice(1, selector.length).split('-'); 13 | type = 'C'; 14 | } 15 | else 16 | { 17 | selectorArray = selector.split('-'); 18 | type = 'E'; 19 | } 20 | 21 | let first = selectorArray.shift(); 22 | let name; 23 | 24 | if(selectorArray.length > 0) 25 | { 26 | for(let i = 0; i < selectorArray.length; i++) 27 | { 28 | let s = selectorArray[i]; 29 | s = s.slice(0, 1).toUpperCase() + s.slice(1, s.length); 30 | selectorArray[i] = s; 31 | } 32 | 33 | name = [first, ...selectorArray].join(''); 34 | } 35 | else 36 | { 37 | name = first; 38 | } 39 | 40 | return { name, type }; 41 | } 42 | -------------------------------------------------------------------------------- /src/util/decorate.spec.js: -------------------------------------------------------------------------------- 1 | import {sinon} from '../tests/frameworks'; 2 | import {d, register, registerFactory} from './decorate'; 3 | 4 | describe('Decorator helpers for ES5/ES6', function(){ 5 | it('should export the d helper object and two registeration functions', function(){ 6 | d.should.be.defined; 7 | register.should.be.defined; 8 | registerFactory.should.be.defined; 9 | }); 10 | 11 | it('should let you register new simple decorators', function(){ 12 | let spy = sinon.spy(); 13 | register('Test', spy); 14 | d.Test.for(function(){ }); 15 | 16 | d.Test.should.be.defined; 17 | spy.should.have.been.called; 18 | }); 19 | 20 | it('should let you register new decorator factories', function(){ 21 | let spy = sinon.spy(); 22 | registerFactory('NewTest', () => spy); 23 | d.NewTest().for(function(){ }); 24 | 25 | d.NewTest.should.be.defined; 26 | spy.should.have.been.called; 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /dist/decorators/component/require.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | 7 | function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; return arr2; } else { return Array.from(arr); } } 8 | 9 | var _writers = require('../../writers'); 10 | 11 | var Require = function Require() { 12 | for (var _len = arguments.length, components = Array(_len), _key = 0; _key < _len; _key++) { 13 | components[_key] = arguments[_key]; 14 | } 15 | 16 | return function (t) { 17 | if (_writers.componentWriter.has('require', t)) { 18 | var oldRequires = _writers.componentWriter.get('require', t); 19 | _writers.componentWriter.set('require', [].concat(_toConsumableArray(oldRequires), components), t); 20 | } else { 21 | _writers.componentWriter.set('require', components, t); 22 | } 23 | }; 24 | }; 25 | exports.Require = Require; -------------------------------------------------------------------------------- /src/decorators/providers/animation.js: -------------------------------------------------------------------------------- 1 | import Module from '../../module'; 2 | import {providerWriter} from '../../writers'; 3 | import parseSelector from '../../util/parse-selector'; 4 | 5 | const TYPE = 'animation'; 6 | 7 | export const Animation = className => { 8 | if(typeof className !== 'string') 9 | { 10 | throw new Error(`@Animation must be supplied with the name of a class: @Animation('.my-animation'`); 11 | } 12 | 13 | let {type} = parseSelector(className); 14 | 15 | if(type !== 'C') 16 | { 17 | throw new Error(`Invalid selector passed to @Animation: ${className} is not a class selector`); 18 | } 19 | 20 | return target => { 21 | 22 | providerWriter.set('type', TYPE, target); 23 | providerWriter.set('name', className, target); 24 | } 25 | } 26 | 27 | Module.addProvider(TYPE, (provider, name, injects, ngModule) => { 28 | ngModule.animation(name, [...injects, (...depends) => { 29 | return new provider(...depends); 30 | }]); 31 | }); -------------------------------------------------------------------------------- /src/decorators/component/require.spec.js: -------------------------------------------------------------------------------- 1 | import {Require} from './require'; 2 | import {componentWriter} from '../../writers'; 3 | import {expect} from '../../tests/frameworks'; 4 | 5 | describe('@Require Component Decorator', function(){ 6 | it('should add the require DDO key to the target', function(){ 7 | @Require() 8 | class MyClass{ } 9 | 10 | componentWriter.has('require', MyClass).should.be.ok; 11 | }); 12 | 13 | it('should set an array of requires as the value for the require key', function(){ 14 | @Require('a', 'b') 15 | class MyClass{ } 16 | 17 | Array.isArray(componentWriter.get('require', MyClass)).should.be.ok; 18 | componentWriter.get('require', MyClass).should.eql(['a', 'b']); 19 | }); 20 | 21 | it('should respect inheritance', function(){ 22 | @Require('a') 23 | class Parent{ } 24 | 25 | @Require('b') 26 | class Child extends Parent{ } 27 | 28 | componentWriter.get('require', Child).should.eql(['a', 'b']); 29 | }); 30 | }); -------------------------------------------------------------------------------- /src/decorators/inject.spec.js: -------------------------------------------------------------------------------- 1 | import {Inject} from './inject'; 2 | import {baseWriter} from '../writers'; 3 | import chai from '../tests/frameworks'; 4 | 5 | describe('@Inject annotation', function(){ 6 | it('should decorate a function with the $inject array', function(){ 7 | @Inject('a', 'b', 'c') 8 | class MyClass{ } 9 | 10 | baseWriter.has('$inject', MyClass).should.be.ok; 11 | }); 12 | 13 | it('should add injected dependencies to the $inject array', function(){ 14 | @Inject('a', 'b', 'c') 15 | class MyClass{ } 16 | 17 | baseWriter.get('$inject', MyClass).should.eql(['a', 'b', 'c']); 18 | }); 19 | 20 | it('should adhere to inheritance', function(){ 21 | @Inject('a', 'b', 'c') 22 | class MyClass{ } 23 | 24 | @Inject('d', 'e', 'f') 25 | class SubClass extends MyClass{ } 26 | 27 | baseWriter.get('$inject', MyClass).should.eql(['a', 'b', 'c']); 28 | baseWriter.get('$inject', SubClass).should.eql(['d', 'e', 'f', 'a', 'b', 'c']); 29 | }); 30 | }); -------------------------------------------------------------------------------- /dist/decorators/providers/service.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | 7 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 8 | 9 | function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; return arr2; } else { return Array.from(arr); } } 10 | 11 | var _module2 = require('../../module'); 12 | 13 | var _module3 = _interopRequireDefault(_module2); 14 | 15 | var _utilDecoratorFactory = require('../../util/decorator-factory'); 16 | 17 | var _utilDecoratorFactory2 = _interopRequireDefault(_utilDecoratorFactory); 18 | 19 | var TYPE = 'service'; 20 | 21 | var Service = (0, _utilDecoratorFactory2['default'])(TYPE); 22 | 23 | exports.Service = Service; 24 | _module3['default'].addProvider(TYPE, function (provider, name, injects, ngModule) { 25 | ngModule.service(name, [].concat(_toConsumableArray(injects), [provider])); 26 | }); -------------------------------------------------------------------------------- /dist/decorators/component/view.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | 7 | var _writers = require('../../writers'); 8 | 9 | var View = function View(config) { 10 | return function (t) { 11 | if (typeof config !== 'object' || !config.templateUrl && !config.template || t === undefined) { 12 | throw new Error('Config object must be passed to the view decorator with either a view url or an inline template'); 13 | } 14 | 15 | if (config.templateUrl) { 16 | if (_writers.componentWriter.has('template', t)) { 17 | _writers.componentWriter.set('template', undefined, t); 18 | } 19 | 20 | _writers.componentWriter.set('templateUrl', config.templateUrl, t); 21 | } else if (config.template) { 22 | if (_writers.componentWriter.has('templateUrl', t)) { 23 | _writers.componentWriter.set('templateUrl', undefined, t); 24 | } 25 | 26 | _writers.componentWriter.set('template', config.template, t); 27 | } 28 | }; 29 | }; 30 | exports.View = View; -------------------------------------------------------------------------------- /dist/decorators/providers/provider.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | 7 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 8 | 9 | function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; return arr2; } else { return Array.from(arr); } } 10 | 11 | var _module2 = require('../../module'); 12 | 13 | var _module3 = _interopRequireDefault(_module2); 14 | 15 | var _utilDecoratorFactory = require('../../util/decorator-factory'); 16 | 17 | var _utilDecoratorFactory2 = _interopRequireDefault(_utilDecoratorFactory); 18 | 19 | var TYPE = 'provider'; 20 | 21 | var Provider = (0, _utilDecoratorFactory2['default'])(TYPE); 22 | 23 | exports.Provider = Provider; 24 | _module3['default'].addProvider(TYPE, function (provider, name, injects, ngModule) { 25 | ngModule.provider(name, [].concat(_toConsumableArray(injects), [provider])); 26 | }); -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import Module from './module'; 2 | import { Inject } from './decorators/inject'; 3 | 4 | import { Animation } from './decorators/providers/animation'; 5 | import { Component } from './decorators/providers/component'; 6 | import { Controller } from './decorators/providers/controller'; 7 | import { Directive } from './decorators/providers/directive'; 8 | import { Factory } from './decorators/providers/factory'; 9 | import { Filter } from './decorators/providers/filter'; 10 | import { Provider } from './decorators/providers/provider'; 11 | import { Service } from './decorators/providers/service'; 12 | 13 | import { Require } from './decorators/component/require'; 14 | import { View } from './decorators/component/view'; 15 | import { Transclude } from './decorators/component/transclude'; 16 | 17 | export { 18 | Module, 19 | Inject, 20 | 21 | Component, 22 | Controller, 23 | Directive, 24 | Filter, 25 | Provider, 26 | Factory, 27 | Service, 28 | Animation, 29 | 30 | Require, 31 | View, 32 | Transclude 33 | }; -------------------------------------------------------------------------------- /dist/decorators/providers/controller.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | 7 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 8 | 9 | function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; return arr2; } else { return Array.from(arr); } } 10 | 11 | var _module2 = require('../../module'); 12 | 13 | var _module3 = _interopRequireDefault(_module2); 14 | 15 | var _utilDecoratorFactory = require('../../util/decorator-factory'); 16 | 17 | var _utilDecoratorFactory2 = _interopRequireDefault(_utilDecoratorFactory); 18 | 19 | var TYPE = 'controller'; 20 | 21 | var Controller = (0, _utilDecoratorFactory2['default'])(TYPE); 22 | 23 | exports.Controller = Controller; 24 | _module3['default'].addProvider(TYPE, function (provider, name, injects, ngModule) { 25 | ngModule.controller(name, [].concat(_toConsumableArray(injects), [provider])); 26 | }); -------------------------------------------------------------------------------- /src/util/parse-properties.spec.js: -------------------------------------------------------------------------------- 1 | import chai from '../tests/frameworks'; 2 | import parseProperties from './parse-properties'; 3 | 4 | describe('Property Parser', function(){ 5 | it('should parse an array of colon-delimited properties', function(){ 6 | parseProperties([ 7 | 'a: @a1', 8 | 'b: =b2', 9 | 'c: =?c2', 10 | 'd: =*d2', 11 | 'e: =*?e2' 12 | ]) 13 | 14 | .should.eql({ 15 | a : '@a1', 16 | b : '=b2', 17 | c : '=?c2', 18 | d : '=*d2', 19 | e : '=*?e2' 20 | }); 21 | }); 22 | 23 | it('should parse an array of simple properties', function(){ 24 | parseProperties([ 25 | '@a', 26 | '=b', 27 | '=?c', 28 | '=*?d' 29 | ]) 30 | 31 | .should.eql({ 32 | a: '@', 33 | b: '=', 34 | c: '=?', 35 | d: '=*?' 36 | }); 37 | }); 38 | 39 | it('should throw an error if the properties are malformed', function(){ 40 | let parse = prop => () => parseProperties([ prop ]); 41 | 42 | parse('myProp @anotherProp').should.throw(Error); 43 | parse('secondProp: thirdProp').should.throw(Error); 44 | parse('aProp').should.throw(Error); 45 | }); 46 | }); -------------------------------------------------------------------------------- /dist/util/decorate.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _testsFrameworks = require('../tests/frameworks'); 4 | 5 | var _decorate = require('./decorate'); 6 | 7 | describe('Decorator helpers for ES5/ES6', function () { 8 | it('should export the d helper object and two registeration functions', function () { 9 | _decorate.d.should.be.defined; 10 | _decorate.register.should.be.defined; 11 | _decorate.registerFactory.should.be.defined; 12 | }); 13 | 14 | it('should let you register new simple decorators', function () { 15 | var spy = _testsFrameworks.sinon.spy(); 16 | (0, _decorate.register)('Test', spy); 17 | _decorate.d.Test['for'](function () {}); 18 | 19 | _decorate.d.Test.should.be.defined; 20 | spy.should.have.been.called; 21 | }); 22 | 23 | it('should let you register new decorator factories', function () { 24 | var spy = _testsFrameworks.sinon.spy(); 25 | (0, _decorate.registerFactory)('NewTest', function () { 26 | return spy; 27 | }); 28 | _decorate.d.NewTest()['for'](function () {}); 29 | 30 | _decorate.d.NewTest.should.be.defined; 31 | spy.should.have.been.called; 32 | }); 33 | }); -------------------------------------------------------------------------------- /src/util/decorate.js: -------------------------------------------------------------------------------- 1 | export let d = {}; 2 | 3 | class D{ 4 | constructor(){ 5 | this.decorators = []; 6 | } 7 | 8 | for(target){ 9 | for(let i = 0; i < this.decorators.length; i++) 10 | { 11 | if(typeof this.decorators[i] !== 'function') 12 | { 13 | throw new TypeError(`Decorator ${i + 1} did not produce a function`); 14 | } 15 | 16 | this.decorators[i](target); 17 | } 18 | 19 | this.decorators = []; 20 | } 21 | } 22 | 23 | export const register = (name, decorator) => { 24 | Object.defineProperty(D.prototype, name, { 25 | get: function(){ 26 | this.decorators.push(decorator); 27 | return this; 28 | }, 29 | enumerable: true, 30 | configurable: true 31 | }); 32 | 33 | Object.defineProperty(d, name, { 34 | get: function(){ 35 | return (new D())[name]; 36 | }, 37 | enumerable: true, 38 | configurable: true 39 | }); 40 | }; 41 | 42 | export const registerFactory = (name, decoratorFactory) => { 43 | D.prototype[name] = function(...params){ 44 | this.decorators.push(decoratorFactory(...params)); 45 | return this; 46 | }; 47 | 48 | d[name] = function(...params){ 49 | return (new D())[name](...params); 50 | }; 51 | }; 52 | -------------------------------------------------------------------------------- /src/decorators/providers/component.js: -------------------------------------------------------------------------------- 1 | import parseSelector from '../../util/parse-selector'; 2 | import decorateDirective from '../../util/decorate-directive'; 3 | import {providerWriter, componentWriter} from '../../writers'; 4 | 5 | const TYPE = 'directive'; 6 | 7 | export const Component = config => t => { 8 | if( !config.selector ) 9 | { 10 | throw new Error('Component selector must be provided'); 11 | } 12 | 13 | let {name, type: restrict} = parseSelector(config.selector); 14 | 15 | if(restrict !== 'E') 16 | { 17 | throw new Error('@Component selectors can only be elements. Perhaps you meant to use @Directive?'); 18 | } 19 | 20 | providerWriter.set('name', name, t); 21 | providerWriter.set('type', TYPE, t); 22 | 23 | // Sensible defaults for components 24 | if( !componentWriter.has('restrict', t) ) 25 | { 26 | componentWriter.set('restrict', restrict, t); 27 | } 28 | if( !componentWriter.has('scope', t) ) 29 | { 30 | componentWriter.set('scope', {}, t); 31 | } 32 | if( !componentWriter.has('bindToController', t) ) 33 | { 34 | componentWriter.set('bindToController', true, t); 35 | } 36 | 37 | componentWriter.set('controllerAs', name, t); 38 | 39 | decorateDirective(config, t); 40 | }; 41 | -------------------------------------------------------------------------------- /src/util/parse-properties.js: -------------------------------------------------------------------------------- 1 | const ALLOWED_SYMBOLS = ['&', '=', '@', '=', '*', '?']; 2 | 3 | function checkBindingType(str){ 4 | return (ALLOWED_SYMBOLS.indexOf(str.charAt(0)) !== -1); 5 | } 6 | 7 | function parseProperty(str){ 8 | let symbols = []; 9 | 10 | function getName(input){ 11 | if(checkBindingType(input.join(''))) 12 | { 13 | symbols.push(input.shift()); 14 | return getName(input); 15 | } 16 | 17 | return input; 18 | } 19 | 20 | let name = getName(str.split('')); 21 | 22 | return { name: name.join(''), symbols: symbols.join('') }; 23 | } 24 | 25 | export default function(props){ 26 | let map = {}; 27 | 28 | for(let i = 0; i < props.length; i++){ 29 | let split = props[i].split(':'); 30 | 31 | for(let y = 0; y < split.length; y++){ 32 | split[y] = split[y].trim(); 33 | } 34 | 35 | if(split.length === 1 && checkBindingType(split[0])){ 36 | let {name, symbols} = parseProperty(split[0]); 37 | map[name] = symbols; 38 | } 39 | else if(split.length === 2 && checkBindingType(split[1])){ 40 | map[split[0]] = split[1]; 41 | } 42 | else{ 43 | throw new Error('Properties must be in the form of "propName: [&, @, =, =*, =?, =*?]attrName" or in the form of "[&, @, =, =*, =?, =*?]attrName"'); 44 | } 45 | } 46 | 47 | return map; 48 | } -------------------------------------------------------------------------------- /dist/util/parse-selector.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | 7 | function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; return arr2; } else { return Array.from(arr); } } 8 | 9 | exports['default'] = function (selector) { 10 | var selectorArray = undefined; 11 | var type = undefined; 12 | 13 | if (selector.match(/\[(.*?)\]/) !== null) { 14 | selectorArray = selector.slice(1, selector.length - 1).split('-'); 15 | type = 'A'; 16 | } else if (selector[0] === '.') { 17 | selectorArray = selector.slice(1, selector.length).split('-'); 18 | type = 'C'; 19 | } else { 20 | selectorArray = selector.split('-'); 21 | type = 'E'; 22 | } 23 | 24 | var first = selectorArray.shift(); 25 | var name = undefined; 26 | 27 | if (selectorArray.length > 0) { 28 | for (var i = 0; i < selectorArray.length; i++) { 29 | var s = selectorArray[i]; 30 | s = s.slice(0, 1).toUpperCase() + s.slice(1, s.length); 31 | selectorArray[i] = s; 32 | } 33 | 34 | name = [first].concat(_toConsumableArray(selectorArray)).join(''); 35 | } else { 36 | name = first; 37 | } 38 | 39 | return { name: name, type: type }; 40 | }; 41 | 42 | module.exports = exports['default']; -------------------------------------------------------------------------------- /dist/util/parse-selector.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 4 | 5 | var _parseSelector = require('./parse-selector'); 6 | 7 | var _parseSelector2 = _interopRequireDefault(_parseSelector); 8 | 9 | var _testsFrameworks = require('../tests/frameworks'); 10 | 11 | var _testsFrameworks2 = _interopRequireDefault(_testsFrameworks); 12 | 13 | describe('Component selector parser', function () { 14 | it('should correctly parse element selectors', function () { 15 | var info = (0, _parseSelector2['default'])('my-component-selector'); 16 | 17 | info.should.have.property('name', 'myComponentSelector'); 18 | info.should.have.property('type', 'E'); 19 | 20 | info = (0, _parseSelector2['default'])('component'); 21 | 22 | info.name.should.equal('component'); 23 | }); 24 | 25 | it('should correctly parse attribute selectors', function () { 26 | var info = (0, _parseSelector2['default'])('[my-attr]'); 27 | 28 | info.name.should.equal('myAttr'); 29 | info.type.should.equal('A'); 30 | }); 31 | 32 | it('should correctly parse class selectors', function () { 33 | var info = (0, _parseSelector2['default'])('.my-class'); 34 | 35 | info.name.should.equal('myClass'); 36 | info.type.should.equal('C'); 37 | }); 38 | }); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-decorators", 3 | "version": "1.2.0", 4 | "description": "A collection of utilities and annotations that make it easier to write Angular 2 style code in AngularJS 1.x", 5 | "main": "./dist/index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/MikeRyan52/angular-decorators" 9 | }, 10 | "scripts": { 11 | "test": "gulp test", 12 | "build": "gulp build && browserify -t babelify ./src/index.js --standalone angular-decorators --ignore reflect-metadata | derequire > ./dist/angular-decorators.js" 13 | }, 14 | "keywords": [ 15 | "angular", 16 | "angular2", 17 | "angularjs", 18 | "annotations", 19 | "decorators", 20 | "ecmascript6" 21 | ], 22 | "author": "Mike Ryan", 23 | "license": "ISC", 24 | "devDependencies": { 25 | "angular": "^1.4.0", 26 | "babel": "^5.0.8", 27 | "babelify": "^6.3.0", 28 | "babel-eslint": "^3.1.23", 29 | "browserify": "^11.2.0", 30 | "chai": "^2.2.0", 31 | "derequire": "^2.0.2", 32 | "eslint": "^0.24.0", 33 | "gulp": "^3.8.11", 34 | "gulp-babel": "^5.0.0", 35 | "gulp-mocha": "^2.0.1", 36 | "mocha": "^2.2.1", 37 | "sinon": "^1.14.1", 38 | "sinon-chai": "^2.7.0" 39 | }, 40 | "dependencies": { 41 | "metawriter": "^1.0.0" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/decorators/component/view.spec.js: -------------------------------------------------------------------------------- 1 | import {View} from './view'; 2 | import '../../tests/frameworks'; 3 | import {componentWriter} from '../../writers'; 4 | 5 | describe('@View Decorator', function(){ 6 | it('should add a template option to a component', function(){ 7 | @View({ template: 'test' }) 8 | class MyClass{ } 9 | 10 | componentWriter.get('template', MyClass).should.eql('test'); 11 | }); 12 | 13 | it('should support template URLs', function(){ 14 | @View({ templateUrl : '/path/to/it' }) 15 | class MyClass{ } 16 | 17 | componentWriter.get('templateUrl', MyClass).should.eql('/path/to/it'); 18 | }); 19 | 20 | it('should overwrite previously set template options via inheritance', function(){ 21 | @View({ template: 'test' }) 22 | class Parent{ } 23 | 24 | @View({ templateUrl: '/path/to/it' }) 25 | class Child extends Parent{ } 26 | 27 | @View({ template: 'new test' }) 28 | class GrandChild extends Child{ } 29 | 30 | componentWriter.get('template', Parent).should.eql('test'); 31 | componentWriter.get('templateUrl', Child).should.eql('/path/to/it'); 32 | (componentWriter.get('template', Child) === undefined).should.be.true; 33 | componentWriter.get('template', GrandChild).should.eql('new test'); 34 | (componentWriter.get('templateUrl', GrandChild) === undefined).should.be.true; 35 | }); 36 | }); -------------------------------------------------------------------------------- /dist/util/parse-properties.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 4 | 5 | var _testsFrameworks = require('../tests/frameworks'); 6 | 7 | var _testsFrameworks2 = _interopRequireDefault(_testsFrameworks); 8 | 9 | var _parseProperties = require('./parse-properties'); 10 | 11 | var _parseProperties2 = _interopRequireDefault(_parseProperties); 12 | 13 | describe('Property Parser', function () { 14 | it('should parse an array of colon-delimited properties', function () { 15 | (0, _parseProperties2['default'])(['a: @a1', 'b: =b2', 'c: =?c2', 'd: =*d2', 'e: =*?e2']).should.eql({ 16 | a: '@a1', 17 | b: '=b2', 18 | c: '=?c2', 19 | d: '=*d2', 20 | e: '=*?e2' 21 | }); 22 | }); 23 | 24 | it('should parse an array of simple properties', function () { 25 | (0, _parseProperties2['default'])(['@a', '=b', '=?c', '=*?d']).should.eql({ 26 | a: '@', 27 | b: '=', 28 | c: '=?', 29 | d: '=*?' 30 | }); 31 | }); 32 | 33 | it('should throw an error if the properties are malformed', function () { 34 | var parse = function parse(prop) { 35 | return function () { 36 | return (0, _parseProperties2['default'])([prop]); 37 | }; 38 | }; 39 | 40 | parse('myProp @anotherProp').should['throw'](Error); 41 | parse('secondProp: thirdProp').should['throw'](Error); 42 | parse('aProp').should['throw'](Error); 43 | }); 44 | }); -------------------------------------------------------------------------------- /src/decorators/providers/directive.spec.js: -------------------------------------------------------------------------------- 1 | import {providerWriter, componentWriter} from '../../writers'; 2 | import '../../tests/frameworks'; 3 | import {Directive} from './directive'; 4 | 5 | describe('@Directive Decorator', function(){ 6 | it('should set the correct provider metadata', function(){ 7 | @Directive({ selector: '[my-directive]' }) 8 | class MyDirectiveCtrl{ } 9 | 10 | providerWriter.get('type', MyDirectiveCtrl).should.eql('directive'); 11 | providerWriter.get('name', MyDirectiveCtrl).should.eql('myDirective'); 12 | }); 13 | 14 | it('should restrict the directive type', function(){ 15 | @Directive({ selector: '[attr]' }) 16 | class AttrCtrl{ } 17 | 18 | @Directive({ selector: '.class' }) 19 | class ClassCtrl{ } 20 | 21 | componentWriter.get('restrict', AttrCtrl).should.eql('A'); 22 | componentWriter.get('restrict', ClassCtrl).should.eql('C'); 23 | }); 24 | 25 | it('should set sensible defaults for attribute and class directives', function(){ 26 | @Directive({ selector: '[my-directive]' }) 27 | class DirCtrl{ } 28 | 29 | componentWriter.get('scope', DirCtrl).should.eql(false); 30 | }); 31 | 32 | it('should throw an error if used with an element selector', function(){ 33 | let decorate = () => { 34 | @Directive({ selector: 'my-component' }) 35 | class MyComponentCtrl{ } 36 | }; 37 | 38 | decorate.should.throw(Error); 39 | }); 40 | }); 41 | -------------------------------------------------------------------------------- /dist/decorators/providers/directive.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | 7 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 8 | 9 | var _utilDecorateDirective = require('../../util/decorate-directive'); 10 | 11 | var _utilDecorateDirective2 = _interopRequireDefault(_utilDecorateDirective); 12 | 13 | var _utilParseSelector = require('../../util/parse-selector'); 14 | 15 | var _utilParseSelector2 = _interopRequireDefault(_utilParseSelector); 16 | 17 | var _writers = require('../../writers'); 18 | 19 | var TYPE = 'directive'; 20 | 21 | var Directive = function Directive(config) { 22 | return function (t) { 23 | if (!config.selector) { 24 | throw new Error('Directive selector must be provided'); 25 | } 26 | 27 | var _parseSelector = (0, _utilParseSelector2['default'])(config.selector); 28 | 29 | var name = _parseSelector.name; 30 | var type = _parseSelector.type; 31 | 32 | if (type === 'E') { 33 | throw new Error('Directives cannot be elements. Perhaps you meant to use @Component?'); 34 | } 35 | 36 | _writers.providerWriter.set('name', name, t); 37 | _writers.providerWriter.set('type', TYPE, t); 38 | 39 | // Sensible defaults for attribute directives 40 | _writers.componentWriter.set('scope', false, t); 41 | _writers.componentWriter.set('restrict', type, t); 42 | 43 | (0, _utilDecorateDirective2['default'])(config, t); 44 | }; 45 | }; 46 | exports.Directive = Directive; -------------------------------------------------------------------------------- /src/decorators/providers/service.spec.js: -------------------------------------------------------------------------------- 1 | import Module from '../../module'; 2 | import {Service} from './service'; 3 | import {sinon} from '../../tests/frameworks'; 4 | import {providerWriter} from '../../writers'; 5 | 6 | describe('@Service Decorator', function(){ 7 | it('should decorate a class with a provider name and type', function(){ 8 | @Service 9 | class MyService{ } 10 | 11 | providerWriter.get('type', MyService).should.eql('service'); 12 | providerWriter.get('name', MyService).should.eql('MyService'); 13 | }); 14 | 15 | it('should adhere to inheritance', function(){ 16 | @Service 17 | class BaseClass{ } 18 | 19 | @Service 20 | class MyClass extends BaseClass{ } 21 | 22 | providerWriter.get('name', BaseClass).should.eql('BaseClass'); 23 | providerWriter.get('name', MyClass).should.eql('MyClass'); 24 | }); 25 | 26 | it('should let you specify a name for the service', function(){ 27 | @Service('Renamed') 28 | class BaseClass{ } 29 | 30 | providerWriter.get('name', BaseClass).should.eql('Renamed'); 31 | }); 32 | 33 | describe('Parser', function(){ 34 | let parser, module; 35 | 36 | beforeEach(function(){ 37 | parser = Module.getParser('service'); 38 | module = { 39 | service : sinon.spy() 40 | }; 41 | }); 42 | 43 | it('should register itself with Module', function(){ 44 | parser.should.be.defined; 45 | }); 46 | 47 | it('should parse an annotated class into an ng service', function(){ 48 | @Service 49 | class MyService{ } 50 | 51 | parser(MyService, 'MyService', [], module); 52 | 53 | module.service.should.have.been.calledWith('MyService', [MyService]); 54 | }); 55 | }); 56 | }); -------------------------------------------------------------------------------- /dist/decorators/component/transclude.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 4 | 5 | var _transclude = require('./transclude'); 6 | 7 | var _writers = require('../../writers'); 8 | 9 | var _testsFrameworks = require('../../tests/frameworks'); 10 | 11 | describe('@Transclude Component decorator', function () { 12 | it('should add the transclude key on the DDO', function () { 13 | var MyClass = (function () { 14 | function MyClass() { 15 | _classCallCheck(this, _MyClass); 16 | } 17 | 18 | var _MyClass = MyClass; 19 | MyClass = (0, _transclude.Transclude)(MyClass) || MyClass; 20 | return MyClass; 21 | })(); 22 | 23 | _writers.componentWriter.has('transclude', MyClass).should.be.ok; 24 | _writers.componentWriter.get('transclude', MyClass).should.be.ok; 25 | }); 26 | 27 | it('should let you pass a string or boolean value to the decorator', function () { 28 | var First = (function () { 29 | function First() { 30 | _classCallCheck(this, _First); 31 | } 32 | 33 | var _First = First; 34 | First = (0, _transclude.Transclude)(true)(First) || First; 35 | return First; 36 | })(); 37 | 38 | var Second = (function () { 39 | function Second() { 40 | _classCallCheck(this, _Second); 41 | } 42 | 43 | var _Second = Second; 44 | Second = (0, _transclude.Transclude)('element')(Second) || Second; 45 | return Second; 46 | })(); 47 | 48 | _writers.componentWriter.get('transclude', First).should.be.ok; 49 | _writers.componentWriter.get('transclude', Second).should.eql('element'); 50 | }); 51 | }); -------------------------------------------------------------------------------- /dist/util/parse-properties.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | var ALLOWED_SYMBOLS = ['&', '=', '@', '=', '*', '?']; 7 | 8 | function checkBindingType(str) { 9 | return ALLOWED_SYMBOLS.indexOf(str.charAt(0)) !== -1; 10 | } 11 | 12 | function parseProperty(str) { 13 | var symbols = []; 14 | 15 | function getName(_x) { 16 | var _again = true; 17 | 18 | _function: while (_again) { 19 | var input = _x; 20 | _again = false; 21 | 22 | if (checkBindingType(input.join(''))) { 23 | symbols.push(input.shift()); 24 | _x = input; 25 | _again = true; 26 | continue _function; 27 | } 28 | 29 | return input; 30 | } 31 | } 32 | 33 | var name = getName(str.split('')); 34 | 35 | return { name: name.join(''), symbols: symbols.join('') }; 36 | } 37 | 38 | exports['default'] = function (props) { 39 | var map = {}; 40 | 41 | for (var i = 0; i < props.length; i++) { 42 | var split = props[i].split(':'); 43 | 44 | for (var y = 0; y < split.length; y++) { 45 | split[y] = split[y].trim(); 46 | } 47 | 48 | if (split.length === 1 && checkBindingType(split[0])) { 49 | var _parseProperty = parseProperty(split[0]); 50 | 51 | var _name = _parseProperty.name; 52 | var symbols = _parseProperty.symbols; 53 | 54 | map[_name] = symbols; 55 | } else if (split.length === 2 && checkBindingType(split[1])) { 56 | map[split[0]] = split[1]; 57 | } else { 58 | throw new Error('Properties must be in the form of "propName: [&, @, =, =*, =?, =*?]attrName" or in the form of "[&, @, =, =*, =?, =*?]attrName"'); 59 | } 60 | } 61 | 62 | return map; 63 | }; 64 | 65 | module.exports = exports['default']; -------------------------------------------------------------------------------- /src/decorators/providers/animation.spec.js: -------------------------------------------------------------------------------- 1 | import {Animation} from './animation'; 2 | import Module from '../../module'; 3 | import {providerWriter} from '../../writers'; 4 | import {sinon} from '../../tests/frameworks'; 5 | 6 | describe('@Animation Decorator', function(){ 7 | it('should set the correct provider name and type', function(){ 8 | @Animation('.my-class') 9 | class MyClassAnimation{ } 10 | 11 | providerWriter.get('type', MyClassAnimation).should.eql('animation'); 12 | providerWriter.get('name', MyClassAnimation).should.eql('.my-class'); 13 | }); 14 | 15 | it('should throw an error if you do not provide a class name', function(){ 16 | let test = () => { 17 | @Animation 18 | class MyAnimation{ } 19 | }; 20 | 21 | test.should.throw(Error, /must be supplied with the name of a class/); 22 | }); 23 | 24 | it('should throw an error if the class selector is invalid', function(){ 25 | let element = () => { 26 | @Animation('my-class') 27 | class Element{ } 28 | }; 29 | 30 | let attr = () => { 31 | @Animation('[my-class]') 32 | class Attr{ } 33 | }; 34 | 35 | element.should.throw(Error, /Invalid selector passed/); 36 | attr.should.throw(Error, /Invalid selector passed/); 37 | }); 38 | 39 | describe('Parser', function(){ 40 | let parser, module; 41 | 42 | beforeEach(function(){ 43 | parser = Module.getParser('animation'); 44 | module = { animation: sinon.spy() }; 45 | }); 46 | 47 | it('should add a parser to Module', function(){ 48 | parser.should.be.defined; 49 | }); 50 | 51 | it('should correctly register a new animation', function(){ 52 | parser(function(){}, 'Test', [], module); 53 | 54 | module.animation.should.have.been.called; 55 | }); 56 | }); 57 | }); -------------------------------------------------------------------------------- /src/decorators/providers/filter.spec.js: -------------------------------------------------------------------------------- 1 | import '../../tests/frameworks'; 2 | import {ngMocks} from '../../tests/angular'; 3 | import {providerWriter} from '../../writers'; 4 | import Module from '../../module'; 5 | import {Filter} from './filter'; 6 | 7 | describe('@Filter Decorator', function(){ 8 | it('should set the correct name and provider type', function(){ 9 | @Filter('splice') 10 | class SpliceFilter{ } 11 | 12 | providerWriter.get('type', SpliceFilter).should.eql('filter'); 13 | providerWriter.get('name', SpliceFilter).should.eql('splice'); 14 | }); 15 | 16 | it('should be parsed into a filter', function(){ 17 | @Filter('splice') 18 | class SpliceFilter{ } 19 | 20 | Module('test', []).add(SpliceFilter); 21 | 22 | ngMocks.filter.should.have.been.calledWith('splice'); 23 | }); 24 | 25 | describe('Filter Parser Implementation', function(){ 26 | let filter; 27 | 28 | beforeEach(function(){ 29 | let parser = Module.getParser('filter'); 30 | 31 | class Test{ 32 | supports(input){ 33 | return (typeof input === 'string'); 34 | } 35 | 36 | transform(input, param){ 37 | return `${input}-${param}`; 38 | } 39 | } 40 | 41 | parser(Test, 'test', [], { 42 | filter: (name, filterBlock) => { 43 | filter = filterBlock[0](); 44 | } 45 | }); 46 | }); 47 | 48 | it('should have created a filter', function(){ 49 | filter.should.be.defined; 50 | }); 51 | 52 | it('should check for support before applying the transform', function(){ 53 | let test = obj => filter(obj); 54 | 55 | test.should.throw(Error, /does not support/); 56 | }); 57 | 58 | it('should apply the transform if the test passes', function(){ 59 | filter('hello', 'world').should.eql('hello-world'); 60 | }); 61 | }); 62 | }); -------------------------------------------------------------------------------- /src/decorators/providers/controller.spec.js: -------------------------------------------------------------------------------- 1 | import {sinon} from '../../tests/frameworks'; 2 | import Module from '../../module'; 3 | import {providerWriter, componentWriter} from '../../writers'; 4 | import {Controller} from './controller'; 5 | 6 | describe('@Controller annotation', function(){ 7 | it('should decorate a class with $provider meta data', function(){ 8 | @Controller 9 | class MyController{ } 10 | 11 | providerWriter.get('type', MyController).should.eql('controller'); 12 | providerWriter.get('name', MyController).should.eql('MyController'); 13 | }); 14 | 15 | it('should register a controller parser with the Module class', function(){ 16 | let parser = Module.getParser('controller'); 17 | 18 | parser.should.exist; 19 | }); 20 | 21 | it('should correctly parse a controller', function(){ 22 | @Controller 23 | class MyController{ } 24 | 25 | let module = { 26 | controller : sinon.spy() 27 | }; 28 | 29 | let parser = Module.getParser('controller'); 30 | 31 | parser(MyController, 'MyController', [], module); 32 | 33 | let name = module.controller.args[0][0]; 34 | let controller = module.controller.args[0][1]; 35 | 36 | module.controller.called.should.be.true; 37 | name.should.equal('MyController'); 38 | controller.should.eql([MyController]); 39 | }); 40 | 41 | it('should define the $provider property on the prototype of the target', function(){ 42 | @Controller 43 | class MyController{ } 44 | 45 | @Controller 46 | class NewController extends MyController{ } 47 | 48 | providerWriter.get('name', MyController).should.not.equal('NewController'); 49 | providerWriter.get('name', MyController).should.equal('MyController'); 50 | providerWriter.get('name', NewController).should.equal('NewController'); 51 | }); 52 | }); 53 | -------------------------------------------------------------------------------- /dist/index.d.ts: -------------------------------------------------------------------------------- 1 | 2 | export function Factory(name: string): (any) => void; 3 | export function Inject(...dependencies: string[]): (any) => void; 4 | export function Service(name: string): (any) => void; 5 | 6 | export function Component( 7 | componentConfig: { 8 | selector: string, 9 | properties?: string[], 10 | controllerAs?: string, 11 | bindings?: any, 12 | restrict?: string, 13 | scope?: any, 14 | bindToController?: boolean 15 | } 16 | ): (any) => void; 17 | 18 | export function Directive( 19 | directiveConfig: { 20 | selector: string, 21 | properties?: string[], 22 | controllerAs?: string, 23 | bindings?: any, 24 | restrict?: string, 25 | scope?: any, 26 | bindToController?: boolean 27 | } 28 | ): (any) => void; 29 | 30 | export function Controller(name: string): (any) => void; 31 | 32 | export interface IFilter{ 33 | supports(input: any): boolean; 34 | transform(input: any, ...params: any[]): any; 35 | } 36 | 37 | export function Filter(name: string): (IFilter) => void; 38 | 39 | export interface IProvider{ 40 | $get: any; 41 | } 42 | 43 | export function Provider(name: string): (IProvider) => void; 44 | 45 | export function Animation(classSelector: string): (any) => void; 46 | 47 | export function Require(...directiveNames: string[]): (any) => void; 48 | 49 | export function View( 50 | viewConfig: { 51 | template?: string, 52 | templateUrl?: string 53 | } 54 | ): (any) => void; 55 | 56 | export function Transclude(any): (any) => any; 57 | 58 | export interface IModule{ 59 | add(...providers: any[]): IModule; 60 | config(...providers: any[]): IModule; 61 | run(...providers: any[]): IModule; 62 | value(name: string, value: any); 63 | constant(name: string, value: any); 64 | } 65 | 66 | export function Module(name: string, dependencies: any[]): IModule; 67 | -------------------------------------------------------------------------------- /src/index.d.ts: -------------------------------------------------------------------------------- 1 | 2 | export function Factory(name: string): (any) => void; 3 | export function Inject(...dependencies: string[]): (any) => void; 4 | export function Service(name: string): (any) => void; 5 | 6 | export function Component( 7 | componentConfig: { 8 | selector: string, 9 | properties?: string[], 10 | controllerAs?: string, 11 | bindings?: any, 12 | restrict?: string, 13 | scope?: any, 14 | bindToController?: boolean 15 | } 16 | ): (any) => void; 17 | 18 | export function Directive( 19 | directiveConfig: { 20 | selector: string, 21 | properties?: string[], 22 | controllerAs?: string, 23 | bindings?: any, 24 | restrict?: string, 25 | scope?: any, 26 | bindToController?: boolean 27 | } 28 | ): (any) => void; 29 | 30 | export function Controller(name: string): (any) => void; 31 | 32 | export interface IFilter{ 33 | supports(input: any): boolean; 34 | transform(input: any, ...params: any[]): any; 35 | } 36 | 37 | export function Filter(name: string): (IFilter) => void; 38 | 39 | export interface IProvider{ 40 | $get: any; 41 | } 42 | 43 | export function Provider(name: string): (IProvider) => void; 44 | 45 | export function Animation(classSelector: string): (any) => void; 46 | 47 | export function Require(...directiveNames: string[]): (any) => void; 48 | 49 | export function View( 50 | viewConfig: { 51 | template?: string, 52 | templateUrl?: string 53 | } 54 | ): (any) => void; 55 | 56 | export function Transclude(any): (any) => any; 57 | 58 | export interface IModule{ 59 | add(...providers: any[]): IModule; 60 | config(...providers: any[]): IModule; 61 | run(...providers: any[]): IModule; 62 | value(name: string, value: any); 63 | constant(name: string, value: any); 64 | } 65 | 66 | export function Module(name: string, dependencies: any[]): IModule; 67 | -------------------------------------------------------------------------------- /dist/decorators/providers/filter.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | var _bind = Function.prototype.bind; 7 | 8 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 9 | 10 | function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; return arr2; } else { return Array.from(arr); } } 11 | 12 | var _module2 = require('../../module'); 13 | 14 | var _module3 = _interopRequireDefault(_module2); 15 | 16 | var _utilDecoratorFactory = require('../../util/decorator-factory'); 17 | 18 | var _utilDecoratorFactory2 = _interopRequireDefault(_utilDecoratorFactory); 19 | 20 | var TYPE = 'filter'; 21 | 22 | var Filter = (0, _utilDecoratorFactory2['default'])(TYPE); 23 | 24 | exports.Filter = Filter; 25 | _module3['default'].addProvider(TYPE, function (provider, name, injects, ngModule) { 26 | ngModule.filter(name, [].concat(_toConsumableArray(injects), [function () { 27 | for (var _len = arguments.length, dependencies = Array(_len), _key = 0; _key < _len; _key++) { 28 | dependencies[_key] = arguments[_key]; 29 | } 30 | 31 | var filter = new (_bind.apply(provider, [null].concat(dependencies)))(); 32 | 33 | if (!filter.transform) { 34 | throw new Error('Filters must implement a transform method'); 35 | } 36 | 37 | return function (input) { 38 | for (var _len2 = arguments.length, params = Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { 39 | params[_key2 - 1] = arguments[_key2]; 40 | } 41 | 42 | if (filter.supports && !filter.supports(input)) { 43 | throw new Error('Filter ' + name + ' does not support ' + input); 44 | } 45 | 46 | return filter.transform.apply(filter, [input].concat(params)); 47 | }; 48 | }])); 49 | }); -------------------------------------------------------------------------------- /dist/decorators/providers/component.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | 7 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 8 | 9 | var _utilParseSelector = require('../../util/parse-selector'); 10 | 11 | var _utilParseSelector2 = _interopRequireDefault(_utilParseSelector); 12 | 13 | var _utilDecorateDirective = require('../../util/decorate-directive'); 14 | 15 | var _utilDecorateDirective2 = _interopRequireDefault(_utilDecorateDirective); 16 | 17 | var _writers = require('../../writers'); 18 | 19 | var TYPE = 'directive'; 20 | 21 | var Component = function Component(config) { 22 | return function (t) { 23 | if (!config.selector) { 24 | throw new Error('Component selector must be provided'); 25 | } 26 | 27 | var _parseSelector = (0, _utilParseSelector2['default'])(config.selector); 28 | 29 | var name = _parseSelector.name; 30 | var restrict = _parseSelector.type; 31 | 32 | if (restrict !== 'E') { 33 | throw new Error('@Component selectors can only be elements. Perhaps you meant to use @Directive?'); 34 | } 35 | 36 | _writers.providerWriter.set('name', name, t); 37 | _writers.providerWriter.set('type', TYPE, t); 38 | 39 | // Sensible defaults for components 40 | if (!_writers.componentWriter.has('restrict', t)) { 41 | _writers.componentWriter.set('restrict', restrict, t); 42 | } 43 | if (!_writers.componentWriter.has('scope', t)) { 44 | _writers.componentWriter.set('scope', {}, t); 45 | } 46 | if (!_writers.componentWriter.has('bindToController', t)) { 47 | _writers.componentWriter.set('bindToController', true, t); 48 | } 49 | 50 | _writers.componentWriter.set('controllerAs', name, t); 51 | 52 | (0, _utilDecorateDirective2['default'])(config, t); 53 | }; 54 | }; 55 | exports.Component = Component; -------------------------------------------------------------------------------- /dist/decorators/providers/factory.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | var _bind = Function.prototype.bind; 7 | 8 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 9 | 10 | function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; return arr2; } else { return Array.from(arr); } } 11 | 12 | var _module2 = require('../../module'); 13 | 14 | var _module3 = _interopRequireDefault(_module2); 15 | 16 | var _utilDecoratorFactory = require('../../util/decorator-factory'); 17 | 18 | var _utilDecoratorFactory2 = _interopRequireDefault(_utilDecoratorFactory); 19 | 20 | var TYPE = 'factory'; 21 | 22 | var Factory = (0, _utilDecoratorFactory2['default'])(TYPE); 23 | 24 | exports.Factory = Factory; 25 | _module3['default'].addProvider(TYPE, function (provider, name, injects, ngModule) { 26 | var create = provider.create || function (dependencies) { 27 | for (var _len = arguments.length, params = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { 28 | params[_key - 1] = arguments[_key]; 29 | } 30 | 31 | return new (_bind.apply(provider, [null].concat(_toConsumableArray(dependencies), params)))(); 32 | }; 33 | 34 | function factory() { 35 | for (var _len2 = arguments.length, dependencies = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { 36 | dependencies[_key2] = arguments[_key2]; 37 | } 38 | 39 | return function () { 40 | for (var _len3 = arguments.length, params = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { 41 | params[_key3] = arguments[_key3]; 42 | } 43 | 44 | return create.apply(undefined, [dependencies].concat(params)); 45 | }; 46 | } 47 | 48 | ngModule.factory(name, [].concat(_toConsumableArray(injects), [factory])); 49 | }); -------------------------------------------------------------------------------- /dist/decorators/providers/animation.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | var _bind = Function.prototype.bind; 7 | 8 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 9 | 10 | function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; return arr2; } else { return Array.from(arr); } } 11 | 12 | var _module2 = require('../../module'); 13 | 14 | var _module3 = _interopRequireDefault(_module2); 15 | 16 | var _writers = require('../../writers'); 17 | 18 | var _utilParseSelector = require('../../util/parse-selector'); 19 | 20 | var _utilParseSelector2 = _interopRequireDefault(_utilParseSelector); 21 | 22 | var TYPE = 'animation'; 23 | 24 | var Animation = function Animation(className) { 25 | if (typeof className !== 'string') { 26 | throw new Error('@Animation must be supplied with the name of a class: @Animation(\'.my-animation\''); 27 | } 28 | 29 | var _parseSelector = (0, _utilParseSelector2['default'])(className); 30 | 31 | var type = _parseSelector.type; 32 | 33 | if (type !== 'C') { 34 | throw new Error('Invalid selector passed to @Animation: ' + className + ' is not a class selector'); 35 | } 36 | 37 | return function (target) { 38 | 39 | _writers.providerWriter.set('type', TYPE, target); 40 | _writers.providerWriter.set('name', className, target); 41 | }; 42 | }; 43 | 44 | exports.Animation = Animation; 45 | _module3['default'].addProvider(TYPE, function (provider, name, injects, ngModule) { 46 | ngModule.animation(name, [].concat(_toConsumableArray(injects), [function () { 47 | for (var _len = arguments.length, depends = Array(_len), _key = 0; _key < _len; _key++) { 48 | depends[_key] = arguments[_key]; 49 | } 50 | 51 | return new (_bind.apply(provider, [null].concat(depends)))(); 52 | }])); 53 | }); -------------------------------------------------------------------------------- /src/decorators/providers/component.spec.js: -------------------------------------------------------------------------------- 1 | import {Component} from './component'; 2 | import '../../tests/frameworks'; 3 | import {providerWriter, componentWriter} from '../../writers'; 4 | 5 | describe('@Component annotation', function(){ 6 | it('should decorate a class with correct $provider metadata', function(){ 7 | @Component({ selector : 'my-component' }) 8 | class MyComponentCtrl{ } 9 | 10 | providerWriter.has('type', MyComponentCtrl).should.be.ok; 11 | providerWriter.get('type', MyComponentCtrl).should.eql('directive'); 12 | providerWriter.has('name', MyComponentCtrl).should.be.ok; 13 | providerWriter.get('name', MyComponentCtrl).should.eql('myComponent'); 14 | }); 15 | 16 | it('should set sensible defaults using $component metadata', function(){ 17 | @Component({ selector: 'my-component' }) 18 | class MyComponentCtrl{ } 19 | 20 | componentWriter.get('restrict', MyComponentCtrl).should.eql('E'); 21 | componentWriter.get('scope', MyComponentCtrl).should.eql({}); 22 | componentWriter.get('bindToController', MyComponentCtrl).should.be.ok; 23 | }); 24 | 25 | it('should throw an error if the selector is not an element', function(){ 26 | let caughtAttr = false; 27 | let caughtClass = false; 28 | 29 | try{ 30 | @Component({ selector : '[my-attr]' }) 31 | class MyClass{ } 32 | } 33 | catch(e){ 34 | caughtAttr = true; 35 | } 36 | 37 | try{ 38 | @Component({ selector : '.my-class' }) 39 | class MyClass{ } 40 | } 41 | catch(e){ 42 | caughtClass = true; 43 | } 44 | 45 | caughtAttr.should.be.ok; 46 | caughtClass.should.be.ok; 47 | }); 48 | 49 | it('should respect inheritance', function(){ 50 | @Component({ 51 | selector: 'parent', 52 | properties: [ 53 | '@first', 54 | '=second' 55 | ] 56 | }) 57 | class ParentCtrl{ } 58 | 59 | @Component({ selector: 'child' }) 60 | class ChildCtrl extends ParentCtrl{ } 61 | 62 | componentWriter.get('bindToController', ChildCtrl).should.eql({ 63 | first: '@', 64 | second: '=' 65 | }); 66 | }); 67 | }); 68 | -------------------------------------------------------------------------------- /src/util/decorate-directive.js: -------------------------------------------------------------------------------- 1 | import Module from '../module'; 2 | import {componentWriter} from '../writers'; 3 | import parseProperties from './parse-properties'; 4 | 5 | export default function(config, t){ 6 | // Support for legacy angular-decorators bind config 7 | if(config.bind){ 8 | componentWriter.set('scope', config.bind, t); 9 | componentWriter.set('bindToController', true, t); 10 | } 11 | 12 | // Check for scope 13 | if(config.scope){ 14 | let scope = componentWriter.get('scope', t); 15 | 16 | if(scope && typeof scope === 'object') 17 | { 18 | componentWriter.set('scope', {...scope, ...config.scope}, t); 19 | } 20 | else 21 | { 22 | componentWriter.set('scope', config.scope, t); 23 | } 24 | } 25 | 26 | 27 | // Check for Angular 2 style properties 28 | if(config.properties && Array.isArray(config.properties)){ 29 | let binders = parseProperties(config.properties); 30 | let previous = componentWriter.get('bindToController', t); 31 | 32 | if(previous && typeof previous === 'object') 33 | { 34 | componentWriter.set('bindToController', {...previous, ...binders}, t); 35 | } 36 | else 37 | { 38 | componentWriter.set('bindToController', parseProperties(config.properties), t); 39 | } 40 | } 41 | else if(config.properties !== undefined){ 42 | throw new TypeError('Component properties must be an array'); 43 | } 44 | 45 | // Allow for renaming the controllerAs 46 | if(config.controllerAs){ 47 | componentWriter.set('controllerAs', config.controllerAs, t); 48 | } 49 | 50 | // Set a link function 51 | if(t.link){ 52 | componentWriter.set('link', t.link, t); 53 | } 54 | 55 | // Set a controller function 56 | if(t.compile){ 57 | componentWriter.set('compile', t.compile, t); 58 | } 59 | } 60 | 61 | Module.addProvider('directive', (target, name, injects, ngModule) => { 62 | let ddo = {}; 63 | 64 | componentWriter.forEach((val, key) => { 65 | ddo[key] = val; 66 | }, target); 67 | 68 | ddo.controller = [...injects, target]; 69 | 70 | ngModule.directive(name, () => ddo); 71 | }); 72 | -------------------------------------------------------------------------------- /dist/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | 7 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 8 | 9 | var _module2 = require('./module'); 10 | 11 | var _module3 = _interopRequireDefault(_module2); 12 | 13 | var _decoratorsInject = require('./decorators/inject'); 14 | 15 | var _decoratorsProvidersAnimation = require('./decorators/providers/animation'); 16 | 17 | var _decoratorsProvidersComponent = require('./decorators/providers/component'); 18 | 19 | var _decoratorsProvidersController = require('./decorators/providers/controller'); 20 | 21 | var _decoratorsProvidersDirective = require('./decorators/providers/directive'); 22 | 23 | var _decoratorsProvidersFactory = require('./decorators/providers/factory'); 24 | 25 | var _decoratorsProvidersFilter = require('./decorators/providers/filter'); 26 | 27 | var _decoratorsProvidersProvider = require('./decorators/providers/provider'); 28 | 29 | var _decoratorsProvidersService = require('./decorators/providers/service'); 30 | 31 | var _decoratorsComponentRequire = require('./decorators/component/require'); 32 | 33 | var _decoratorsComponentView = require('./decorators/component/view'); 34 | 35 | var _decoratorsComponentTransclude = require('./decorators/component/transclude'); 36 | 37 | exports.Module = _module3['default']; 38 | exports.Inject = _decoratorsInject.Inject; 39 | exports.Component = _decoratorsProvidersComponent.Component; 40 | exports.Controller = _decoratorsProvidersController.Controller; 41 | exports.Directive = _decoratorsProvidersDirective.Directive; 42 | exports.Filter = _decoratorsProvidersFilter.Filter; 43 | exports.Provider = _decoratorsProvidersProvider.Provider; 44 | exports.Factory = _decoratorsProvidersFactory.Factory; 45 | exports.Service = _decoratorsProvidersService.Service; 46 | exports.Animation = _decoratorsProvidersAnimation.Animation; 47 | exports.Require = _decoratorsComponentRequire.Require; 48 | exports.View = _decoratorsComponentView.View; 49 | exports.Transclude = _decoratorsComponentTransclude.Transclude; -------------------------------------------------------------------------------- /dist/util/decorate.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | 7 | var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); 8 | 9 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 10 | 11 | var d = {}; 12 | 13 | exports.d = d; 14 | 15 | var D = (function () { 16 | function D() { 17 | _classCallCheck(this, D); 18 | 19 | this.decorators = []; 20 | } 21 | 22 | _createClass(D, [{ 23 | key: 'for', 24 | value: function _for(target) { 25 | for (var i = 0; i < this.decorators.length; i++) { 26 | if (typeof this.decorators[i] !== 'function') { 27 | throw new TypeError('Decorator ' + (i + 1) + ' did not produce a function'); 28 | } 29 | 30 | this.decorators[i](target); 31 | } 32 | 33 | this.decorators = []; 34 | } 35 | }]); 36 | 37 | return D; 38 | })(); 39 | 40 | var register = function register(name, decorator) { 41 | Object.defineProperty(D.prototype, name, { 42 | get: function get() { 43 | this.decorators.push(decorator); 44 | return this; 45 | }, 46 | enumerable: true, 47 | configurable: true 48 | }); 49 | 50 | Object.defineProperty(d, name, { 51 | get: function get() { 52 | return new D()[name]; 53 | }, 54 | enumerable: true, 55 | configurable: true 56 | }); 57 | }; 58 | 59 | exports.register = register; 60 | var registerFactory = function registerFactory(name, decoratorFactory) { 61 | D.prototype[name] = function () { 62 | this.decorators.push(decoratorFactory.apply(undefined, arguments)); 63 | return this; 64 | }; 65 | 66 | d[name] = function () { 67 | var _ref; 68 | 69 | return (_ref = new D())[name].apply(_ref, arguments); 70 | }; 71 | }; 72 | exports.registerFactory = registerFactory; -------------------------------------------------------------------------------- /src/module.js: -------------------------------------------------------------------------------- 1 | import {baseWriter, providerWriter} from './writers'; 2 | 3 | let _parsers = {}; 4 | 5 | class DecoratedModule{ 6 | constructor(name, modules = false){ 7 | this.name = name; 8 | this.moduleList(modules); 9 | 10 | if(modules) 11 | { 12 | this._module = angular.module(name, this._dependencies); 13 | } 14 | else 15 | { 16 | this._module = angular.module(name); 17 | } 18 | } 19 | 20 | add(...providers){ 21 | for(let provider of providers) 22 | { 23 | if( !providerWriter.has('type', provider) ){ 24 | throw new Error(`Cannot read provider metadata. Are you adding a class that hasn't been decorated yet?`); 25 | } 26 | 27 | let type = providerWriter.get('type', provider); 28 | let name = providerWriter.get('name', provider); 29 | let inject = baseWriter.get('$inject', provider) || []; 30 | 31 | if(_parsers[type]){ 32 | _parsers[type](provider, name, inject, this._module); 33 | } 34 | else{ 35 | throw new Error(`No parser registered for type '${type}'`); 36 | } 37 | } 38 | 39 | return this; 40 | } 41 | 42 | publish(){ 43 | return this._module; 44 | } 45 | 46 | moduleList(modules){ 47 | this._dependencies = []; 48 | 49 | if(modules && modules.length !== 0){ 50 | for(let i = 0; i < modules.length; i++) 51 | { 52 | if(modules[i] && modules[i].name) 53 | { 54 | this._dependencies.push(modules[i].name); 55 | } 56 | else if(typeof modules[i] === 'string') 57 | { 58 | this._dependencies.push(modules[i]); 59 | } 60 | else 61 | { 62 | throw new Error(`Cannot read module: Unknown module in ${this.name}`); 63 | } 64 | } 65 | } 66 | } 67 | 68 | config(configFunc){ 69 | this._module.config(configFunc); 70 | 71 | return this; 72 | } 73 | 74 | run(runFunc){ 75 | this._module.run(runFunc); 76 | 77 | return this; 78 | } 79 | 80 | value(...args){ 81 | this._module.value(...args); 82 | 83 | return this; 84 | } 85 | 86 | constant(...args){ 87 | this._module.constant(...args); 88 | 89 | return this; 90 | } 91 | } 92 | 93 | function Module(...params){ 94 | return new DecoratedModule(...params); 95 | } 96 | 97 | Module.addProvider = function(providerType, parser){ 98 | _parsers[providerType] = parser; 99 | }; 100 | 101 | Module.getParser = function(providerType){ 102 | return _parsers[providerType]; 103 | }; 104 | 105 | export default Module; 106 | -------------------------------------------------------------------------------- /src/decorators/providers/factory.spec.js: -------------------------------------------------------------------------------- 1 | import {Factory} from './factory'; 2 | import Module from '../../module'; 3 | import {sinon} from '../../tests/frameworks'; 4 | import {providerWriter} from '../../writers'; 5 | 6 | describe('@Factory Annotation', function(){ 7 | it('should decorate a class with $provider meta information', function(){ 8 | @Factory('MyFactory') 9 | class ExampleClass{ } 10 | 11 | providerWriter.get('type', ExampleClass).should.eql('factory'); 12 | providerWriter.get('name', ExampleClass).should.eql('MyFactory'); 13 | }); 14 | 15 | describe('Parser', function(){ 16 | let parser, module; 17 | 18 | beforeEach(function(){ 19 | module = { factory : sinon.spy() }; 20 | parser = Module.getParser('factory'); 21 | }); 22 | 23 | it('should register itself with Module', function(){ 24 | parser.should.be.defined; 25 | }); 26 | 27 | it('should use the static create method on a class as the factory function', function(){ 28 | let called = false; 29 | 30 | @Factory('MyFactory') 31 | class ExampleClass{ 32 | static create(){ 33 | called = true; 34 | } 35 | } 36 | 37 | parser(ExampleClass, 'MyFactory', [], module); 38 | let factoryProvider = module.factory.args[0][1][0]; 39 | 40 | factoryProvider()(); 41 | 42 | called.should.be.true; 43 | }); 44 | 45 | it('should pass dependencies to the create method', function(){ 46 | let a, b; 47 | 48 | @Factory('MyFactory') 49 | class ExampleClass{ 50 | static create(dependencies){ 51 | [a, b] = dependencies; 52 | } 53 | } 54 | 55 | parser(ExampleClass, 'MyFactory', [], module); 56 | let factoryProvider = module.factory.args[0][1][0]; 57 | 58 | factoryProvider(1, 2)(); 59 | 60 | a.should.equal(1); 61 | b.should.equal(2); 62 | }); 63 | 64 | it('should generate a factory function for a class', function(){ 65 | @Factory('MyFactory') 66 | class ExampleClass{ 67 | constructor(depA, depB, depC, propA, propB, propC){ 68 | this.depA = depA; 69 | this.depB = depB; 70 | this.depC = depC; 71 | 72 | this.propA = propA; 73 | this.propB = propB; 74 | this.propC = propC; 75 | } 76 | } 77 | 78 | parser(ExampleClass, 'MyFactory', [], module); 79 | 80 | let factoryName = module.factory.args[0][0]; 81 | let factoryProvider = module.factory.args[0][1][0]; 82 | factoryName.should.equal('MyFactory'); 83 | factoryProvider.should.be.defined; 84 | 85 | let factory = factoryProvider('a', 'b', 'c'); 86 | factory.should.be.defined; 87 | 88 | let instance = factory('1', '2', '3'); 89 | instance.should.have.property('propA', '1'); 90 | instance.should.have.property('propB', '2'); 91 | instance.should.have.property('propC', '3'); 92 | }); 93 | }); 94 | }); -------------------------------------------------------------------------------- /dist/decorators/providers/directive.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 4 | 5 | var _writers = require('../../writers'); 6 | 7 | require('../../tests/frameworks'); 8 | 9 | var _directive = require('./directive'); 10 | 11 | describe('@Directive Decorator', function () { 12 | it('should set the correct provider metadata', function () { 13 | var MyDirectiveCtrl = (function () { 14 | function MyDirectiveCtrl() { 15 | _classCallCheck(this, _MyDirectiveCtrl); 16 | } 17 | 18 | var _MyDirectiveCtrl = MyDirectiveCtrl; 19 | MyDirectiveCtrl = (0, _directive.Directive)({ selector: '[my-directive]' })(MyDirectiveCtrl) || MyDirectiveCtrl; 20 | return MyDirectiveCtrl; 21 | })(); 22 | 23 | _writers.providerWriter.get('type', MyDirectiveCtrl).should.eql('directive'); 24 | _writers.providerWriter.get('name', MyDirectiveCtrl).should.eql('myDirective'); 25 | }); 26 | 27 | it('should restrict the directive type', function () { 28 | var AttrCtrl = (function () { 29 | function AttrCtrl() { 30 | _classCallCheck(this, _AttrCtrl); 31 | } 32 | 33 | var _AttrCtrl = AttrCtrl; 34 | AttrCtrl = (0, _directive.Directive)({ selector: '[attr]' })(AttrCtrl) || AttrCtrl; 35 | return AttrCtrl; 36 | })(); 37 | 38 | var ClassCtrl = (function () { 39 | function ClassCtrl() { 40 | _classCallCheck(this, _ClassCtrl); 41 | } 42 | 43 | var _ClassCtrl = ClassCtrl; 44 | ClassCtrl = (0, _directive.Directive)({ selector: '.class' })(ClassCtrl) || ClassCtrl; 45 | return ClassCtrl; 46 | })(); 47 | 48 | _writers.componentWriter.get('restrict', AttrCtrl).should.eql('A'); 49 | _writers.componentWriter.get('restrict', ClassCtrl).should.eql('C'); 50 | }); 51 | 52 | it('should set sensible defaults for attribute and class directives', function () { 53 | var DirCtrl = (function () { 54 | function DirCtrl() { 55 | _classCallCheck(this, _DirCtrl); 56 | } 57 | 58 | var _DirCtrl = DirCtrl; 59 | DirCtrl = (0, _directive.Directive)({ selector: '[my-directive]' })(DirCtrl) || DirCtrl; 60 | return DirCtrl; 61 | })(); 62 | 63 | _writers.componentWriter.get('scope', DirCtrl).should.eql(false); 64 | }); 65 | 66 | it('should throw an error if used with an element selector', function () { 67 | var decorate = function decorate() { 68 | var MyComponentCtrl = (function () { 69 | function MyComponentCtrl() { 70 | _classCallCheck(this, _MyComponentCtrl); 71 | } 72 | 73 | var _MyComponentCtrl = MyComponentCtrl; 74 | MyComponentCtrl = (0, _directive.Directive)({ selector: 'my-component' })(MyComponentCtrl) || MyComponentCtrl; 75 | return MyComponentCtrl; 76 | })(); 77 | }; 78 | 79 | decorate.should['throw'](Error); 80 | }); 81 | }); -------------------------------------------------------------------------------- /src/module.spec.js: -------------------------------------------------------------------------------- 1 | import {sinon} from './tests/frameworks'; 2 | import {angular, ngMocks} from './tests/angular'; 3 | import {providerWriter, baseWriter} from './writers'; 4 | import Module from './module'; 5 | 6 | const provider = (type, name) => t => { 7 | providerWriter.set('type', type, t); 8 | providerWriter.set('name', name, t); 9 | }; 10 | 11 | describe('Decorator Supported Module', function(){ 12 | it('should let you create an Angular module', function(){ 13 | let module = Module('test', []); 14 | 15 | module.should.be.defined; 16 | angular.module.should.have.been.called; 17 | }); 18 | 19 | it('should let you publish the module to gain access to the ng module', function(){ 20 | Module('test', []).publish().should.eql(ngMocks); 21 | }); 22 | 23 | it('should let you config the module', function(){ 24 | let config = ['$q', () => {}]; 25 | Module('test', []).config(config); 26 | 27 | ngMocks.config.should.have.been.calledWith(config); 28 | }); 29 | 30 | it('should let you create a run function', function(){ 31 | let run = ['$q', () => {}]; 32 | Module('test', []).run(run); 33 | 34 | ngMocks.run.should.have.been.calledWith(run); 35 | }); 36 | 37 | it('should let you add value to the module', function () { 38 | let value = 'testValue'; 39 | Module('test', []).value('test', value); 40 | 41 | ngMocks.value.should.have.been.calledWith('test', value); 42 | }); 43 | 44 | it('should let you add constant to the module', function () { 45 | let value = 'constantValue'; 46 | Module('test', []).constant('TEST', value); 47 | 48 | ngMocks.constant.should.have.been.calledWith('TEST', value); 49 | }); 50 | 51 | describe('Adding providers', function(){ 52 | let exampleRegister; 53 | 54 | beforeEach(function(){ 55 | exampleRegister = sinon.spy(); 56 | Module.addProvider('example', exampleRegister); 57 | }); 58 | 59 | it('should let you add providers', function(){ 60 | @provider('example', 'A') 61 | class A{ } 62 | 63 | let mod = Module('test', []).add(A); 64 | 65 | exampleRegister.should.have.been.calledWith(A, 'A', [], mod.publish()); 66 | }); 67 | 68 | it('should let you add multiple providers', function(){ 69 | @provider('example', 'A') 70 | class A{ } 71 | 72 | @provider('example', 'B') 73 | class B{ } 74 | 75 | @provider('example', 'C') 76 | class C{ } 77 | 78 | Module('test', []).add(A, B, C); 79 | 80 | exampleRegister.should.have.been.calledThrice; 81 | }); 82 | 83 | it('should throw an error if you add provider with no decorators', function(){ 84 | class A{ } 85 | 86 | let test = () => Module('test', []).add(A); 87 | 88 | test.should.throw(Error, /Cannot read provider/); 89 | }); 90 | 91 | it('should throw an error when adding a provider with an unrecognized type', function(){ 92 | @provider('dne', 'A') 93 | class A{ } 94 | 95 | let test = () => Module('test', []).add(A); 96 | 97 | test.should.throw(Error, /No parser registered/); 98 | }); 99 | }); 100 | }); -------------------------------------------------------------------------------- /dist/util/decorate-directive.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | 7 | var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; 8 | 9 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 10 | 11 | function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; return arr2; } else { return Array.from(arr); } } 12 | 13 | var _module2 = require('../module'); 14 | 15 | var _module3 = _interopRequireDefault(_module2); 16 | 17 | var _writers = require('../writers'); 18 | 19 | var _parseProperties = require('./parse-properties'); 20 | 21 | var _parseProperties2 = _interopRequireDefault(_parseProperties); 22 | 23 | exports['default'] = function (config, t) { 24 | // Support for legacy angular-decorators bind config 25 | if (config.bind) { 26 | _writers.componentWriter.set('scope', config.bind, t); 27 | _writers.componentWriter.set('bindToController', true, t); 28 | } 29 | 30 | // Check for scope 31 | if (config.scope) { 32 | var scope = _writers.componentWriter.get('scope', t); 33 | 34 | if (scope && typeof scope === 'object') { 35 | _writers.componentWriter.set('scope', _extends({}, scope, config.scope), t); 36 | } else { 37 | _writers.componentWriter.set('scope', config.scope, t); 38 | } 39 | } 40 | 41 | // Check for Angular 2 style properties 42 | if (config.properties && Array.isArray(config.properties)) { 43 | var binders = (0, _parseProperties2['default'])(config.properties); 44 | var previous = _writers.componentWriter.get('bindToController', t); 45 | 46 | if (previous && typeof previous === 'object') { 47 | _writers.componentWriter.set('bindToController', _extends({}, previous, binders), t); 48 | } else { 49 | _writers.componentWriter.set('bindToController', (0, _parseProperties2['default'])(config.properties), t); 50 | } 51 | } else if (config.properties !== undefined) { 52 | throw new TypeError('Component properties must be an array'); 53 | } 54 | 55 | // Allow for renaming the controllerAs 56 | if (config.controllerAs) { 57 | _writers.componentWriter.set('controllerAs', config.controllerAs, t); 58 | } 59 | 60 | // Set a link function 61 | if (t.link) { 62 | _writers.componentWriter.set('link', t.link, t); 63 | } 64 | 65 | // Set a controller function 66 | if (t.compile) { 67 | _writers.componentWriter.set('compile', t.compile, t); 68 | } 69 | }; 70 | 71 | _module3['default'].addProvider('directive', function (target, name, injects, ngModule) { 72 | var ddo = {}; 73 | 74 | _writers.componentWriter.forEach(function (val, key) { 75 | ddo[key] = val; 76 | }, target); 77 | 78 | ddo.controller = [].concat(_toConsumableArray(injects), [target]); 79 | 80 | ngModule.directive(name, function () { 81 | return ddo; 82 | }); 83 | }); 84 | module.exports = exports['default']; -------------------------------------------------------------------------------- /dist/decorators/providers/animation.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 4 | 5 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 6 | 7 | var _animation = require('./animation'); 8 | 9 | var _module2 = require('../../module'); 10 | 11 | var _module3 = _interopRequireDefault(_module2); 12 | 13 | var _writers = require('../../writers'); 14 | 15 | var _testsFrameworks = require('../../tests/frameworks'); 16 | 17 | describe('@Animation Decorator', function () { 18 | it('should set the correct provider name and type', function () { 19 | var MyClassAnimation = (function () { 20 | function MyClassAnimation() { 21 | _classCallCheck(this, _MyClassAnimation); 22 | } 23 | 24 | var _MyClassAnimation = MyClassAnimation; 25 | MyClassAnimation = (0, _animation.Animation)('.my-class')(MyClassAnimation) || MyClassAnimation; 26 | return MyClassAnimation; 27 | })(); 28 | 29 | _writers.providerWriter.get('type', MyClassAnimation).should.eql('animation'); 30 | _writers.providerWriter.get('name', MyClassAnimation).should.eql('.my-class'); 31 | }); 32 | 33 | it('should throw an error if you do not provide a class name', function () { 34 | var test = function test() { 35 | var MyAnimation = (function () { 36 | function MyAnimation() { 37 | _classCallCheck(this, _MyAnimation); 38 | } 39 | 40 | var _MyAnimation = MyAnimation; 41 | MyAnimation = (0, _animation.Animation)(MyAnimation) || MyAnimation; 42 | return MyAnimation; 43 | })(); 44 | }; 45 | 46 | test.should['throw'](Error, /must be supplied with the name of a class/); 47 | }); 48 | 49 | it('should throw an error if the class selector is invalid', function () { 50 | var element = function element() { 51 | var Element = (function () { 52 | function Element() { 53 | _classCallCheck(this, _Element); 54 | } 55 | 56 | var _Element = Element; 57 | Element = (0, _animation.Animation)('my-class')(Element) || Element; 58 | return Element; 59 | })(); 60 | }; 61 | 62 | var attr = function attr() { 63 | var Attr = (function () { 64 | function Attr() { 65 | _classCallCheck(this, _Attr); 66 | } 67 | 68 | var _Attr = Attr; 69 | Attr = (0, _animation.Animation)('[my-class]')(Attr) || Attr; 70 | return Attr; 71 | })(); 72 | }; 73 | 74 | element.should['throw'](Error, /Invalid selector passed/); 75 | attr.should['throw'](Error, /Invalid selector passed/); 76 | }); 77 | 78 | describe('Parser', function () { 79 | var parser = undefined, 80 | module = undefined; 81 | 82 | beforeEach(function () { 83 | parser = _module3['default'].getParser('animation'); 84 | module = { animation: _testsFrameworks.sinon.spy() }; 85 | }); 86 | 87 | it('should add a parser to Module', function () { 88 | parser.should.be.defined; 89 | }); 90 | 91 | it('should correctly register a new animation', function () { 92 | parser(function () {}, 'Test', [], module); 93 | 94 | module.animation.should.have.been.called; 95 | }); 96 | }); 97 | }); -------------------------------------------------------------------------------- /dist/decorators/component/require.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; 4 | 5 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 6 | 7 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 8 | 9 | var _require = require('./require'); 10 | 11 | var _writers = require('../../writers'); 12 | 13 | var _testsFrameworks = require('../../tests/frameworks'); 14 | 15 | describe('@Require Component Decorator', function () { 16 | it('should add the require DDO key to the target', function () { 17 | var MyClass = (function () { 18 | function MyClass() { 19 | _classCallCheck(this, _MyClass); 20 | } 21 | 22 | var _MyClass = MyClass; 23 | MyClass = (0, _require.Require)()(MyClass) || MyClass; 24 | return MyClass; 25 | })(); 26 | 27 | _writers.componentWriter.has('require', MyClass).should.be.ok; 28 | }); 29 | 30 | it('should set an array of requires as the value for the require key', function () { 31 | var MyClass = (function () { 32 | function MyClass() { 33 | _classCallCheck(this, _MyClass2); 34 | } 35 | 36 | var _MyClass2 = MyClass; 37 | MyClass = (0, _require.Require)('a', 'b')(MyClass) || MyClass; 38 | return MyClass; 39 | })(); 40 | 41 | Array.isArray(_writers.componentWriter.get('require', MyClass)).should.be.ok; 42 | _writers.componentWriter.get('require', MyClass).should.eql(['a', 'b']); 43 | }); 44 | 45 | it('should respect inheritance', function () { 46 | var Parent = (function () { 47 | function Parent() { 48 | _classCallCheck(this, _Parent); 49 | } 50 | 51 | var _Parent = Parent; 52 | Parent = (0, _require.Require)('a')(Parent) || Parent; 53 | return Parent; 54 | })(); 55 | 56 | var Child = (function (_Parent2) { 57 | _inherits(Child, _Parent2); 58 | 59 | function Child() { 60 | _classCallCheck(this, _Child); 61 | 62 | _get(Object.getPrototypeOf(_Child.prototype), 'constructor', this).apply(this, arguments); 63 | } 64 | 65 | var _Child = Child; 66 | Child = (0, _require.Require)('b')(Child) || Child; 67 | return Child; 68 | })(Parent); 69 | 70 | _writers.componentWriter.get('require', Child).should.eql(['a', 'b']); 71 | }); 72 | }); -------------------------------------------------------------------------------- /dist/decorators/inject.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; 4 | 5 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 6 | 7 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 8 | 9 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 10 | 11 | var _inject = require('./inject'); 12 | 13 | var _writers = require('../writers'); 14 | 15 | var _testsFrameworks = require('../tests/frameworks'); 16 | 17 | var _testsFrameworks2 = _interopRequireDefault(_testsFrameworks); 18 | 19 | describe('@Inject annotation', function () { 20 | it('should decorate a function with the $inject array', function () { 21 | var MyClass = (function () { 22 | function MyClass() { 23 | _classCallCheck(this, _MyClass); 24 | } 25 | 26 | var _MyClass = MyClass; 27 | MyClass = (0, _inject.Inject)('a', 'b', 'c')(MyClass) || MyClass; 28 | return MyClass; 29 | })(); 30 | 31 | _writers.baseWriter.has('$inject', MyClass).should.be.ok; 32 | }); 33 | 34 | it('should add injected dependencies to the $inject array', function () { 35 | var MyClass = (function () { 36 | function MyClass() { 37 | _classCallCheck(this, _MyClass2); 38 | } 39 | 40 | var _MyClass2 = MyClass; 41 | MyClass = (0, _inject.Inject)('a', 'b', 'c')(MyClass) || MyClass; 42 | return MyClass; 43 | })(); 44 | 45 | _writers.baseWriter.get('$inject', MyClass).should.eql(['a', 'b', 'c']); 46 | }); 47 | 48 | it('should adhere to inheritance', function () { 49 | var MyClass = (function () { 50 | function MyClass() { 51 | _classCallCheck(this, _MyClass3); 52 | } 53 | 54 | var _MyClass3 = MyClass; 55 | MyClass = (0, _inject.Inject)('a', 'b', 'c')(MyClass) || MyClass; 56 | return MyClass; 57 | })(); 58 | 59 | var SubClass = (function (_MyClass4) { 60 | _inherits(SubClass, _MyClass4); 61 | 62 | function SubClass() { 63 | _classCallCheck(this, _SubClass); 64 | 65 | _get(Object.getPrototypeOf(_SubClass.prototype), 'constructor', this).apply(this, arguments); 66 | } 67 | 68 | var _SubClass = SubClass; 69 | SubClass = (0, _inject.Inject)('d', 'e', 'f')(SubClass) || SubClass; 70 | return SubClass; 71 | })(MyClass); 72 | 73 | _writers.baseWriter.get('$inject', MyClass).should.eql(['a', 'b', 'c']); 74 | _writers.baseWriter.get('$inject', SubClass).should.eql(['d', 'e', 'f', 'a', 'b', 'c']); 75 | }); 76 | }); -------------------------------------------------------------------------------- /dist/decorators/providers/filter.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); 4 | 5 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 6 | 7 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 8 | 9 | require('../../tests/frameworks'); 10 | 11 | var _testsAngular = require('../../tests/angular'); 12 | 13 | var _writers = require('../../writers'); 14 | 15 | var _module2 = require('../../module'); 16 | 17 | var _module3 = _interopRequireDefault(_module2); 18 | 19 | var _filter2 = require('./filter'); 20 | 21 | describe('@Filter Decorator', function () { 22 | it('should set the correct name and provider type', function () { 23 | var SpliceFilter = (function () { 24 | function SpliceFilter() { 25 | _classCallCheck(this, _SpliceFilter); 26 | } 27 | 28 | var _SpliceFilter = SpliceFilter; 29 | SpliceFilter = (0, _filter2.Filter)('splice')(SpliceFilter) || SpliceFilter; 30 | return SpliceFilter; 31 | })(); 32 | 33 | _writers.providerWriter.get('type', SpliceFilter).should.eql('filter'); 34 | _writers.providerWriter.get('name', SpliceFilter).should.eql('splice'); 35 | }); 36 | 37 | it('should be parsed into a filter', function () { 38 | var SpliceFilter = (function () { 39 | function SpliceFilter() { 40 | _classCallCheck(this, _SpliceFilter2); 41 | } 42 | 43 | var _SpliceFilter2 = SpliceFilter; 44 | SpliceFilter = (0, _filter2.Filter)('splice')(SpliceFilter) || SpliceFilter; 45 | return SpliceFilter; 46 | })(); 47 | 48 | (0, _module3['default'])('test', []).add(SpliceFilter); 49 | 50 | _testsAngular.ngMocks.filter.should.have.been.calledWith('splice'); 51 | }); 52 | 53 | describe('Filter Parser Implementation', function () { 54 | var _filter = undefined; 55 | 56 | beforeEach(function () { 57 | var parser = _module3['default'].getParser('filter'); 58 | 59 | var Test = (function () { 60 | function Test() { 61 | _classCallCheck(this, Test); 62 | } 63 | 64 | _createClass(Test, [{ 65 | key: 'supports', 66 | value: function supports(input) { 67 | return typeof input === 'string'; 68 | } 69 | }, { 70 | key: 'transform', 71 | value: function transform(input, param) { 72 | return input + '-' + param; 73 | } 74 | }]); 75 | 76 | return Test; 77 | })(); 78 | 79 | parser(Test, 'test', [], { 80 | filter: function filter(name, filterBlock) { 81 | _filter = filterBlock[0](); 82 | } 83 | }); 84 | }); 85 | 86 | it('should have created a filter', function () { 87 | _filter.should.be.defined; 88 | }); 89 | 90 | it('should check for support before applying the transform', function () { 91 | var test = function test(obj) { 92 | return _filter(obj); 93 | }; 94 | 95 | test.should['throw'](Error, /does not support/); 96 | }); 97 | 98 | it('should apply the transform if the test passes', function () { 99 | _filter('hello', 'world').should.eql('hello-world'); 100 | }); 101 | }); 102 | }); -------------------------------------------------------------------------------- /dist/decorators/component/view.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; 4 | 5 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 6 | 7 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 8 | 9 | var _view = require('./view'); 10 | 11 | require('../../tests/frameworks'); 12 | 13 | var _writers = require('../../writers'); 14 | 15 | describe('@View Decorator', function () { 16 | it('should add a template option to a component', function () { 17 | var MyClass = (function () { 18 | function MyClass() { 19 | _classCallCheck(this, _MyClass); 20 | } 21 | 22 | var _MyClass = MyClass; 23 | MyClass = (0, _view.View)({ template: 'test' })(MyClass) || MyClass; 24 | return MyClass; 25 | })(); 26 | 27 | _writers.componentWriter.get('template', MyClass).should.eql('test'); 28 | }); 29 | 30 | it('should support template URLs', function () { 31 | var MyClass = (function () { 32 | function MyClass() { 33 | _classCallCheck(this, _MyClass2); 34 | } 35 | 36 | var _MyClass2 = MyClass; 37 | MyClass = (0, _view.View)({ templateUrl: '/path/to/it' })(MyClass) || MyClass; 38 | return MyClass; 39 | })(); 40 | 41 | _writers.componentWriter.get('templateUrl', MyClass).should.eql('/path/to/it'); 42 | }); 43 | 44 | it('should overwrite previously set template options via inheritance', function () { 45 | var Parent = (function () { 46 | function Parent() { 47 | _classCallCheck(this, _Parent); 48 | } 49 | 50 | var _Parent = Parent; 51 | Parent = (0, _view.View)({ template: 'test' })(Parent) || Parent; 52 | return Parent; 53 | })(); 54 | 55 | var Child = (function (_Parent2) { 56 | _inherits(Child, _Parent2); 57 | 58 | function Child() { 59 | _classCallCheck(this, _Child); 60 | 61 | _get(Object.getPrototypeOf(_Child.prototype), 'constructor', this).apply(this, arguments); 62 | } 63 | 64 | var _Child = Child; 65 | Child = (0, _view.View)({ templateUrl: '/path/to/it' })(Child) || Child; 66 | return Child; 67 | })(Parent); 68 | 69 | var GrandChild = (function (_Child2) { 70 | _inherits(GrandChild, _Child2); 71 | 72 | function GrandChild() { 73 | _classCallCheck(this, _GrandChild); 74 | 75 | _get(Object.getPrototypeOf(_GrandChild.prototype), 'constructor', this).apply(this, arguments); 76 | } 77 | 78 | var _GrandChild = GrandChild; 79 | GrandChild = (0, _view.View)({ template: 'new test' })(GrandChild) || GrandChild; 80 | return GrandChild; 81 | })(Child); 82 | 83 | _writers.componentWriter.get('template', Parent).should.eql('test'); 84 | _writers.componentWriter.get('templateUrl', Child).should.eql('/path/to/it'); 85 | (_writers.componentWriter.get('template', Child) === undefined).should.be['true']; 86 | _writers.componentWriter.get('template', GrandChild).should.eql('new test'); 87 | (_writers.componentWriter.get('templateUrl', GrandChild) === undefined).should.be['true']; 88 | }); 89 | }); -------------------------------------------------------------------------------- /dist/decorators/providers/controller.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; 4 | 5 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 6 | 7 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 8 | 9 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 10 | 11 | var _testsFrameworks = require('../../tests/frameworks'); 12 | 13 | var _module2 = require('../../module'); 14 | 15 | var _module3 = _interopRequireDefault(_module2); 16 | 17 | var _writers = require('../../writers'); 18 | 19 | var _controller = require('./controller'); 20 | 21 | describe('@Controller annotation', function () { 22 | it('should decorate a class with $provider meta data', function () { 23 | var MyController = (function () { 24 | function MyController() { 25 | _classCallCheck(this, _MyController); 26 | } 27 | 28 | var _MyController = MyController; 29 | MyController = (0, _controller.Controller)(MyController) || MyController; 30 | return MyController; 31 | })(); 32 | 33 | _writers.providerWriter.get('type', MyController).should.eql('controller'); 34 | _writers.providerWriter.get('name', MyController).should.eql('MyController'); 35 | }); 36 | 37 | it('should register a controller parser with the Module class', function () { 38 | var parser = _module3['default'].getParser('controller'); 39 | 40 | parser.should.exist; 41 | }); 42 | 43 | it('should correctly parse a controller', function () { 44 | var MyController = (function () { 45 | function MyController() { 46 | _classCallCheck(this, _MyController2); 47 | } 48 | 49 | var _MyController2 = MyController; 50 | MyController = (0, _controller.Controller)(MyController) || MyController; 51 | return MyController; 52 | })(); 53 | 54 | var module = { 55 | controller: _testsFrameworks.sinon.spy() 56 | }; 57 | 58 | var parser = _module3['default'].getParser('controller'); 59 | 60 | parser(MyController, 'MyController', [], module); 61 | 62 | var name = module.controller.args[0][0]; 63 | var controller = module.controller.args[0][1]; 64 | 65 | module.controller.called.should.be['true']; 66 | name.should.equal('MyController'); 67 | controller.should.eql([MyController]); 68 | }); 69 | 70 | it('should define the $provider property on the prototype of the target', function () { 71 | var MyController = (function () { 72 | function MyController() { 73 | _classCallCheck(this, _MyController3); 74 | } 75 | 76 | var _MyController3 = MyController; 77 | MyController = (0, _controller.Controller)(MyController) || MyController; 78 | return MyController; 79 | })(); 80 | 81 | var NewController = (function (_MyController4) { 82 | _inherits(NewController, _MyController4); 83 | 84 | function NewController() { 85 | _classCallCheck(this, _NewController); 86 | 87 | _get(Object.getPrototypeOf(_NewController.prototype), 'constructor', this).apply(this, arguments); 88 | } 89 | 90 | var _NewController = NewController; 91 | NewController = (0, _controller.Controller)(NewController) || NewController; 92 | return NewController; 93 | })(MyController); 94 | 95 | _writers.providerWriter.get('name', MyController).should.not.equal('NewController'); 96 | _writers.providerWriter.get('name', MyController).should.equal('MyController'); 97 | _writers.providerWriter.get('name', NewController).should.equal('NewController'); 98 | }); 99 | }); -------------------------------------------------------------------------------- /dist/decorators/providers/service.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; 4 | 5 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 6 | 7 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 8 | 9 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 10 | 11 | var _module2 = require('../../module'); 12 | 13 | var _module3 = _interopRequireDefault(_module2); 14 | 15 | var _service = require('./service'); 16 | 17 | var _testsFrameworks = require('../../tests/frameworks'); 18 | 19 | var _writers = require('../../writers'); 20 | 21 | describe('@Service Decorator', function () { 22 | it('should decorate a class with a provider name and type', function () { 23 | var MyService = (function () { 24 | function MyService() { 25 | _classCallCheck(this, _MyService); 26 | } 27 | 28 | var _MyService = MyService; 29 | MyService = (0, _service.Service)(MyService) || MyService; 30 | return MyService; 31 | })(); 32 | 33 | _writers.providerWriter.get('type', MyService).should.eql('service'); 34 | _writers.providerWriter.get('name', MyService).should.eql('MyService'); 35 | }); 36 | 37 | it('should adhere to inheritance', function () { 38 | var BaseClass = (function () { 39 | function BaseClass() { 40 | _classCallCheck(this, _BaseClass); 41 | } 42 | 43 | var _BaseClass = BaseClass; 44 | BaseClass = (0, _service.Service)(BaseClass) || BaseClass; 45 | return BaseClass; 46 | })(); 47 | 48 | var MyClass = (function (_BaseClass2) { 49 | _inherits(MyClass, _BaseClass2); 50 | 51 | function MyClass() { 52 | _classCallCheck(this, _MyClass); 53 | 54 | _get(Object.getPrototypeOf(_MyClass.prototype), 'constructor', this).apply(this, arguments); 55 | } 56 | 57 | var _MyClass = MyClass; 58 | MyClass = (0, _service.Service)(MyClass) || MyClass; 59 | return MyClass; 60 | })(BaseClass); 61 | 62 | _writers.providerWriter.get('name', BaseClass).should.eql('BaseClass'); 63 | _writers.providerWriter.get('name', MyClass).should.eql('MyClass'); 64 | }); 65 | 66 | it('should let you specify a name for the service', function () { 67 | var BaseClass = (function () { 68 | function BaseClass() { 69 | _classCallCheck(this, _BaseClass3); 70 | } 71 | 72 | var _BaseClass3 = BaseClass; 73 | BaseClass = (0, _service.Service)('Renamed')(BaseClass) || BaseClass; 74 | return BaseClass; 75 | })(); 76 | 77 | _writers.providerWriter.get('name', BaseClass).should.eql('Renamed'); 78 | }); 79 | 80 | describe('Parser', function () { 81 | var parser = undefined, 82 | module = undefined; 83 | 84 | beforeEach(function () { 85 | parser = _module3['default'].getParser('service'); 86 | module = { 87 | service: _testsFrameworks.sinon.spy() 88 | }; 89 | }); 90 | 91 | it('should register itself with Module', function () { 92 | parser.should.be.defined; 93 | }); 94 | 95 | it('should parse an annotated class into an ng service', function () { 96 | var MyService = (function () { 97 | function MyService() { 98 | _classCallCheck(this, _MyService2); 99 | } 100 | 101 | var _MyService2 = MyService; 102 | MyService = (0, _service.Service)(MyService) || MyService; 103 | return MyService; 104 | })(); 105 | 106 | parser(MyService, 'MyService', [], module); 107 | 108 | module.service.should.have.been.calledWith('MyService', [MyService]); 109 | }); 110 | }); 111 | }); -------------------------------------------------------------------------------- /src/util/decorate-directive.spec.js: -------------------------------------------------------------------------------- 1 | /*global describe,it,beforeEach */ 2 | import decorateDirective from './decorate-directive'; 3 | import Module from '../module'; 4 | import {componentWriter} from '../writers'; 5 | import {sinon} from '../tests/frameworks'; 6 | 7 | describe('Directive Decorator', function(){ 8 | class Example{ } 9 | 10 | it('should let you bind attributes to the controller using a simple map', function(){ 11 | decorateDirective({ bind: { 12 | 'someProp' : '@' 13 | }}, Example); 14 | 15 | componentWriter.get('scope', Example).should.eql({ someProp: '@' }); 16 | componentWriter.get('bindToController', Example).should.be.ok; 17 | }); 18 | 19 | it('should manually let you configure the scope', function(){ 20 | decorateDirective({ 21 | scope : true 22 | }, Example); 23 | 24 | componentWriter.get('scope', Example).should.be.ok; 25 | }); 26 | 27 | it('should let you bind attributes to the controller using a properties array like Angular 2', function(){ 28 | decorateDirective({ 29 | properties: [ 30 | 'someProp: @', 31 | 'anotherProp: =' 32 | ] 33 | }, Example); 34 | 35 | componentWriter.get('bindToController', Example).should.eql({ 36 | 'someProp': '@', 37 | 'anotherProp': '=' 38 | }); 39 | }); 40 | 41 | it('should throw an error if you do not pass an array to the properties field', function(){ 42 | let dec = (val) => () => decorateDirective({ 43 | properties: val 44 | }, Example); 45 | 46 | dec('string').should.throw(TypeError); 47 | dec({}).should.throw(TypeError); 48 | dec(false).should.throw(TypeError); 49 | dec(null).should.throw(TypeError); 50 | dec(undefined).should.not.throw(TypeError); 51 | }); 52 | 53 | it('should set the controllerAs field if provided', function(){ 54 | decorateDirective({ controllerAs: 'hi' }, Example); 55 | 56 | componentWriter.get('controllerAs', Example).should.eql('hi'); 57 | }); 58 | 59 | afterEach(function(){ 60 | componentWriter.clear(Example); 61 | }); 62 | 63 | describe('Directive Parser', function(){ 64 | let parser, ngModule; 65 | 66 | beforeEach(function(){ 67 | parser = Module.getParser('directive'); 68 | ngModule = { directive: sinon.spy() }; 69 | }); 70 | 71 | it('should be defined', function(){ 72 | parser.should.be.defined; 73 | }); 74 | 75 | it('should correctly generate a simple DDO', function(){ 76 | class Test{ } 77 | decorateDirective({}, Test); 78 | 79 | parser(Test, 'testSelector', [], ngModule); 80 | 81 | let [name, factory] = ngModule.directive.args[0]; 82 | 83 | name.should.eql('testSelector'); 84 | (typeof factory).should.eql('function'); 85 | factory().should.eql({ 86 | controller: [Test] 87 | }); 88 | }); 89 | 90 | it('should generate a complex DDO', function(){ 91 | class AnotherTest{ 92 | static link(){ } 93 | static compile(){ } 94 | } 95 | 96 | decorateDirective({ 97 | scope: true, 98 | properties: [ 99 | 'attr: @', 100 | 'prop : =' 101 | ], 102 | controllerAs: 'asdf' 103 | }, AnotherTest); 104 | 105 | parser(AnotherTest, 'testSelector', ['$q', '$timeout'], ngModule); 106 | 107 | let [name, factory] = ngModule.directive.args[0]; 108 | 109 | factory().should.eql({ 110 | scope: true, 111 | bindToController: { 112 | attr: '@', 113 | prop: '=' 114 | }, 115 | controllerAs: 'asdf', 116 | controller: ['$q', '$timeout', AnotherTest], 117 | link: AnotherTest.link, 118 | compile: AnotherTest.compile 119 | }); 120 | }); 121 | 122 | it('should respect properties inheritance during parsing', function(){ 123 | class Parent{ } 124 | 125 | decorateDirective({ 126 | properties: [ 127 | '=first', 128 | '@second' 129 | ], 130 | scope: { 131 | first: '=', 132 | second: '&another' 133 | } 134 | }, Parent); 135 | 136 | class Child extends Parent{ } 137 | 138 | decorateDirective({ 139 | properties: [ 140 | '&second', 141 | '&third', 142 | 'fourth: =*renamed' 143 | ], 144 | scope: { 145 | second: '=primary', 146 | third: '@' 147 | } 148 | }, Child); 149 | 150 | parser(Child, 'childSelector', [], ngModule); 151 | 152 | let [name, factory] = ngModule.directive.args[0]; 153 | 154 | factory().should.eql({ 155 | bindToController: { 156 | first: '=', 157 | second: '&', 158 | third: '&', 159 | fourth: '=*renamed' 160 | }, 161 | scope: { 162 | first: '=', 163 | second: '=primary', 164 | third: '@' 165 | }, 166 | controller: [Child] 167 | }); 168 | }); 169 | }); 170 | }); 171 | -------------------------------------------------------------------------------- /dist/module.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 4 | 5 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 6 | 7 | var _testsFrameworks = require('./tests/frameworks'); 8 | 9 | var _testsAngular = require('./tests/angular'); 10 | 11 | var _writers = require('./writers'); 12 | 13 | var _module2 = require('./module'); 14 | 15 | var _module3 = _interopRequireDefault(_module2); 16 | 17 | var provider = function provider(type, name) { 18 | return function (t) { 19 | _writers.providerWriter.set('type', type, t); 20 | _writers.providerWriter.set('name', name, t); 21 | }; 22 | }; 23 | 24 | describe('Decorator Supported Module', function () { 25 | it('should let you create an Angular module', function () { 26 | var module = (0, _module3['default'])('test', []); 27 | 28 | module.should.be.defined; 29 | _testsAngular.angular.module.should.have.been.called; 30 | }); 31 | 32 | it('should let you publish the module to gain access to the ng module', function () { 33 | (0, _module3['default'])('test', []).publish().should.eql(_testsAngular.ngMocks); 34 | }); 35 | 36 | it('should let you config the module', function () { 37 | var config = ['$q', function () {}]; 38 | (0, _module3['default'])('test', []).config(config); 39 | 40 | _testsAngular.ngMocks.config.should.have.been.calledWith(config); 41 | }); 42 | 43 | it('should let you create a run function', function () { 44 | var run = ['$q', function () {}]; 45 | (0, _module3['default'])('test', []).run(run); 46 | 47 | _testsAngular.ngMocks.run.should.have.been.calledWith(run); 48 | }); 49 | 50 | it('should let you add value to the module', function () { 51 | var value = 'testValue'; 52 | (0, _module3['default'])('test', []).value('test', value); 53 | 54 | _testsAngular.ngMocks.value.should.have.been.calledWith('test', value); 55 | }); 56 | 57 | it('should let you add constant to the module', function () { 58 | var value = 'constantValue'; 59 | (0, _module3['default'])('test', []).constant('TEST', value); 60 | 61 | _testsAngular.ngMocks.constant.should.have.been.calledWith('TEST', value); 62 | }); 63 | 64 | describe('Adding providers', function () { 65 | var exampleRegister = undefined; 66 | 67 | beforeEach(function () { 68 | exampleRegister = _testsFrameworks.sinon.spy(); 69 | _module3['default'].addProvider('example', exampleRegister); 70 | }); 71 | 72 | it('should let you add providers', function () { 73 | var A = (function () { 74 | function A() { 75 | _classCallCheck(this, _A); 76 | } 77 | 78 | var _A = A; 79 | A = provider('example', 'A')(A) || A; 80 | return A; 81 | })(); 82 | 83 | var mod = (0, _module3['default'])('test', []).add(A); 84 | 85 | exampleRegister.should.have.been.calledWith(A, 'A', [], mod.publish()); 86 | }); 87 | 88 | it('should let you add multiple providers', function () { 89 | var A = (function () { 90 | function A() { 91 | _classCallCheck(this, _A2); 92 | } 93 | 94 | var _A2 = A; 95 | A = provider('example', 'A')(A) || A; 96 | return A; 97 | })(); 98 | 99 | var B = (function () { 100 | function B() { 101 | _classCallCheck(this, _B); 102 | } 103 | 104 | var _B = B; 105 | B = provider('example', 'B')(B) || B; 106 | return B; 107 | })(); 108 | 109 | var C = (function () { 110 | function C() { 111 | _classCallCheck(this, _C); 112 | } 113 | 114 | var _C = C; 115 | C = provider('example', 'C')(C) || C; 116 | return C; 117 | })(); 118 | 119 | (0, _module3['default'])('test', []).add(A, B, C); 120 | 121 | exampleRegister.should.have.been.calledThrice; 122 | }); 123 | 124 | it('should throw an error if you add provider with no decorators', function () { 125 | var A = function A() { 126 | _classCallCheck(this, A); 127 | }; 128 | 129 | var test = function test() { 130 | return (0, _module3['default'])('test', []).add(A); 131 | }; 132 | 133 | test.should['throw'](Error, /Cannot read provider/); 134 | }); 135 | 136 | it('should throw an error when adding a provider with an unrecognized type', function () { 137 | var A = (function () { 138 | function A() { 139 | _classCallCheck(this, _A3); 140 | } 141 | 142 | var _A3 = A; 143 | A = provider('dne', 'A')(A) || A; 144 | return A; 145 | })(); 146 | 147 | var test = function test() { 148 | return (0, _module3['default'])('test', []).add(A); 149 | }; 150 | 151 | test.should['throw'](Error, /No parser registered/); 152 | }); 153 | }); 154 | }); -------------------------------------------------------------------------------- /dist/module.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { 4 | value: true 5 | }); 6 | var _bind = Function.prototype.bind; 7 | 8 | var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); 9 | 10 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 11 | 12 | var _writers = require('./writers'); 13 | 14 | var _parsers = {}; 15 | 16 | var DecoratedModule = (function () { 17 | function DecoratedModule(name) { 18 | var modules = arguments.length <= 1 || arguments[1] === undefined ? false : arguments[1]; 19 | 20 | _classCallCheck(this, DecoratedModule); 21 | 22 | this.name = name; 23 | this.moduleList(modules); 24 | 25 | if (modules) { 26 | this._module = angular.module(name, this._dependencies); 27 | } else { 28 | this._module = angular.module(name); 29 | } 30 | } 31 | 32 | _createClass(DecoratedModule, [{ 33 | key: 'add', 34 | value: function add() { 35 | var _iteratorNormalCompletion = true; 36 | var _didIteratorError = false; 37 | var _iteratorError = undefined; 38 | 39 | try { 40 | for (var _len = arguments.length, providers = Array(_len), _key = 0; _key < _len; _key++) { 41 | providers[_key] = arguments[_key]; 42 | } 43 | 44 | for (var _iterator = providers[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { 45 | var provider = _step.value; 46 | 47 | if (!_writers.providerWriter.has('type', provider)) { 48 | throw new Error('Cannot read provider metadata. Are you adding a class that hasn\'t been decorated yet?'); 49 | } 50 | 51 | var type = _writers.providerWriter.get('type', provider); 52 | var _name = _writers.providerWriter.get('name', provider); 53 | var inject = _writers.baseWriter.get('$inject', provider) || []; 54 | 55 | if (_parsers[type]) { 56 | _parsers[type](provider, _name, inject, this._module); 57 | } else { 58 | throw new Error('No parser registered for type \'' + type + '\''); 59 | } 60 | } 61 | } catch (err) { 62 | _didIteratorError = true; 63 | _iteratorError = err; 64 | } finally { 65 | try { 66 | if (!_iteratorNormalCompletion && _iterator['return']) { 67 | _iterator['return'](); 68 | } 69 | } finally { 70 | if (_didIteratorError) { 71 | throw _iteratorError; 72 | } 73 | } 74 | } 75 | 76 | return this; 77 | } 78 | }, { 79 | key: 'publish', 80 | value: function publish() { 81 | return this._module; 82 | } 83 | }, { 84 | key: 'moduleList', 85 | value: function moduleList(modules) { 86 | this._dependencies = []; 87 | 88 | if (modules && modules.length !== 0) { 89 | for (var i = 0; i < modules.length; i++) { 90 | if (modules[i] && modules[i].name) { 91 | this._dependencies.push(modules[i].name); 92 | } else if (typeof modules[i] === 'string') { 93 | this._dependencies.push(modules[i]); 94 | } else { 95 | throw new Error('Cannot read module: Unknown module in ' + this.name); 96 | } 97 | } 98 | } 99 | } 100 | }, { 101 | key: 'config', 102 | value: function config(configFunc) { 103 | this._module.config(configFunc); 104 | 105 | return this; 106 | } 107 | }, { 108 | key: 'run', 109 | value: function run(runFunc) { 110 | this._module.run(runFunc); 111 | 112 | return this; 113 | } 114 | }, { 115 | key: 'value', 116 | value: function value() { 117 | var _module2; 118 | 119 | (_module2 = this._module).value.apply(_module2, arguments); 120 | 121 | return this; 122 | } 123 | }, { 124 | key: 'constant', 125 | value: function constant() { 126 | var _module3; 127 | 128 | (_module3 = this._module).constant.apply(_module3, arguments); 129 | 130 | return this; 131 | } 132 | }]); 133 | 134 | return DecoratedModule; 135 | })(); 136 | 137 | function Module() { 138 | for (var _len2 = arguments.length, params = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { 139 | params[_key2] = arguments[_key2]; 140 | } 141 | 142 | return new (_bind.apply(DecoratedModule, [null].concat(params)))(); 143 | } 144 | 145 | Module.addProvider = function (providerType, parser) { 146 | _parsers[providerType] = parser; 147 | }; 148 | 149 | Module.getParser = function (providerType) { 150 | return _parsers[providerType]; 151 | }; 152 | 153 | exports['default'] = Module; 154 | module.exports = exports['default']; -------------------------------------------------------------------------------- /dist/decorators/providers/component.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; 4 | 5 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 6 | 7 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 8 | 9 | var _component = require('./component'); 10 | 11 | require('../../tests/frameworks'); 12 | 13 | var _writers = require('../../writers'); 14 | 15 | describe('@Component annotation', function () { 16 | it('should decorate a class with correct $provider metadata', function () { 17 | var MyComponentCtrl = (function () { 18 | function MyComponentCtrl() { 19 | _classCallCheck(this, _MyComponentCtrl); 20 | } 21 | 22 | var _MyComponentCtrl = MyComponentCtrl; 23 | MyComponentCtrl = (0, _component.Component)({ selector: 'my-component' })(MyComponentCtrl) || MyComponentCtrl; 24 | return MyComponentCtrl; 25 | })(); 26 | 27 | _writers.providerWriter.has('type', MyComponentCtrl).should.be.ok; 28 | _writers.providerWriter.get('type', MyComponentCtrl).should.eql('directive'); 29 | _writers.providerWriter.has('name', MyComponentCtrl).should.be.ok; 30 | _writers.providerWriter.get('name', MyComponentCtrl).should.eql('myComponent'); 31 | }); 32 | 33 | it('should set sensible defaults using $component metadata', function () { 34 | var MyComponentCtrl = (function () { 35 | function MyComponentCtrl() { 36 | _classCallCheck(this, _MyComponentCtrl2); 37 | } 38 | 39 | var _MyComponentCtrl2 = MyComponentCtrl; 40 | MyComponentCtrl = (0, _component.Component)({ selector: 'my-component' })(MyComponentCtrl) || MyComponentCtrl; 41 | return MyComponentCtrl; 42 | })(); 43 | 44 | _writers.componentWriter.get('restrict', MyComponentCtrl).should.eql('E'); 45 | _writers.componentWriter.get('scope', MyComponentCtrl).should.eql({}); 46 | _writers.componentWriter.get('bindToController', MyComponentCtrl).should.be.ok; 47 | }); 48 | 49 | it('should throw an error if the selector is not an element', function () { 50 | var caughtAttr = false; 51 | var caughtClass = false; 52 | 53 | try { 54 | (function () { 55 | var MyClass = (function () { 56 | function MyClass() { 57 | _classCallCheck(this, _MyClass); 58 | } 59 | 60 | var _MyClass = MyClass; 61 | MyClass = (0, _component.Component)({ selector: '[my-attr]' })(MyClass) || MyClass; 62 | return MyClass; 63 | })(); 64 | })(); 65 | } catch (e) { 66 | caughtAttr = true; 67 | } 68 | 69 | try { 70 | (function () { 71 | var MyClass = (function () { 72 | function MyClass() { 73 | _classCallCheck(this, _MyClass2); 74 | } 75 | 76 | var _MyClass2 = MyClass; 77 | MyClass = (0, _component.Component)({ selector: '.my-class' })(MyClass) || MyClass; 78 | return MyClass; 79 | })(); 80 | })(); 81 | } catch (e) { 82 | caughtClass = true; 83 | } 84 | 85 | caughtAttr.should.be.ok; 86 | caughtClass.should.be.ok; 87 | }); 88 | 89 | it('should respect inheritance', function () { 90 | var ParentCtrl = (function () { 91 | function ParentCtrl() { 92 | _classCallCheck(this, _ParentCtrl); 93 | } 94 | 95 | var _ParentCtrl = ParentCtrl; 96 | ParentCtrl = (0, _component.Component)({ 97 | selector: 'parent', 98 | properties: ['@first', '=second'] 99 | })(ParentCtrl) || ParentCtrl; 100 | return ParentCtrl; 101 | })(); 102 | 103 | var ChildCtrl = (function (_ParentCtrl2) { 104 | _inherits(ChildCtrl, _ParentCtrl2); 105 | 106 | function ChildCtrl() { 107 | _classCallCheck(this, _ChildCtrl); 108 | 109 | _get(Object.getPrototypeOf(_ChildCtrl.prototype), 'constructor', this).apply(this, arguments); 110 | } 111 | 112 | var _ChildCtrl = ChildCtrl; 113 | ChildCtrl = (0, _component.Component)({ selector: 'child' })(ChildCtrl) || ChildCtrl; 114 | return ChildCtrl; 115 | })(ParentCtrl); 116 | 117 | _writers.componentWriter.get('bindToController', ChildCtrl).should.eql({ 118 | first: '@', 119 | second: '=' 120 | }); 121 | }); 122 | }); -------------------------------------------------------------------------------- /changelog.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## v1.2.0 4 | * Added experimental typings file for TypeScript support 5 | * Added publishing for bower 6 | 7 | ## v1.1.0 8 | Added `constant` and `value` aliases to to Module: 9 | 10 | ```js 11 | import {Module} from 'angular-decorators'; 12 | 13 | Module('my-module', []) 14 | .constant('constant', 'test constant') 15 | .value('value', 'test value'); 16 | 17 | ## v1.0.3 18 | 19 | **Documentation now includes examples of `@Animation` and `@Provider`** 20 | Examples of usage: 21 | ```js 22 | @Animation('.my-animation') 23 | class MyAnimation{ ... } 24 | 25 | @Provider('SomeService') 26 | class SomeServiceProvider{ ... } 27 | ``` 28 | 29 | **Properties and scope of a component are respected with inheritance** 30 | 31 | ```js 32 | @Component({ 33 | selector: 'parent', 34 | properties: [ 35 | '=first' 36 | ] 37 | }) 38 | class ParentCtrl{ ... } 39 | 40 | @Component({ 41 | selector: 'child', 42 | properties: [ 43 | '@second' 44 | ] 45 | }) 46 | class ChildCtrl extends ParentCtrl{ ... } 47 | 48 | // Properties of childCtrl are: ['=first', '@second'] 49 | ``` 50 | 51 | ## v1.0.2 52 | 53 | **Fixed bug where properties were parsed incorrectly** 54 | Property declarations now have full support for watch collection and optional symbols: 55 | 56 | ```js 57 | @Component({ 58 | selector: 'example', 59 | properties: [ 60 | '=*first', 61 | '=?second', 62 | '=*?third' 63 | ] 64 | }) 65 | ``` 66 | 67 | ## v1.0.1 68 | 69 | **Correctly exporting `@Inject` decorator** 70 | 71 | ## v1.0.0 72 | 73 | ### New Features 74 | 75 | * `@Animation` decorator for creating animation providers 76 | * `@Provider` decorator for creating raw providers 77 | * `@Filter` decorator for defining Angular 2 pipe-style filters 78 | * `@Component({ properties: [ 'myAttr: =renamedAttr' ] })` for defining properties Angular 2 style 79 | 80 | ### Breaking Changes 81 | 82 | **Inject decorator now places new injects at the front of the injection array rather than at the end** 83 | 84 | Given: 85 | 86 | ```js 87 | @Inject('$http', '$q') 88 | class Parent{ } 89 | 90 | @Inject('$timeout') 91 | class Child extends Parent{ } 92 | ``` 93 | 94 | Before, injection array on `Child` would have been `['$http', '$q', '$timeout']`. Starting with v1.0 it will now be `['$timeout', '$http', '$q']`. This makes it easy for subclasses to capture parent dependencies using a rest parameter: 95 | 96 | ```js 97 | @Inject('$timeout') 98 | class Child extends Parent{ 99 | constructor($timeout, ...parentDependcies){ 100 | super(...parentDependencies); 101 | } 102 | } 103 | ``` 104 | 105 | 106 | 107 | **Metadata is now installed on classes using a polyfill of the Reflect metadata API** 108 | 109 | angular-decorators uses two libraries to achieve this: 110 | 111 | * [reflect-metadata polyfill](https://github.com/rbuckton/ReflectDecorators) - Polyfill for the proposed Reflect Metadata API 112 | * [metawriter](https://github.com/MikeRyan52/metawriter) - A small library that wraps the metadata API to add namespacing, iteration, and a map-like syntax 113 | 114 | 115 | 116 | **`@Template` decorator has been renamed to @View to align with Angular 2 API** 117 | 118 | Before: 119 | ```js 120 | @Template({ url: '/path/to/it.html' }) 121 | class ComponentCtrl{ ... } 122 | 123 | @Template({ inline: '

Inline Template

' }) 124 | class AnotherComponentCtrl{ ... } 125 | ``` 126 | 127 | After: 128 | ```js 129 | @View({ templateUrl: '/path/to/it.html' }) 130 | class ComponentCtrl{ ... } 131 | 132 | @View({ template: '

Inline Template

' }) 133 | class AnotherComponentCtrl{ ... } 134 | ``` 135 | 136 | 137 | 138 | **`@Decorator` decorator has been renamed to `@Directive` to align with new Angular 2 API. `@Directive` no longer exposes the controller on the scope.** 139 | 140 | Before: 141 | ```js 142 | @Decorator({ selector: '[my-attr]' }) 143 | class MyDecoratorCtrl{ ... } 144 | ``` 145 | 146 | After: 147 | ```js 148 | @Directive({ selector: '[my-attr]' }) 149 | class MyDecoratorCtrl{ ... } 150 | ``` 151 | 152 | 153 | 154 | **`@Component` decorator now sets `scope: {}` by default on the directive definition object** 155 | 156 | You can manually override this: 157 | 158 | ```js 159 | @Component({ selector: 'my-component', scope: false }) 160 | class MyComponentCtrl{ ... } 161 | ``` 162 | 163 | 164 | 165 | **Provider parsers are now passed the provider, name, injection array, and Angular module** 166 | 167 | Before: 168 | ```js 169 | Module.registerProvider('myProvider', function(provider, ngModule){ }); 170 | ``` 171 | 172 | After: 173 | ```js 174 | Module.addProvider('myProvider', function(provider, providerName, injectionArray, ngModule){ }); 175 | ``` 176 | 177 | **Classes are no longer decorated with an `unpackRequires` static method for handling requires** 178 | This can be easily done using a destructuring assignment 179 | 180 | Before: 181 | ```js 182 | @Require('$http') 183 | class MyClass{ 184 | static link(scope, element, attrs, requires){ 185 | let {$http} = MyClass.unpackRequires(requires); 186 | } 187 | } 188 | ``` 189 | 190 | After: 191 | ```js 192 | @Require('$http') 193 | class MyClass{ 194 | static link(scope, element, attrs, requires){ 195 | let [$http] = requires; 196 | } 197 | } 198 | ``` 199 | -------------------------------------------------------------------------------- /dist/decorators/providers/factory.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _slicedToArray = (function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i['return']) _i['return'](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError('Invalid attempt to destructure non-iterable instance'); } }; })(); 4 | 5 | var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); 6 | 7 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 8 | 9 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 10 | 11 | var _factory = require('./factory'); 12 | 13 | var _module2 = require('../../module'); 14 | 15 | var _module3 = _interopRequireDefault(_module2); 16 | 17 | var _testsFrameworks = require('../../tests/frameworks'); 18 | 19 | var _writers = require('../../writers'); 20 | 21 | describe('@Factory Annotation', function () { 22 | it('should decorate a class with $provider meta information', function () { 23 | var ExampleClass = (function () { 24 | function ExampleClass() { 25 | _classCallCheck(this, _ExampleClass); 26 | } 27 | 28 | var _ExampleClass = ExampleClass; 29 | ExampleClass = (0, _factory.Factory)('MyFactory')(ExampleClass) || ExampleClass; 30 | return ExampleClass; 31 | })(); 32 | 33 | _writers.providerWriter.get('type', ExampleClass).should.eql('factory'); 34 | _writers.providerWriter.get('name', ExampleClass).should.eql('MyFactory'); 35 | }); 36 | 37 | describe('Parser', function () { 38 | var parser = undefined, 39 | module = undefined; 40 | 41 | beforeEach(function () { 42 | module = { factory: _testsFrameworks.sinon.spy() }; 43 | parser = _module3['default'].getParser('factory'); 44 | }); 45 | 46 | it('should register itself with Module', function () { 47 | parser.should.be.defined; 48 | }); 49 | 50 | it('should use the static create method on a class as the factory function', function () { 51 | var called = false; 52 | 53 | var ExampleClass = (function () { 54 | function ExampleClass() { 55 | _classCallCheck(this, _ExampleClass2); 56 | } 57 | 58 | _createClass(ExampleClass, null, [{ 59 | key: 'create', 60 | value: function create() { 61 | called = true; 62 | } 63 | }]); 64 | 65 | var _ExampleClass2 = ExampleClass; 66 | ExampleClass = (0, _factory.Factory)('MyFactory')(ExampleClass) || ExampleClass; 67 | return ExampleClass; 68 | })(); 69 | 70 | parser(ExampleClass, 'MyFactory', [], module); 71 | var factoryProvider = module.factory.args[0][1][0]; 72 | 73 | factoryProvider()(); 74 | 75 | called.should.be['true']; 76 | }); 77 | 78 | it('should pass dependencies to the create method', function () { 79 | var a = undefined, 80 | b = undefined; 81 | 82 | var ExampleClass = (function () { 83 | function ExampleClass() { 84 | _classCallCheck(this, _ExampleClass3); 85 | } 86 | 87 | _createClass(ExampleClass, null, [{ 88 | key: 'create', 89 | value: function create(dependencies) { 90 | var _dependencies = _slicedToArray(dependencies, 2); 91 | 92 | a = _dependencies[0]; 93 | b = _dependencies[1]; 94 | } 95 | }]); 96 | 97 | var _ExampleClass3 = ExampleClass; 98 | ExampleClass = (0, _factory.Factory)('MyFactory')(ExampleClass) || ExampleClass; 99 | return ExampleClass; 100 | })(); 101 | 102 | parser(ExampleClass, 'MyFactory', [], module); 103 | var factoryProvider = module.factory.args[0][1][0]; 104 | 105 | factoryProvider(1, 2)(); 106 | 107 | a.should.equal(1); 108 | b.should.equal(2); 109 | }); 110 | 111 | it('should generate a factory function for a class', function () { 112 | var ExampleClass = (function () { 113 | function ExampleClass(depA, depB, depC, propA, propB, propC) { 114 | _classCallCheck(this, _ExampleClass4); 115 | 116 | this.depA = depA; 117 | this.depB = depB; 118 | this.depC = depC; 119 | 120 | this.propA = propA; 121 | this.propB = propB; 122 | this.propC = propC; 123 | } 124 | 125 | var _ExampleClass4 = ExampleClass; 126 | ExampleClass = (0, _factory.Factory)('MyFactory')(ExampleClass) || ExampleClass; 127 | return ExampleClass; 128 | })(); 129 | 130 | parser(ExampleClass, 'MyFactory', [], module); 131 | 132 | var factoryName = module.factory.args[0][0]; 133 | var factoryProvider = module.factory.args[0][1][0]; 134 | factoryName.should.equal('MyFactory'); 135 | factoryProvider.should.be.defined; 136 | 137 | var factory = factoryProvider('a', 'b', 'c'); 138 | factory.should.be.defined; 139 | 140 | var instance = factory('1', '2', '3'); 141 | instance.should.have.property('propA', '1'); 142 | instance.should.have.property('propB', '2'); 143 | instance.should.have.property('propC', '3'); 144 | }); 145 | }); 146 | }); -------------------------------------------------------------------------------- /dist/util/decorate-directive.spec.js: -------------------------------------------------------------------------------- 1 | /*global describe,it,beforeEach */ 2 | 'use strict'; 3 | 4 | var _slicedToArray = (function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i['return']) _i['return'](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError('Invalid attempt to destructure non-iterable instance'); } }; })(); 5 | 6 | var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; 7 | 8 | var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); 9 | 10 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 11 | 12 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 13 | 14 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 15 | 16 | var _decorateDirective = require('./decorate-directive'); 17 | 18 | var _decorateDirective2 = _interopRequireDefault(_decorateDirective); 19 | 20 | var _module2 = require('../module'); 21 | 22 | var _module3 = _interopRequireDefault(_module2); 23 | 24 | var _writers = require('../writers'); 25 | 26 | var _testsFrameworks = require('../tests/frameworks'); 27 | 28 | describe('Directive Decorator', function () { 29 | var Example = function Example() { 30 | _classCallCheck(this, Example); 31 | }; 32 | 33 | it('should let you bind attributes to the controller using a simple map', function () { 34 | (0, _decorateDirective2['default'])({ bind: { 35 | 'someProp': '@' 36 | } }, Example); 37 | 38 | _writers.componentWriter.get('scope', Example).should.eql({ someProp: '@' }); 39 | _writers.componentWriter.get('bindToController', Example).should.be.ok; 40 | }); 41 | 42 | it('should manually let you configure the scope', function () { 43 | (0, _decorateDirective2['default'])({ 44 | scope: true 45 | }, Example); 46 | 47 | _writers.componentWriter.get('scope', Example).should.be.ok; 48 | }); 49 | 50 | it('should let you bind attributes to the controller using a properties array like Angular 2', function () { 51 | (0, _decorateDirective2['default'])({ 52 | properties: ['someProp: @', 'anotherProp: ='] 53 | }, Example); 54 | 55 | _writers.componentWriter.get('bindToController', Example).should.eql({ 56 | 'someProp': '@', 57 | 'anotherProp': '=' 58 | }); 59 | }); 60 | 61 | it('should throw an error if you do not pass an array to the properties field', function () { 62 | var dec = function dec(val) { 63 | return function () { 64 | return (0, _decorateDirective2['default'])({ 65 | properties: val 66 | }, Example); 67 | }; 68 | }; 69 | 70 | dec('string').should['throw'](TypeError); 71 | dec({}).should['throw'](TypeError); 72 | dec(false).should['throw'](TypeError); 73 | dec(null).should['throw'](TypeError); 74 | dec(undefined).should.not['throw'](TypeError); 75 | }); 76 | 77 | it('should set the controllerAs field if provided', function () { 78 | (0, _decorateDirective2['default'])({ controllerAs: 'hi' }, Example); 79 | 80 | _writers.componentWriter.get('controllerAs', Example).should.eql('hi'); 81 | }); 82 | 83 | afterEach(function () { 84 | _writers.componentWriter.clear(Example); 85 | }); 86 | 87 | describe('Directive Parser', function () { 88 | var parser = undefined, 89 | ngModule = undefined; 90 | 91 | beforeEach(function () { 92 | parser = _module3['default'].getParser('directive'); 93 | ngModule = { directive: _testsFrameworks.sinon.spy() }; 94 | }); 95 | 96 | it('should be defined', function () { 97 | parser.should.be.defined; 98 | }); 99 | 100 | it('should correctly generate a simple DDO', function () { 101 | var Test = function Test() { 102 | _classCallCheck(this, Test); 103 | }; 104 | 105 | (0, _decorateDirective2['default'])({}, Test); 106 | 107 | parser(Test, 'testSelector', [], ngModule); 108 | 109 | var _ngModule$directive$args$0 = _slicedToArray(ngModule.directive.args[0], 2); 110 | 111 | var name = _ngModule$directive$args$0[0]; 112 | var factory = _ngModule$directive$args$0[1]; 113 | 114 | name.should.eql('testSelector'); 115 | (typeof factory).should.eql('function'); 116 | factory().should.eql({ 117 | controller: [Test] 118 | }); 119 | }); 120 | 121 | it('should generate a complex DDO', function () { 122 | var AnotherTest = (function () { 123 | function AnotherTest() { 124 | _classCallCheck(this, AnotherTest); 125 | } 126 | 127 | _createClass(AnotherTest, null, [{ 128 | key: 'link', 129 | value: function link() {} 130 | }, { 131 | key: 'compile', 132 | value: function compile() {} 133 | }]); 134 | 135 | return AnotherTest; 136 | })(); 137 | 138 | (0, _decorateDirective2['default'])({ 139 | scope: true, 140 | properties: ['attr: @', 'prop : ='], 141 | controllerAs: 'asdf' 142 | }, AnotherTest); 143 | 144 | parser(AnotherTest, 'testSelector', ['$q', '$timeout'], ngModule); 145 | 146 | var _ngModule$directive$args$02 = _slicedToArray(ngModule.directive.args[0], 2); 147 | 148 | var name = _ngModule$directive$args$02[0]; 149 | var factory = _ngModule$directive$args$02[1]; 150 | 151 | factory().should.eql({ 152 | scope: true, 153 | bindToController: { 154 | attr: '@', 155 | prop: '=' 156 | }, 157 | controllerAs: 'asdf', 158 | controller: ['$q', '$timeout', AnotherTest], 159 | link: AnotherTest.link, 160 | compile: AnotherTest.compile 161 | }); 162 | }); 163 | 164 | it('should respect properties inheritance during parsing', function () { 165 | var Parent = function Parent() { 166 | _classCallCheck(this, Parent); 167 | }; 168 | 169 | (0, _decorateDirective2['default'])({ 170 | properties: ['=first', '@second'], 171 | scope: { 172 | first: '=', 173 | second: '&another' 174 | } 175 | }, Parent); 176 | 177 | var Child = (function (_Parent) { 178 | _inherits(Child, _Parent); 179 | 180 | function Child() { 181 | _classCallCheck(this, Child); 182 | 183 | _get(Object.getPrototypeOf(Child.prototype), 'constructor', this).apply(this, arguments); 184 | } 185 | 186 | return Child; 187 | })(Parent); 188 | 189 | (0, _decorateDirective2['default'])({ 190 | properties: ['&second', '&third', 'fourth: =*renamed'], 191 | scope: { 192 | second: '=primary', 193 | third: '@' 194 | } 195 | }, Child); 196 | 197 | parser(Child, 'childSelector', [], ngModule); 198 | 199 | var _ngModule$directive$args$03 = _slicedToArray(ngModule.directive.args[0], 2); 200 | 201 | var name = _ngModule$directive$args$03[0]; 202 | var factory = _ngModule$directive$args$03[1]; 203 | 204 | factory().should.eql({ 205 | bindToController: { 206 | first: '=', 207 | second: '&', 208 | third: '&', 209 | fourth: '=*renamed' 210 | }, 211 | scope: { 212 | first: '=', 213 | second: '=primary', 214 | third: '@' 215 | }, 216 | controller: [Child] 217 | }); 218 | }); 219 | }); 220 | }); -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # angular-decorators [![Build Status](https://travis-ci.org/MikeRyan52/angular-decorators.svg?branch=master)](https://travis-ci.org/MikeRyan52/angular-decorators) 2 | 3 | angular-decorators is a library of ES7 decorators for writing Angular 2 style code in AngularJS. 4 | 5 | **Notice:** While angular-decorators is stable and ready for production, it will not be receiving new feature development. In the future, this project will be deprecated in favor of the community fork of angular-decorators called [ng-forward](https://www.github.com/ngUpgraders/ng-forward). For more information on the ng-forward project, checkout [this talk by Pete Bacon Darwin](https://www.youtube.com/watch?v=uXvNDcnLnwU). 6 | 7 | **Installation via npm** 8 | 9 | `npm install angular-decorators --save` 10 | 11 | **Installation via jspm** 12 | 13 | `jspm install angular-decorators` 14 | 15 | _[Looking for the 0.1x docs?](https://github.com/MikeRyan52/angular-decorators/blob/v0.1.x/README.md)_ 16 | 17 | ## Modules 18 | 19 | The standard `angular.module` does not understand the metadata attached to your classes from this library's decorators. Use the provided Module function to create decorator-friendly Angular modules: 20 | 21 | ```js 22 | import {Module} from 'angular-decorators'; 23 | 24 | // Create a new module: 25 | let myModule = Module('my-module', ['ui.bootrap', 'ui.router']); 26 | 27 | // Reference a pre-existing module: 28 | let otherModule = Module('my-module'); 29 | ``` 30 | 31 | All decorated classes are added to the module using `add`: 32 | 33 | ```js 34 | import {Service, Module} from 'angular-decorators'; 35 | 36 | @Service('MyService') 37 | class MyService{ } 38 | 39 | Module('my-module', []).add(MyService); 40 | ``` 41 | 42 | If you need the raw `angular.module`, use the `publish` function: 43 | 44 | ```js 45 | let angularModule = myModule.add(AnnotatedClass).publish(); 46 | ``` 47 | 48 | Modules alias `config` and `run` blocks to the internal `angular-module`: 49 | 50 | ```js 51 | Module('example', []).config(...).run(...); 52 | ``` 53 | 54 | ### Module Dependencies 55 | 56 | You do not need to publish a module to add it as a dependency to another module: 57 | 58 | ```js 59 | let myModule = Module('my-module', []); 60 | let otherModule = Module('other-module', [ myModule ]); 61 | ``` 62 | 63 | This works for vanilla AngularJS modules as well: 64 | ```js 65 | let otherModule = angular.module('other-module', []); 66 | let myModule = Module('my-module', [ otherModule ]); 67 | let lastModule = angular.module('last-module', [ myModule.name ]); 68 | ``` 69 | 70 | ## Decorators 71 | 72 | The decorators provided in this package follow [this proposal](https://github.com/jonathandturner/brainstorming/blob/master/README.md). They work by adding metadata to your classes under the `$ng-decs` namespace using the [reflect-metadata polyfill](https://github.com/rbuckton/ReflectDecorators). 73 | 74 | ### Inject 75 | 76 | The `@Inject` decorator lets you specify dependencies: 77 | 78 | ```js 79 | @Inject('$q', '$http') 80 | class MyService{ 81 | constructor($q, $http){ 82 | 83 | } 84 | } 85 | ``` 86 | 87 | When inheriting from a decorated class, child dependencies are specified before parent dependencies letting you capture parent dependencies using a rest parameter: 88 | 89 | ```js 90 | @Inject('$q', '$http') 91 | class Parent{ 92 | constructor($q, $http){ 93 | 94 | } 95 | } 96 | 97 | @Inject('$timeout') 98 | class Child extends Parent{ 99 | constructor($timeout, ...parentDependencies){ 100 | super(...parentDependencies); 101 | } 102 | } 103 | ``` 104 | 105 | ### Component 106 | 107 | The `@Component` decorator lets you create components in AngularJS by wrapping the directive API and setting you up with sensible defaults: 108 | 109 | ```js 110 | import {Component, Inject, Module} from 'angular-decorators'; 111 | 112 | @Component({ selector : 'my-component' }) 113 | @Inject('$q') 114 | class MyComponentCtrl{ 115 | constructor($q){ ... } 116 | } 117 | 118 | export default Module('my-component-module', []).add(MyComponentCtrl); 119 | ``` 120 | 121 | The directive definition object generated for the above component is: 122 | 123 | ```js 124 | { 125 | controller: ['$q', MyComponentCtrl], 126 | controllerAs: 'myComponent', 127 | bindToController: true, 128 | scope: {}, 129 | restrict: 'E' 130 | } 131 | ``` 132 | 133 | ##### Binding Element Attributes to the Controller 134 | 135 | Supply an array of properties key of your config object using Angular 2 property syntax: 136 | 137 | ```js 138 | @Component({ 139 | selector: 'my-component', 140 | properties: [ 141 | 'myProp: =renamedProp', 142 | '@anotherAttribute' 143 | ] 144 | }) 145 | class MyComponentCtrl 146 | ``` 147 | 148 | This becomes: 149 | 150 | ```js 151 | .directive('myComponent', function(){ 152 | return { 153 | restrict: 'E', 154 | controller: function MyComponentCtrl{ }, 155 | controllerAs: 'myComponent', 156 | scope: {}, 157 | bindToController: { 158 | 'myProp' : '=renamedProp', 159 | 'anotherAttribute' : '@' 160 | } 161 | } 162 | }) 163 | ``` 164 | 165 | For information on attribute binding, view the [AngularJS docs on scopes](https://docs.angularjs.org/api/ng/service/$compile#-scope-). 166 | 167 | **Note**: the above uses the new `bindToController` syntax introduced in AngularJS 1.4. For AngularJS 1.3, use `bind` in your `@Component` config instead of `properties`: 168 | 169 | ```js 170 | import {Component} from 'angular-decorators'; 171 | 172 | @Component({ 173 | selector: 'my-component', 174 | bind: { 175 | myProp: '=renamedProp', 176 | anotherAttribute: '@' 177 | } 178 | }) 179 | class MyComponentCtrl{ ... } 180 | ``` 181 | 182 | ##### Renaming `controllerAs` 183 | 184 | By default, the `controllerAs` property is a camelCased version of your selector (i.e. `my-own-component`'s `controllerAs` would be `myOwnComponent`'). You can override this by specifying a new name in the `@Component` config object: 185 | 186 | ```js 187 | @Component({ 188 | selector: 'my-component', 189 | controllerAs: 'vm' 190 | }) 191 | ``` 192 | 193 | ##### Changing Scope 194 | By default, components create new, isolate scopes but this can be manually set in the component config object: 195 | 196 | ```js 197 | @Component({ 198 | selector: 'my-component', 199 | scope: false 200 | }) 201 | ``` 202 | 203 | ##### Setting the Template 204 | Templates are added with the `@View` decorator. Pass in a config object with either an inline `template` or a `templateUrl`: 205 | 206 | ```js 207 | import {Component, View} from 'angular-decorators'; 208 | 209 | @Component({ selector: 'my-component' }) 210 | @View({ template: `

My Component Template

` }) 211 | class MyComponentCtrl{ ... } 212 | 213 | @Component({ selector: 'another-component' }) 214 | @View({ templateUrl: '/path/to/template.html' }) 215 | class AnotherComponentCtrl{ ... } 216 | ``` 217 | 218 | ##### Requiring Other Directives 219 | Use the `@Require` decorator to require directive controllers and access them using the static link function: 220 | 221 | ```js 222 | import {Component, Require} from 'angular-decorators'; 223 | 224 | @Component({ selector : 'my-component' }) 225 | @Require('^parent', 'myComponent') 226 | class MyComponent{ 227 | static link(scope, element, attrs, controllers){ 228 | let [parent, self] = controllers; 229 | 230 | self.parent = parent; 231 | } 232 | } 233 | ``` 234 | 235 | #### Transclusion 236 | Use the `@Transclude` decorator to setup transclusion for your component: 237 | 238 | ```js 239 | import {Component, Transclude} from 'angular-decorators'; 240 | 241 | @Component({ selector: 'my-component' }) 242 | @Transclude 243 | class MyComponent{ ... } 244 | ``` 245 | 246 | ### Directive 247 | Unlike `@Component`, `@Directive` does not create a new isolate scope by default nor does it expose your directive's controller on the scope. It can only be used for directives that you want to restrict to a class name or attribute: 248 | 249 | ```js 250 | import {Directive} from 'angular-decorators'; 251 | 252 | @Directive({ selector: '[my-attr]' }) 253 | class MyAttrCtrl{ 254 | constructor(){ 255 | 256 | } 257 | } 258 | 259 | @Directive({ selector: '.my-class' }) 260 | class MyClassCtrl{ 261 | constructor(){ 262 | 263 | } 264 | } 265 | ``` 266 | 267 | ### Filter 268 | The `@Filter` decorator lets you write class-based filters similar to Angular 2's Pipes: 269 | 270 | ```js 271 | import {Filter, Module} from 'angular-decorators'; 272 | 273 | @Filter('trim') 274 | class TrimFilter{ 275 | // Implementing a supports function is encouraged but optional 276 | supports(input){ 277 | return (typeof input === 'string'); 278 | } 279 | transform(input, param){ 280 | return input.trim(); 281 | } 282 | } 283 | 284 | export default Module('trim-filter', []).add(TrimFilter); 285 | ``` 286 | 287 | The `supports` function is an optional test against the input. If the `supports` function returns false the generated filter will throw an error instead of applying the transform. 288 | 289 | ### Service 290 | The `@Service` decorator turns your class into a service: 291 | 292 | ```js 293 | import {Service, Inject, Module} from 'angular-decorators'; 294 | 295 | @Service('MyService') 296 | @Inject('$q') 297 | class MyService{ 298 | constructor($q){ 299 | this.$q = $q; 300 | } 301 | } 302 | 303 | export default Module('my-service', []).add(MyService); 304 | ``` 305 | 306 | ### Factory 307 | The `@Factory` decorator is a complex decorator that assumes you have a class that requires more parameters on instantiation than what will be provided by AngularJS's injector. For example, if you had a class that looked like this: 308 | 309 | ```js 310 | @Inject('$http') 311 | class Post{ 312 | constructor($http, title, content){ 313 | 314 | } 315 | } 316 | ``` 317 | 318 | and you wanted to make a factory that created a new `Post` with a parameters for title and content, you would use `@Factory`: 319 | 320 | ```js 321 | import {Factory, Inject, Module} from 'angular-decorators'; 322 | 323 | @Factory('PostFactory') 324 | @Inject('$http') 325 | class Post{ 326 | constructor($http, title, content){ 327 | 328 | } 329 | } 330 | 331 | export default Module('post-factory', []).add(Post); 332 | ``` 333 | 334 | When injected elsewhere use the factory like this: 335 | 336 | ```js 337 | import {Inject, Service, Module} from 'angular-decorators'; 338 | import PostFactory from './post-factory'; 339 | 340 | @Service('SomeService') 341 | @Inject('PostFactory') 342 | class SomeService{ 343 | constructor(PostFactory){ 344 | let post = PostFactory('Title', 'Some content'); 345 | } 346 | } 347 | 348 | export default Module('some-service', [PostFactory]).add(SomeService); 349 | ``` 350 | 351 | You can override the default factory function by implementing a static create function: 352 | 353 | ```js 354 | import {Factory, Inject, Module} from 'angular-decorators'; 355 | 356 | @Factory('CommentFactory') 357 | @Inject('$http', '$q') 358 | class Comment{ 359 | constructor($http, $q, postID, comment){ 360 | 361 | } 362 | 363 | static create(dependencies, post, comment){ 364 | return new Comment(...dependencies, post.id, comment); 365 | } 366 | } 367 | 368 | export default Module('comment-factory', []).add(Comment); 369 | ``` 370 | 371 | ### Providers 372 | Create raw providers using the `@Provider` decorator. For easily injecting dependencies to the `$get` function, enable ES7 property initializers in your compiler: 373 | 374 | ```js 375 | import {Provider, Module} from 'angular-decorators'; 376 | 377 | @Provider('SomeService') 378 | class SomeServiceProvider{ 379 | constructor(){ 380 | this.greeting = 'hello'; 381 | } 382 | 383 | setGreeting(newGreeting){ 384 | this.greeting = newGreeting; 385 | } 386 | 387 | $get = ['$timeout', $timeout => name => $timeout(() => console.log(`${this.greeting} ${name}`))]; 388 | } 389 | 390 | export default Module('some-service-provider', []).add(SomeServiceProvider); 391 | ``` 392 | 393 | ### Animation 394 | Create animations using the `@Animation` decorator. Requires `ngAnimate` to be included in your module: 395 | 396 | ```js 397 | import {Animation, Inject, Module} from 'angular-decorators'; 398 | import ngAnimate from 'angular-animate'; 399 | 400 | @Animation('.animation-class') 401 | @Inject('$q') 402 | class MyAnimation{ 403 | constructor($q){ 404 | this.$q = $q; 405 | } 406 | enter(element){ 407 | return this.$q((resolve, reject) => { ... }); 408 | } 409 | } 410 | 411 | export default Module('my-animation', [ngAnimate]).add(MyAnimation); 412 | ``` 413 | 414 | 415 | ## Extending angular-decorators 416 | #### Adding Your Own Providers 417 | You can register your own providers using `Module.addProvider`. For instance, if you want to add a new decorator called `@RouteableComponent` that hooked up a component to the upcoming router, you would start by creating a decorator that set a provider name and type on a class: 418 | 419 | ```js 420 | import {providerWriter} from 'angular-decorators/writers'; 421 | 422 | export default const RouteableComponent = name => targetClass => { 423 | providerWriter.set('type', 'routeable-component', targetClass); 424 | providerWriter.set('name', name, targetClass); 425 | } 426 | ``` 427 | 428 | Then you'll need to register your custom parser: 429 | 430 | ```js 431 | import Module from 'angular-decorators/module'; 432 | 433 | Module.addProvider('routeable-component', (provider, name, injectables, ngModule) => { 434 | // implement parsing logic here, adding necessary config/directives/etc to the raw ngModule 435 | }); 436 | ``` 437 | 438 | Your parser will be called each time a provider is added to a `Module` that has the provider type you've specified. 439 | 440 | #### Extending the Directive Parser 441 | The directive definiton object is derived from all key/value pairs set with the `componentWriter`. Here is an example of creating a priority decorator that sets a directive's priority: 442 | 443 | ```js 444 | import {componentWriter} from 'angular-decorators/writers'; 445 | 446 | export const Priority = level => target => componentWriter.set('priority', level, target); 447 | ``` 448 | 449 | No other configuration is required. Simply using `@Priority` in tandem with `@Component` or `@Directive` will work. 450 | -------------------------------------------------------------------------------- /dist/angular-decorators.js: -------------------------------------------------------------------------------- 1 | (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.angularDecorators = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { 480 | params[_key - 1] = arguments[_key]; 481 | } 482 | 483 | return new (_bind.apply(provider, [null].concat(_toConsumableArray(dependencies), params)))(); 484 | }; 485 | 486 | function factory() { 487 | for (var _len2 = arguments.length, dependencies = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { 488 | dependencies[_key2] = arguments[_key2]; 489 | } 490 | 491 | return function () { 492 | for (var _len3 = arguments.length, params = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { 493 | params[_key3] = arguments[_key3]; 494 | } 495 | 496 | return create.apply(undefined, [dependencies].concat(params)); 497 | }; 498 | } 499 | 500 | ngModule.factory(name, [].concat(_toConsumableArray(injects), [factory])); 501 | }); 502 | 503 | },{"../../module":16,"../../util/decorator-factory":18}],12:[function(_dereq_,module,exports){ 504 | 'use strict'; 505 | 506 | Object.defineProperty(exports, '__esModule', { 507 | value: true 508 | }); 509 | var _bind = Function.prototype.bind; 510 | 511 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 512 | 513 | function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; return arr2; } else { return Array.from(arr); } } 514 | 515 | var _module2 = _dereq_('../../module'); 516 | 517 | var _module3 = _interopRequireDefault(_module2); 518 | 519 | var _utilDecoratorFactory = _dereq_('../../util/decorator-factory'); 520 | 521 | var _utilDecoratorFactory2 = _interopRequireDefault(_utilDecoratorFactory); 522 | 523 | var TYPE = 'filter'; 524 | 525 | var Filter = (0, _utilDecoratorFactory2['default'])(TYPE); 526 | 527 | exports.Filter = Filter; 528 | _module3['default'].addProvider(TYPE, function (provider, name, injects, ngModule) { 529 | ngModule.filter(name, [].concat(_toConsumableArray(injects), [function () { 530 | for (var _len = arguments.length, dependencies = Array(_len), _key = 0; _key < _len; _key++) { 531 | dependencies[_key] = arguments[_key]; 532 | } 533 | 534 | var filter = new (_bind.apply(provider, [null].concat(dependencies)))(); 535 | 536 | if (!filter.transform) { 537 | throw new Error('Filters must implement a transform method'); 538 | } 539 | 540 | return function (input) { 541 | for (var _len2 = arguments.length, params = Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { 542 | params[_key2 - 1] = arguments[_key2]; 543 | } 544 | 545 | if (filter.supports && !filter.supports(input)) { 546 | throw new Error('Filter ' + name + ' does not support ' + input); 547 | } 548 | 549 | return filter.transform.apply(filter, [input].concat(params)); 550 | }; 551 | }])); 552 | }); 553 | 554 | },{"../../module":16,"../../util/decorator-factory":18}],13:[function(_dereq_,module,exports){ 555 | 'use strict'; 556 | 557 | Object.defineProperty(exports, '__esModule', { 558 | value: true 559 | }); 560 | 561 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 562 | 563 | function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; return arr2; } else { return Array.from(arr); } } 564 | 565 | var _module2 = _dereq_('../../module'); 566 | 567 | var _module3 = _interopRequireDefault(_module2); 568 | 569 | var _utilDecoratorFactory = _dereq_('../../util/decorator-factory'); 570 | 571 | var _utilDecoratorFactory2 = _interopRequireDefault(_utilDecoratorFactory); 572 | 573 | var TYPE = 'provider'; 574 | 575 | var Provider = (0, _utilDecoratorFactory2['default'])(TYPE); 576 | 577 | exports.Provider = Provider; 578 | _module3['default'].addProvider(TYPE, function (provider, name, injects, ngModule) { 579 | ngModule.provider(name, [].concat(_toConsumableArray(injects), [provider])); 580 | }); 581 | 582 | },{"../../module":16,"../../util/decorator-factory":18}],14:[function(_dereq_,module,exports){ 583 | 'use strict'; 584 | 585 | Object.defineProperty(exports, '__esModule', { 586 | value: true 587 | }); 588 | 589 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 590 | 591 | function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; return arr2; } else { return Array.from(arr); } } 592 | 593 | var _module2 = _dereq_('../../module'); 594 | 595 | var _module3 = _interopRequireDefault(_module2); 596 | 597 | var _utilDecoratorFactory = _dereq_('../../util/decorator-factory'); 598 | 599 | var _utilDecoratorFactory2 = _interopRequireDefault(_utilDecoratorFactory); 600 | 601 | var TYPE = 'service'; 602 | 603 | var Service = (0, _utilDecoratorFactory2['default'])(TYPE); 604 | 605 | exports.Service = Service; 606 | _module3['default'].addProvider(TYPE, function (provider, name, injects, ngModule) { 607 | ngModule.service(name, [].concat(_toConsumableArray(injects), [provider])); 608 | }); 609 | 610 | },{"../../module":16,"../../util/decorator-factory":18}],15:[function(_dereq_,module,exports){ 611 | 'use strict'; 612 | 613 | Object.defineProperty(exports, '__esModule', { 614 | value: true 615 | }); 616 | 617 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 618 | 619 | var _module2 = _dereq_('./module'); 620 | 621 | var _module3 = _interopRequireDefault(_module2); 622 | 623 | var _decoratorsInject = _dereq_('./decorators/inject'); 624 | 625 | var _decoratorsProvidersAnimation = _dereq_('./decorators/providers/animation'); 626 | 627 | var _decoratorsProvidersComponent = _dereq_('./decorators/providers/component'); 628 | 629 | var _decoratorsProvidersController = _dereq_('./decorators/providers/controller'); 630 | 631 | var _decoratorsProvidersDirective = _dereq_('./decorators/providers/directive'); 632 | 633 | var _decoratorsProvidersFactory = _dereq_('./decorators/providers/factory'); 634 | 635 | var _decoratorsProvidersFilter = _dereq_('./decorators/providers/filter'); 636 | 637 | var _decoratorsProvidersProvider = _dereq_('./decorators/providers/provider'); 638 | 639 | var _decoratorsProvidersService = _dereq_('./decorators/providers/service'); 640 | 641 | var _decoratorsComponentRequire = _dereq_('./decorators/component/require'); 642 | 643 | var _decoratorsComponentView = _dereq_('./decorators/component/view'); 644 | 645 | var _decoratorsComponentTransclude = _dereq_('./decorators/component/transclude'); 646 | 647 | exports.Module = _module3['default']; 648 | exports.Inject = _decoratorsInject.Inject; 649 | exports.Component = _decoratorsProvidersComponent.Component; 650 | exports.Controller = _decoratorsProvidersController.Controller; 651 | exports.Directive = _decoratorsProvidersDirective.Directive; 652 | exports.Filter = _decoratorsProvidersFilter.Filter; 653 | exports.Provider = _decoratorsProvidersProvider.Provider; 654 | exports.Factory = _decoratorsProvidersFactory.Factory; 655 | exports.Service = _decoratorsProvidersService.Service; 656 | exports.Animation = _decoratorsProvidersAnimation.Animation; 657 | exports.Require = _decoratorsComponentRequire.Require; 658 | exports.View = _decoratorsComponentView.View; 659 | exports.Transclude = _decoratorsComponentTransclude.Transclude; 660 | 661 | },{"./decorators/component/require":3,"./decorators/component/transclude":4,"./decorators/component/view":5,"./decorators/inject":6,"./decorators/providers/animation":7,"./decorators/providers/component":8,"./decorators/providers/controller":9,"./decorators/providers/directive":10,"./decorators/providers/factory":11,"./decorators/providers/filter":12,"./decorators/providers/provider":13,"./decorators/providers/service":14,"./module":16}],16:[function(_dereq_,module,exports){ 662 | 'use strict'; 663 | 664 | Object.defineProperty(exports, '__esModule', { 665 | value: true 666 | }); 667 | var _bind = Function.prototype.bind; 668 | 669 | var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); 670 | 671 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 672 | 673 | var _writers = _dereq_('./writers'); 674 | 675 | var _parsers = {}; 676 | 677 | var DecoratedModule = (function () { 678 | function DecoratedModule(name) { 679 | var modules = arguments.length <= 1 || arguments[1] === undefined ? false : arguments[1]; 680 | 681 | _classCallCheck(this, DecoratedModule); 682 | 683 | this.name = name; 684 | this.moduleList(modules); 685 | 686 | if (modules) { 687 | this._module = angular.module(name, this._dependencies); 688 | } else { 689 | this._module = angular.module(name); 690 | } 691 | } 692 | 693 | _createClass(DecoratedModule, [{ 694 | key: 'add', 695 | value: function add() { 696 | var _iteratorNormalCompletion = true; 697 | var _didIteratorError = false; 698 | var _iteratorError = undefined; 699 | 700 | try { 701 | for (var _len = arguments.length, providers = Array(_len), _key = 0; _key < _len; _key++) { 702 | providers[_key] = arguments[_key]; 703 | } 704 | 705 | for (var _iterator = providers[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { 706 | var provider = _step.value; 707 | 708 | if (!_writers.providerWriter.has('type', provider)) { 709 | throw new Error('Cannot read provider metadata. Are you adding a class that hasn\'t been decorated yet?'); 710 | } 711 | 712 | var type = _writers.providerWriter.get('type', provider); 713 | var _name = _writers.providerWriter.get('name', provider); 714 | var inject = _writers.baseWriter.get('$inject', provider) || []; 715 | 716 | if (_parsers[type]) { 717 | _parsers[type](provider, _name, inject, this._module); 718 | } else { 719 | throw new Error('No parser registered for type \'' + type + '\''); 720 | } 721 | } 722 | } catch (err) { 723 | _didIteratorError = true; 724 | _iteratorError = err; 725 | } finally { 726 | try { 727 | if (!_iteratorNormalCompletion && _iterator['return']) { 728 | _iterator['return'](); 729 | } 730 | } finally { 731 | if (_didIteratorError) { 732 | throw _iteratorError; 733 | } 734 | } 735 | } 736 | 737 | return this; 738 | } 739 | }, { 740 | key: 'publish', 741 | value: function publish() { 742 | return this._module; 743 | } 744 | }, { 745 | key: 'moduleList', 746 | value: function moduleList(modules) { 747 | this._dependencies = []; 748 | 749 | if (modules && modules.length !== 0) { 750 | for (var i = 0; i < modules.length; i++) { 751 | if (modules[i] && modules[i].name) { 752 | this._dependencies.push(modules[i].name); 753 | } else if (typeof modules[i] === 'string') { 754 | this._dependencies.push(modules[i]); 755 | } else { 756 | throw new Error('Cannot read module: Unknown module in ' + this.name); 757 | } 758 | } 759 | } 760 | } 761 | }, { 762 | key: 'config', 763 | value: function config(configFunc) { 764 | this._module.config(configFunc); 765 | 766 | return this; 767 | } 768 | }, { 769 | key: 'run', 770 | value: function run(runFunc) { 771 | this._module.run(runFunc); 772 | 773 | return this; 774 | } 775 | }, { 776 | key: 'value', 777 | value: function value() { 778 | var _module2; 779 | 780 | (_module2 = this._module).value.apply(_module2, arguments); 781 | 782 | return this; 783 | } 784 | }, { 785 | key: 'constant', 786 | value: function constant() { 787 | var _module3; 788 | 789 | (_module3 = this._module).constant.apply(_module3, arguments); 790 | 791 | return this; 792 | } 793 | }]); 794 | 795 | return DecoratedModule; 796 | })(); 797 | 798 | function Module() { 799 | for (var _len2 = arguments.length, params = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { 800 | params[_key2] = arguments[_key2]; 801 | } 802 | 803 | return new (_bind.apply(DecoratedModule, [null].concat(params)))(); 804 | } 805 | 806 | Module.addProvider = function (providerType, parser) { 807 | _parsers[providerType] = parser; 808 | }; 809 | 810 | Module.getParser = function (providerType) { 811 | return _parsers[providerType]; 812 | }; 813 | 814 | exports['default'] = Module; 815 | module.exports = exports['default']; 816 | 817 | },{"./writers":21}],17:[function(_dereq_,module,exports){ 818 | 'use strict'; 819 | 820 | Object.defineProperty(exports, '__esModule', { 821 | value: true 822 | }); 823 | 824 | var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; 825 | 826 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 827 | 828 | function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; return arr2; } else { return Array.from(arr); } } 829 | 830 | var _module2 = _dereq_('../module'); 831 | 832 | var _module3 = _interopRequireDefault(_module2); 833 | 834 | var _writers = _dereq_('../writers'); 835 | 836 | var _parseProperties = _dereq_('./parse-properties'); 837 | 838 | var _parseProperties2 = _interopRequireDefault(_parseProperties); 839 | 840 | exports['default'] = function (config, t) { 841 | // Support for legacy angular-decorators bind config 842 | if (config.bind) { 843 | _writers.componentWriter.set('scope', config.bind, t); 844 | _writers.componentWriter.set('bindToController', true, t); 845 | } 846 | 847 | // Check for scope 848 | if (config.scope) { 849 | var scope = _writers.componentWriter.get('scope', t); 850 | 851 | if (scope && typeof scope === 'object') { 852 | _writers.componentWriter.set('scope', _extends({}, scope, config.scope), t); 853 | } else { 854 | _writers.componentWriter.set('scope', config.scope, t); 855 | } 856 | } 857 | 858 | // Check for Angular 2 style properties 859 | if (config.properties && Array.isArray(config.properties)) { 860 | var binders = (0, _parseProperties2['default'])(config.properties); 861 | var previous = _writers.componentWriter.get('bindToController', t); 862 | 863 | if (previous && typeof previous === 'object') { 864 | _writers.componentWriter.set('bindToController', _extends({}, previous, binders), t); 865 | } else { 866 | _writers.componentWriter.set('bindToController', (0, _parseProperties2['default'])(config.properties), t); 867 | } 868 | } else if (config.properties !== undefined) { 869 | throw new TypeError('Component properties must be an array'); 870 | } 871 | 872 | // Allow for renaming the controllerAs 873 | if (config.controllerAs) { 874 | _writers.componentWriter.set('controllerAs', config.controllerAs, t); 875 | } 876 | 877 | // Set a link function 878 | if (t.link) { 879 | _writers.componentWriter.set('link', t.link, t); 880 | } 881 | 882 | // Set a controller function 883 | if (t.compile) { 884 | _writers.componentWriter.set('compile', t.compile, t); 885 | } 886 | }; 887 | 888 | _module3['default'].addProvider('directive', function (target, name, injects, ngModule) { 889 | var ddo = {}; 890 | 891 | _writers.componentWriter.forEach(function (val, key) { 892 | ddo[key] = val; 893 | }, target); 894 | 895 | ddo.controller = [].concat(_toConsumableArray(injects), [target]); 896 | 897 | ngModule.directive(name, function () { 898 | return ddo; 899 | }); 900 | }); 901 | module.exports = exports['default']; 902 | 903 | },{"../module":16,"../writers":21,"./parse-properties":19}],18:[function(_dereq_,module,exports){ 904 | 'use strict'; 905 | 906 | Object.defineProperty(exports, '__esModule', { 907 | value: true 908 | }); 909 | 910 | var _writers = _dereq_('../writers'); 911 | 912 | exports['default'] = function (type) { 913 | return function (maybeT) { 914 | if (typeof maybeT === 'string') { 915 | return function (t) { 916 | _writers.providerWriter.set('type', type, t); 917 | _writers.providerWriter.set('name', maybeT, t); 918 | }; 919 | } else { 920 | _writers.providerWriter.set('type', type, maybeT); 921 | _writers.providerWriter.set('name', maybeT.name, maybeT); 922 | } 923 | }; 924 | }; 925 | 926 | module.exports = exports['default']; 927 | 928 | },{"../writers":21}],19:[function(_dereq_,module,exports){ 929 | 'use strict'; 930 | 931 | Object.defineProperty(exports, '__esModule', { 932 | value: true 933 | }); 934 | var ALLOWED_SYMBOLS = ['&', '=', '@', '=', '*', '?']; 935 | 936 | function checkBindingType(str) { 937 | return ALLOWED_SYMBOLS.indexOf(str.charAt(0)) !== -1; 938 | } 939 | 940 | function parseProperty(str) { 941 | var symbols = []; 942 | 943 | function getName(_x) { 944 | var _again = true; 945 | 946 | _function: while (_again) { 947 | var input = _x; 948 | _again = false; 949 | 950 | if (checkBindingType(input.join(''))) { 951 | symbols.push(input.shift()); 952 | _x = input; 953 | _again = true; 954 | continue _function; 955 | } 956 | 957 | return input; 958 | } 959 | } 960 | 961 | var name = getName(str.split('')); 962 | 963 | return { name: name.join(''), symbols: symbols.join('') }; 964 | } 965 | 966 | exports['default'] = function (props) { 967 | var map = {}; 968 | 969 | for (var i = 0; i < props.length; i++) { 970 | var split = props[i].split(':'); 971 | 972 | for (var y = 0; y < split.length; y++) { 973 | split[y] = split[y].trim(); 974 | } 975 | 976 | if (split.length === 1 && checkBindingType(split[0])) { 977 | var _parseProperty = parseProperty(split[0]); 978 | 979 | var _name = _parseProperty.name; 980 | var symbols = _parseProperty.symbols; 981 | 982 | map[_name] = symbols; 983 | } else if (split.length === 2 && checkBindingType(split[1])) { 984 | map[split[0]] = split[1]; 985 | } else { 986 | throw new Error('Properties must be in the form of "propName: [&, @, =, =*, =?, =*?]attrName" or in the form of "[&, @, =, =*, =?, =*?]attrName"'); 987 | } 988 | } 989 | 990 | return map; 991 | }; 992 | 993 | module.exports = exports['default']; 994 | 995 | },{}],20:[function(_dereq_,module,exports){ 996 | 'use strict'; 997 | 998 | Object.defineProperty(exports, '__esModule', { 999 | value: true 1000 | }); 1001 | 1002 | function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; return arr2; } else { return Array.from(arr); } } 1003 | 1004 | exports['default'] = function (selector) { 1005 | var selectorArray = undefined; 1006 | var type = undefined; 1007 | 1008 | if (selector.match(/\[(.*?)\]/) !== null) { 1009 | selectorArray = selector.slice(1, selector.length - 1).split('-'); 1010 | type = 'A'; 1011 | } else if (selector[0] === '.') { 1012 | selectorArray = selector.slice(1, selector.length).split('-'); 1013 | type = 'C'; 1014 | } else { 1015 | selectorArray = selector.split('-'); 1016 | type = 'E'; 1017 | } 1018 | 1019 | var first = selectorArray.shift(); 1020 | var name = undefined; 1021 | 1022 | if (selectorArray.length > 0) { 1023 | for (var i = 0; i < selectorArray.length; i++) { 1024 | var s = selectorArray[i]; 1025 | s = s.slice(0, 1).toUpperCase() + s.slice(1, s.length); 1026 | selectorArray[i] = s; 1027 | } 1028 | 1029 | name = [first].concat(_toConsumableArray(selectorArray)).join(''); 1030 | } else { 1031 | name = first; 1032 | } 1033 | 1034 | return { name: name, type: type }; 1035 | }; 1036 | 1037 | module.exports = exports['default']; 1038 | 1039 | },{}],21:[function(_dereq_,module,exports){ 1040 | 'use strict'; 1041 | 1042 | Object.defineProperty(exports, '__esModule', { 1043 | value: true 1044 | }); 1045 | 1046 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 1047 | 1048 | var _metawriter = _dereq_('metawriter'); 1049 | 1050 | var _metawriter2 = _interopRequireDefault(_metawriter); 1051 | 1052 | var baseWriter = new _metawriter2['default']('$ng-decs'); 1053 | exports.baseWriter = baseWriter; 1054 | var providerWriter = new _metawriter2['default']('provider', baseWriter); 1055 | exports.providerWriter = providerWriter; 1056 | var componentWriter = new _metawriter2['default']('component', baseWriter); 1057 | exports.componentWriter = componentWriter; 1058 | 1059 | },{"metawriter":2}]},{},[15])(15) 1060 | }); --------------------------------------------------------------------------------