├── .editorconfig ├── .eslintignore ├── .eslintrc ├── .gitignore ├── .npmignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── demo ├── angular-scope-types.js ├── angular.js ├── api-check.js ├── index.html └── script.js ├── dist ├── angular-scope-types.js ├── angular-scope-types.min.js └── angular-scope-types.min.js.map ├── karma.conf.js ├── package.json ├── scripts ├── karma-overrides.js └── webpack-overrides.js └── src ├── angular-fix └── index.js ├── checkers ├── checkerUtils.js ├── ddo.js ├── ddo.test.js ├── index.js ├── index.test.js ├── injectableFunction.js └── injectableFunction.test.js ├── index.js ├── index.test.js ├── scopeTypes.js ├── scopeTypes.test.js └── test.utils.js /.editorconfig: -------------------------------------------------------------------------------- 1 | node_modules/kcd-common-tools/shared/link/editorconfig -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules/kcd-common-tools/shared/link/eslintignore -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "rules": { 4 | "quotes": [2, "single"], 5 | "no-use-before-define": [2, "nofunc"], 6 | "no-unused-expressions": 0, 7 | "strict": 0, 8 | "no-unused-vars": [2, {"args": "none"}], 9 | "new-cap": [2, { 10 | "newIsCap": true, 11 | "capIsNew": true, 12 | "capIsNewExceptions": [ 13 | "DSCreate", "DSUpdate", "DSSave", "DSDestroy", "DSRefresh", "DSChanges" 14 | ] 15 | }], 16 | "comma-dangle": 0, 17 | "max-statements": [2, 30], 18 | "max-len": [2, 120, 2], 19 | "complexity": [2, 5], 20 | "max-depth": [2, 4], 21 | "max-nested-callbacks": [2, 5], 22 | "indent": [2, 2], 23 | "brace-style": [2, "1tbs"], 24 | "spaced-line-comment": [2, "always"], 25 | "no-trailing-spaces": 0, 26 | "no-underscore-dangle": 0 27 | }, 28 | "env": { 29 | "browser": true, 30 | "es6": true, 31 | "mocha": true 32 | }, 33 | "ecmaFeatures": { 34 | "modules": true 35 | }, 36 | "globals": { 37 | "expect": false, 38 | "require": false, 39 | "module": false, 40 | "__filename": false, 41 | 42 | 43 | "ATAC_CONFIG": true, 44 | 45 | "ON_DEV": true, 46 | "ON_PROD": true, 47 | "ON_TEST": true, 48 | 49 | "inject": true, 50 | "module": true, 51 | "before": true, 52 | "beforeEach": true, 53 | "after": true, 54 | "afterEach": true, 55 | "describe": true, 56 | "it": true, 57 | "expect": true, 58 | "sinon": true 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/kcd-common-tools/shared/link/gitignore -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | node_modules/kcd-common-tools/shared/link/npmignore -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 1.0.0-beta.7 2 | 3 | ## Bug Fixes 4 | 5 | - Allowing `replace` in the `ddo` checker. 6 | 7 | # 1.0.0-beta.6 8 | 9 | ## Other 10 | 11 | - Fixing link in README.md 12 | 13 | # 1.0.0-beta.5 14 | 15 | ## Breaking Changes 16 | 17 | - Now, if a checker is not optional, the api-check for it will be evaluated immediately. 18 | 19 | ## New Features 20 | 21 | - Adding `displayName` for the wrapper controller for error messaging and debugging. 22 | - Adding `scopeTypesFunction` to the `ddo` to allow you to specify `warn` or `throw`. 23 | 24 | # 1.0.0-beta.4 25 | 26 | ## New Features 27 | 28 | - Adding ability to specify your own instance of an `apiCheck` which allows you to use your own checkers. 29 | 30 | ## Bug Fixes 31 | 32 | - Fixing the prefix for the `scopeTypes` instance of an `apiCheck` to be `angular-scope-types` rather than `api-check-angular` 33 | 34 | # 1.0.0-beta.3 35 | 36 | ## Bug Fixes 37 | 38 | - Fixing issue where a new instance of the controller was created and the properties were not bound to that instance. 39 | 40 | # 1.0.0-beta.2 41 | 42 | ## Other 43 | 44 | - Adding `.npmignore` 45 | 46 | # 1.0.0-beta.1 47 | 48 | ## Breaking changes 49 | 50 | - `scopeTypes` must be a function that accepts the api-check instance and returns the api (perf improvement) 51 | - Changing what is exported to be the `scopeTypesFactory` function. 52 | 53 | ## New Features 54 | 55 | - Adding `disabled` option. 56 | - Improved the API, adding more tests, adding example. 57 | 58 | # 1.0.0-beta.0 59 | 60 | - Initial release 61 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # angular-scope-types 2 | 3 | [![npm version](https://img.shields.io/npm/v/angular-scope-types.svg?style=flat-square)](https://www.npmjs.org/package/angular-scope-types) 4 | [![npm downloads](https://img.shields.io/npm/dm/angular-scope-types.svg?style=flat-square)](http://npm-stat.com/charts.html?package=angular-scope-types) 5 | [![Build Status](https://snap-ci.com/alianza-dev/angular-scope-types/branch/master/build_image)](https://snap-ci.com/alianza-dev/angular-scope-types/branch/master) 6 | [![Code Coverage](https://img.shields.io/codecov/c/github/alianza-dev/angular-scope-types.svg?style=flat-square)](https://codecov.io/github/alianza-dev/angular-scope-types) 7 | [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/alianza-dev/angular-scope-types?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 8 | 9 | ## [Demo](https://jsbin.com/kuqeye/edit?html,js,output) 10 | 11 | This is still in the early stages. This is currently available as a beta on `npm`. Basically this is intended 12 | to bring a concept like 13 | [React `propTypes`](https://facebook.github.io/react/docs/reusable-components.html#prop-validation) to Angular. 14 | 15 | This is based on trying to support [this issue](https://github.com/angular/angular.js/issues/11657) with as clean an api 16 | as possible. 17 | 18 | 19 | ## Usage 20 | 21 | angular-scope-types uses [api-check](https://github.com/kentcdodds/api-check) to do api checking. api-check is basically 22 | React propTypes without React. So you'll need to install `api-check` into your project and include the script first. It 23 | is available on `npm` via `npm install --save api-check` 24 | 25 | You will then create your own instance of `apiCheck` and use that to create your own instance of `angular-scope-types`. 26 | (Note, you don't have to create your own instance, but it is recommended). 27 | 28 | Both `api-check` and `angular-scope-types` are exported as UMD modules meaning you can use them with CommonJS, AMD, or 29 | as globals (`apiCheck` and `angularScopeTypes` respectively). 30 | 31 | Here's a quick example for recommended usage (uses globals): 32 | 33 | ```javascript 34 | 35 | // create your apiCheckInstance 36 | var myApiCheck = apiCheck({ 37 | output: { 38 | prefix: 'Global prefix', 39 | suffix: 'global suffix', 40 | docsBaseUrl: 'https://example.com/errors-and-warnings#' 41 | }, 42 | disabled: SOME_VARIABLE_THAT_SAYS_YOU_ARE_ON_PRODUCTION 43 | }, { 44 | /* custom checkers if you wanna */ 45 | }); 46 | 47 | 48 | // create your angularScopeTypesInstance 49 | var myScopeTypes = angularScopeTypes({ 50 | disabled: SOME_VARIABLE_THAT_SAYS_YOU_ARE_ON_PRODUCTION, 51 | apiCheckInstance: myApiCheck 52 | }); 53 | 54 | // get your angular module 55 | var yourModule = angular.module('yourModule'); 56 | 57 | // add your instance's `directive` function to your module to make it injectable 58 | yourModule.constant('myScopeTypesDirective', myScopeTypes.directive); 59 | 60 | 61 | // later in your code for a directive: 62 | yourModule.directive('myDirective', function(myScopeTypesDirective) { 63 | return myScopeTypesDirective({ 64 | templateUrl: '/my-directive.html', 65 | scope: {foo: '=', bar: '@'}, 66 | scopeTypes: getScopeTypes 67 | }); 68 | 69 | function getScopeTypes(check) { 70 | return { 71 | foo: check.shape({ 72 | isFoo: check.bool, 73 | isBar: check.bool, 74 | someNum: check.number, 75 | someOptional: check.object.optional 76 | }).strict.optional, 77 | bar: check.oneOf(['fooString', 'barString']) 78 | }; 79 | } 80 | }); 81 | ``` 82 | 83 | See and play with [the demo](https://jsbin.com/kuqeye/edit?html,js,output) for a live example. 84 | 85 | ## LICENSE MIT 86 | -------------------------------------------------------------------------------- /demo/angular-scope-types.js: -------------------------------------------------------------------------------- 1 | ../dist/angular-scope-types.js -------------------------------------------------------------------------------- /demo/angular.js: -------------------------------------------------------------------------------- 1 | ../node_modules/angular/angular.js -------------------------------------------------------------------------------- /demo/api-check.js: -------------------------------------------------------------------------------- 1 | ../node_modules/api-check/dist/api-check.js -------------------------------------------------------------------------------- /demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | angular-scope-types 6 | 7 | 8 | 9 |

angular-scope-types

10 | 11 | Example App 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /demo/script.js: -------------------------------------------------------------------------------- 1 | var app = angular.module('app', []); 2 | 3 | app.controller('MainCtrl', function MainCtrl($timeout) { 4 | var vm = this; 5 | 6 | vm.goodFoo = { 7 | isFoo: true, 8 | isBar: false, 9 | someNum: 32 10 | }; 11 | 12 | $timeout(function() { 13 | vm.badFoo = ''; 14 | }, 1500); 15 | }); 16 | 17 | 18 | app.constant('scopeTypesDirective', angularScopeTypes().directive); 19 | 20 | app.directive('scopeTypedDir', function(scopeTypesDirective) { 21 | return scopeTypesDirective({ 22 | template: ` 23 |
24 | This was scope type checked! 25 |
Passed: {{$scopeTypesResults.__passed}}
26 |
Failed: {{$scopeTypesResults.__failed}}
27 |
28 | `, 29 | scope: {foo: '=', bar: '@'}, 30 | scopeTypes: getScopeTypes 31 | }); 32 | 33 | function getScopeTypes(st) { 34 | return { 35 | foo: st.shape({ 36 | isFoo: st.bool, 37 | isBar: st.bool, 38 | someNum: st.number, 39 | someOptional: st.object.optional 40 | }).strict.optional, 41 | bar: st.oneOf(['fooString', 'barString']) 42 | }; 43 | } 44 | 45 | }); 46 | -------------------------------------------------------------------------------- /dist/angular-scope-types.js: -------------------------------------------------------------------------------- 1 | //! angular-scope-types version 1.0.0-beta.7 built with ♥ by Kent C. Dodds (http://kent.doddsfamily.us) (ó ì_í)=óò=(ì_í ò) 2 | 3 | (function webpackUniversalModuleDefinition(root, factory) { 4 | if(typeof exports === 'object' && typeof module === 'object') 5 | module.exports = factory(require("angular"), require("api-check")); 6 | else if(typeof define === 'function' && define.amd) 7 | define(["angular", "api-check"], factory); 8 | else if(typeof exports === 'object') 9 | exports["angularScopeTypes"] = factory(require("angular"), require("api-check")); 10 | else 11 | root["angularScopeTypes"] = factory(root["angular"], root["apiCheck"]); 12 | })(this, function(__WEBPACK_EXTERNAL_MODULE_3__, __WEBPACK_EXTERNAL_MODULE_4__) { 13 | return /******/ (function(modules) { // webpackBootstrap 14 | /******/ // The module cache 15 | /******/ var installedModules = {}; 16 | 17 | /******/ // The require function 18 | /******/ function __webpack_require__(moduleId) { 19 | 20 | /******/ // Check if module is in cache 21 | /******/ if(installedModules[moduleId]) 22 | /******/ return installedModules[moduleId].exports; 23 | 24 | /******/ // Create a new module (and put it into the cache) 25 | /******/ var module = installedModules[moduleId] = { 26 | /******/ exports: {}, 27 | /******/ id: moduleId, 28 | /******/ loaded: false 29 | /******/ }; 30 | 31 | /******/ // Execute the module function 32 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 33 | 34 | /******/ // Flag the module as loaded 35 | /******/ module.loaded = true; 36 | 37 | /******/ // Return the exports of the module 38 | /******/ return module.exports; 39 | /******/ } 40 | 41 | 42 | /******/ // expose the modules object (__webpack_modules__) 43 | /******/ __webpack_require__.m = modules; 44 | 45 | /******/ // expose the module cache 46 | /******/ __webpack_require__.c = installedModules; 47 | 48 | /******/ // __webpack_public_path__ 49 | /******/ __webpack_require__.p = ""; 50 | 51 | /******/ // Load entry module and return exports 52 | /******/ return __webpack_require__(0); 53 | /******/ }) 54 | /************************************************************************/ 55 | /******/ ([ 56 | /* 0 */ 57 | /***/ function(module, exports, __webpack_require__) { 58 | 59 | 'use strict'; 60 | 61 | Object.defineProperty(exports, '__esModule', { 62 | value: true 63 | }); 64 | 65 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 66 | 67 | var _scopeTypes = __webpack_require__(1); 68 | 69 | var _scopeTypes2 = _interopRequireDefault(_scopeTypes); 70 | 71 | exports['default'] = _scopeTypes2['default']; 72 | module.exports = exports['default']; 73 | 74 | /***/ }, 75 | /* 1 */ 76 | /***/ function(module, exports, __webpack_require__) { 77 | 78 | 'use strict'; 79 | 80 | Object.defineProperty(exports, '__esModule', { 81 | value: true 82 | }); 83 | 84 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 85 | 86 | var _angularFix = __webpack_require__(2); 87 | 88 | var _angularFix2 = _interopRequireDefault(_angularFix); 89 | 90 | var _apiCheck = __webpack_require__(4); 91 | 92 | var _apiCheck2 = _interopRequireDefault(_apiCheck); 93 | 94 | var _checkers = __webpack_require__(5); 95 | 96 | var _checkers2 = _interopRequireDefault(_checkers); 97 | 98 | var defaultOutput = { prefix: 'angular-scope-types' }; 99 | 100 | exports['default'] = scopeTypesFactory; 101 | 102 | function scopeTypesFactory() { 103 | var _ref = arguments[0] === undefined ? { 104 | disabled: false, 105 | output: defaultOutput, 106 | apiCheckInstance: undefined 107 | } : arguments[0]; 108 | 109 | var _ref$disabled = _ref.disabled; 110 | var disabled = _ref$disabled === undefined ? false : _ref$disabled; 111 | var _ref$output = _ref.output; 112 | var output = _ref$output === undefined ? defaultOutput : _ref$output; 113 | var apiCheckInstance = _ref.apiCheckInstance; 114 | 115 | var scopeTypes = (0, _apiCheck2['default'])({ 116 | output: output, 117 | disabled: disabled 118 | }); 119 | // manually adding checkers so we have an instance of scopeTypes to pass them. 120 | _angularFix2['default'].forEach(_checkers2['default'], function (factory, name) { 121 | scopeTypes[name] = factory({ scopeTypes: scopeTypes, disabled: disabled }); 122 | }); 123 | 124 | scopeTypes.directive = validateDirective; 125 | 126 | apiCheckInstance = apiCheckInstance || scopeTypes; 127 | 128 | return scopeTypes; 129 | 130 | function validateDirective(ddo) { 131 | if (scopeTypes.config.disabled || apiCheckInstance.config.disabled) { 132 | return ddo; 133 | } 134 | scopeTypes.warn(scopeTypes.ddo, ddo, { prefix: 'creating directive with scopeTypes' }); 135 | // Would really love to not have to extend the ddo's controller 136 | // like this. Suggestions welcome! 137 | ddo.controller = extendController(ddo.controller, scopeTypesController); 138 | 139 | scopeTypesController.$inject = ['$scope']; 140 | function scopeTypesController($scope) { 141 | var context = $scope; 142 | if (ddo.bindToController) { 143 | context = context[ddo.controllerAs]; 144 | } 145 | 146 | var typeDefinitions = ddo.scopeTypes(apiCheckInstance); 147 | scopeTypes.warn(scopeTypes.objectOf(scopeTypes.func).optional, typeDefinitions, { prefix: 'getting scope types for ' + ddo.name }); 148 | 149 | $scope.$scopeTypesResults = { __passed: 0, __failed: 0 }; 150 | 151 | _angularFix2['default'].forEach(typeDefinitions, function (check, name) { 152 | if (!_angularFix2['default'].isDefined(context[name]) && check.isOptional) { 153 | (function () { 154 | var prefix = ddo.controllerAs ? ddo.controllerAs + '.' : ''; 155 | var stopWatching = $scope.$watch('' + prefix + '' + name, function (value, oldValue) { 156 | if (value !== oldValue) { 157 | stopWatching(); 158 | checkOption(check, name); 159 | } 160 | }); 161 | })(); 162 | } else { 163 | checkOption(check, name); 164 | } 165 | }); 166 | 167 | function checkOption(checker, name) { 168 | $scope.$scopeTypesResults[name] = apiCheckInstance[ddo.scopeTypesFunction || 'warn'](checker, context[name], { prefix: '' + ddo.name + 'Directive for "' + name + '"' }); 169 | updateData(); 170 | } 171 | 172 | function updateData() { 173 | var passedCount = 0; 174 | var failedCount = 0; 175 | var ignore = ['__passed', '__failed']; 176 | _angularFix2['default'].forEach($scope.$scopeTypesResults, function (result, name) { 177 | if (ignore.indexOf(name) === -1) { 178 | if (result.passed) { 179 | passedCount++; 180 | } else { 181 | failedCount++; 182 | } 183 | } 184 | }); 185 | $scope.$scopeTypesResults.__passed = passedCount; 186 | $scope.$scopeTypesResults.__failed = failedCount; 187 | } 188 | } 189 | 190 | return ddo; 191 | 192 | function extendController(originalController, newController) { 193 | if (!_angularFix2['default'].isDefined(originalController)) { 194 | return newController; 195 | } 196 | function wrappedController($scope, $controller, $element, $attrs, $transclude, $injector) { 197 | var locals = { $scope: $scope, $element: $element, $attrs: $attrs, $transclude: $transclude }; 198 | $injector.invoke(newController, this, locals); 199 | $injector.invoke(originalController, this, locals); 200 | } 201 | 202 | wrappedController.$inject = ['$scope', '$controller', '$element', '$attrs', '$transclude', '$injector']; 203 | wrappedController.displayName = getWrappedControllerDisplayName(originalController); 204 | return wrappedController; 205 | } 206 | 207 | function getWrappedControllerDisplayName(originalController) { 208 | var originalControllerName = originalController.displayName || originalController.name; 209 | var name = 'angular-scope-types controller wrapper'; 210 | if (originalControllerName) { 211 | name = '' + name + ' for ' + originalControllerName; 212 | } 213 | return name; 214 | } 215 | } 216 | } 217 | module.exports = exports['default']; 218 | 219 | /***/ }, 220 | /* 2 */ 221 | /***/ function(module, exports, __webpack_require__) { 222 | 223 | // some versions of angular don't export the angular module properly, 224 | // so we get it from window in this case. 225 | 'use strict'; 226 | 227 | Object.defineProperty(exports, '__esModule', { 228 | value: true 229 | }); 230 | var angular = __webpack_require__(3); 231 | /* istanbul ignore next */ 232 | if (!angular.version) { 233 | angular = window.angular; 234 | } 235 | exports['default'] = angular; 236 | module.exports = exports['default']; 237 | 238 | /***/ }, 239 | /* 3 */ 240 | /***/ function(module, exports) { 241 | 242 | module.exports = __WEBPACK_EXTERNAL_MODULE_3__; 243 | 244 | /***/ }, 245 | /* 4 */ 246 | /***/ function(module, exports) { 247 | 248 | module.exports = __WEBPACK_EXTERNAL_MODULE_4__; 249 | 250 | /***/ }, 251 | /* 5 */ 252 | /***/ function(module, exports, __webpack_require__) { 253 | 254 | 'use strict'; 255 | 256 | Object.defineProperty(exports, '__esModule', { 257 | value: true 258 | }); 259 | 260 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 261 | 262 | var _injectableFunction = __webpack_require__(6); 263 | 264 | var _injectableFunction2 = _interopRequireDefault(_injectableFunction); 265 | 266 | var _ddo = __webpack_require__(7); 267 | 268 | var _ddo2 = _interopRequireDefault(_ddo); 269 | 270 | exports['default'] = { 271 | injectableFunction: _injectableFunction2['default'], ddo: _ddo2['default'] 272 | }; 273 | module.exports = exports['default']; 274 | 275 | /***/ }, 276 | /* 6 */ 277 | /***/ function(module, exports, __webpack_require__) { 278 | 279 | 'use strict'; 280 | 281 | Object.defineProperty(exports, '__esModule', { 282 | value: true 283 | }); 284 | exports['default'] = injectableFunction; 285 | 286 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 287 | 288 | var _apiCheck = __webpack_require__(4); 289 | 290 | var _apiCheck2 = _interopRequireDefault(_apiCheck); 291 | 292 | function injectableFunction() { 293 | var _ref = arguments[0] === undefined ? { strictDi: false, disabled: false } : arguments[0]; 294 | 295 | var _ref$strictDi = _ref.strictDi; 296 | var strictDi = _ref$strictDi === undefined ? false : _ref$strictDi; 297 | var _ref$disabled = _ref.disabled; 298 | var disabled = _ref$disabled === undefined ? false : _ref$disabled; 299 | 300 | var $injectProperty = _apiCheck2['default'].func.withProperties({ 301 | $inject: _apiCheck2['default'].arrayOf(_apiCheck2['default'].string) 302 | }); 303 | 304 | var arraySyntax = _apiCheck2['default'].utils.checkerHelpers.setupChecker(function arraySyntax(val, name, location) { 305 | if (!Array.isArray(val)) { 306 | return _apiCheck2['default'].utils.getError(name, location, _apiCheck2['default'].array.type); 307 | } 308 | var copy = val.slice(); 309 | var fn = copy.pop(); 310 | var arrayOfStringsChecker = _apiCheck2['default'].arrayOf(_apiCheck2['default'].string); 311 | var notArrayOfStrings = arrayOfStringsChecker(copy); 312 | if (_apiCheck2['default'].utils.isError(notArrayOfStrings)) { 313 | return _apiCheck2['default'].utils.getError(name, location, arrayOfStringsChecker.type); 314 | } 315 | if (typeof fn !== 'function') { 316 | return _apiCheck2['default'].utils.getError(name, location, _apiCheck2['default'].func.type); 317 | } 318 | }, { type: 'angular injectable function (array syntax)' }, disabled); 319 | 320 | var types = [$injectProperty, arraySyntax]; 321 | 322 | if (!strictDi) { 323 | types.push(_apiCheck2['default'].func); 324 | } 325 | 326 | return _apiCheck2['default'].oneOfType(types); 327 | } 328 | 329 | module.exports = exports['default']; 330 | 331 | /***/ }, 332 | /* 7 */ 333 | /***/ function(module, exports, __webpack_require__) { 334 | 335 | 'use strict'; 336 | 337 | Object.defineProperty(exports, '__esModule', { 338 | value: true 339 | }); 340 | exports['default'] = ddo; 341 | 342 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 343 | 344 | var _checkerUtils = __webpack_require__(8); 345 | 346 | var _checkerUtils2 = _interopRequireDefault(_checkerUtils); 347 | 348 | function ddo() { 349 | var _ref = arguments[0] === undefined ? { 350 | strictDi: false, disabled: false 351 | } : arguments[0]; 352 | 353 | var scopeTypes = _ref.scopeTypes; 354 | var _ref$strictDi = _ref.strictDi; 355 | var strictDi = _ref$strictDi === undefined ? false : _ref$strictDi; 356 | var _ref$disabled = _ref.disabled; 357 | var disabled = _ref$disabled === undefined ? false : _ref$disabled; 358 | 359 | if (disabled) { 360 | return _checkerUtils2['default'].noopChecker; 361 | } 362 | 363 | var check = scopeTypes; 364 | if (!check) { 365 | throw new Error('Must provide an instance of scopeTypes'); 366 | } 367 | var stringOrFunc = scopeTypes.oneOfType([check.string, check.func]); 368 | var ddoShape = check.shape({ 369 | priority: check.number.optional, 370 | template: check.shape.ifNot('templateUrl', stringOrFunc).optional, 371 | templateUrl: check.shape.ifNot('template', check.string).optional, 372 | transclude: check.bool.optional, 373 | restrict: check.oneOf(['A', 'E', 'C', 'AE', 'EA', 'AEC', 'AC', 'EC']).optional, 374 | replace: check.bool.optional, 375 | templateNamespace: check.oneOf(['html', 'svg', 'math']).optional, 376 | scope: check.oneOfType([check.bool, check.objectOf(check.string)]).optional, // TODO, make an advanced scope checker 377 | controller: check.injectableFunction.optional, 378 | controllerAs: check.string.optional, 379 | bindToController: check.oneOfType([check.bool, check.objectOf(check.string)]).optional, 380 | // TODO, tell the version of angular and use a scope checker for +1.4 381 | require: check.typeOrArrayOf(check.string).optional, // TODO make a pattern checker. 382 | // 'siblingDirectiveName', // or // ['^parentDirectiveName', '?optionalDirectiveName', '?^optionalParent'], 383 | compile: check.func.optional, 384 | link: check.oneOfType([check.func, check.shape({ 385 | pre: check.func.optional, 386 | post: check.func.optional 387 | }).strict]).optional, 388 | scopeTypes: check.func, 389 | scopeTypesFunction: check.oneOf(['warn', 'throw']).optional, 390 | data: check.object.optional 391 | }).strict; 392 | 393 | return check.oneOfType([check.func, ddoShape]); 394 | } 395 | 396 | module.exports = exports['default']; 397 | 398 | /***/ }, 399 | /* 8 */ 400 | /***/ function(module, exports) { 401 | 402 | "use strict"; 403 | 404 | Object.defineProperty(exports, "__esModule", { 405 | value: true 406 | }); 407 | function noopChecker() {} 408 | noopChecker.nullable = noopChecker; 409 | noopChecker.nullable.optional = noopChecker; 410 | 411 | exports["default"] = { noopChecker: noopChecker }; 412 | module.exports = exports["default"]; 413 | 414 | /***/ } 415 | /******/ ]) 416 | }); 417 | ; -------------------------------------------------------------------------------- /dist/angular-scope-types.min.js: -------------------------------------------------------------------------------- 1 | //! angular-scope-types version 1.0.0-beta.7 built with ♥ by Kent C. Dodds (http://kent.doddsfamily.us) (ó ì_í)=óò=(ì_í ò) 2 | !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("api-check"),require("angular")):"function"==typeof define&&define.amd?define(["api-check","angular"],t):"object"==typeof exports?exports.angularScopeTypes=t(require("api-check"),require("angular")):e.angularScopeTypes=t(e.apiCheck,e.angular)}(this,function(e,t){return function(e){function t(n){if(o[n])return o[n].exports;var r=o[n]={exports:{},id:n,loaded:!1};return e[n].call(r.exports,r,r.exports,t),r.loaded=!0,r.exports}var o={};return t.m=e,t.c=o,t.p="",t(0)}([function(e,t,o){"use strict";function n(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(t,"__esModule",{value:!0});var r=o(7),a=n(r);t["default"]=a["default"],e.exports=t["default"]},function(t,o){t.exports=e},function(e,t,o){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=o(8);n.version||(n=window.angular),t["default"]=n,e.exports=t["default"]},function(e,t){"use strict";function o(){}Object.defineProperty(t,"__esModule",{value:!0}),o.nullable=o,o.nullable.optional=o,t["default"]={noopChecker:o},e.exports=t["default"]},function(e,t,o){"use strict";function n(e){return e&&e.__esModule?e:{"default":e}}function r(){var e=void 0===arguments[0]?{strictDi:!1,disabled:!1}:arguments[0],t=e.scopeTypes,o=(e.strictDi,e.disabled),n=void 0===o?!1:o;if(n)return i["default"].noopChecker;var r=t;if(!r)throw new Error("Must provide an instance of scopeTypes");var a=t.oneOfType([r.string,r.func]),u=r.shape({priority:r.number.optional,template:r.shape.ifNot("templateUrl",a).optional,templateUrl:r.shape.ifNot("template",r.string).optional,transclude:r.bool.optional,restrict:r.oneOf(["A","E","C","AE","EA","AEC","AC","EC"]).optional,replace:r.bool.optional,templateNamespace:r.oneOf(["html","svg","math"]).optional,scope:r.oneOfType([r.bool,r.objectOf(r.string)]).optional,controller:r.injectableFunction.optional,controllerAs:r.string.optional,bindToController:r.oneOfType([r.bool,r.objectOf(r.string)]).optional,require:r.typeOrArrayOf(r.string).optional,compile:r.func.optional,link:r.oneOfType([r.func,r.shape({pre:r.func.optional,post:r.func.optional}).strict]).optional,scopeTypes:r.func,scopeTypesFunction:r.oneOf(["warn","throw"]).optional,data:r.object.optional}).strict;return r.oneOfType([r.func,u])}Object.defineProperty(t,"__esModule",{value:!0}),t["default"]=r;var a=o(3),i=n(a);e.exports=t["default"]},function(e,t,o){"use strict";function n(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(t,"__esModule",{value:!0});var r=o(6),a=n(r),i=o(4),u=n(i);t["default"]={injectableFunction:a["default"],ddo:u["default"]},e.exports=t["default"]},function(e,t,o){"use strict";function n(e){return e&&e.__esModule?e:{"default":e}}function r(){var e=void 0===arguments[0]?{strictDi:!1,disabled:!1}:arguments[0],t=e.strictDi,o=void 0===t?!1:t,n=e.disabled,r=void 0===n?!1:n,a=i["default"].func.withProperties({$inject:i["default"].arrayOf(i["default"].string)}),u=i["default"].utils.checkerHelpers.setupChecker(function(e,t,o){if(!Array.isArray(e))return i["default"].utils.getError(t,o,i["default"].array.type);var n=e.slice(),r=n.pop(),a=i["default"].arrayOf(i["default"].string),u=a(n);return i["default"].utils.isError(u)?i["default"].utils.getError(t,o,a.type):"function"!=typeof r?i["default"].utils.getError(t,o,i["default"].func.type):void 0},{type:"angular injectable function (array syntax)"},r),l=[a,u];return o||l.push(i["default"].func),i["default"].oneOfType(l)}Object.defineProperty(t,"__esModule",{value:!0}),t["default"]=r;var a=o(1),i=n(a);e.exports=t["default"]},function(e,t,o){"use strict";function n(e){return e&&e.__esModule?e:{"default":e}}function r(){function e(e){function t(t){function o(o,a){t.$scopeTypesResults[a]=u[e.scopeTypesFunction||"warn"](o,r[a],{prefix:""+e.name+'Directive for "'+a+'"'}),n()}function n(){var e=0,o=0,n=["__passed","__failed"];i["default"].forEach(t.$scopeTypesResults,function(t,r){-1===n.indexOf(r)&&(t.passed?e++:o++)}),t.$scopeTypesResults.__passed=e,t.$scopeTypesResults.__failed=o}var r=t;e.bindToController&&(r=r[e.controllerAs]);var a=e.scopeTypes(u);s.warn(s.objectOf(s.func).optional,a,{prefix:"getting scope types for "+e.name}),t.$scopeTypesResults={__passed:0,__failed:0},i["default"].forEach(a,function(n,a){!i["default"].isDefined(r[a])&&n.isOptional?!function(){var r=e.controllerAs?e.controllerAs+".":"",i=t.$watch(""+r+a,function(e,t){e!==t&&(i(),o(n,a))})}():o(n,a)})}function o(e,t){function o(o,n,r,a,i,u){var l={$scope:o,$element:r,$attrs:a,$transclude:i};u.invoke(t,this,l),u.invoke(e,this,l)}return i["default"].isDefined(e)?(o.$inject=["$scope","$controller","$element","$attrs","$transclude","$injector"],o.displayName=n(e),o):t}function n(e){var t=e.displayName||e.name,o="angular-scope-types controller wrapper";return t&&(o=""+o+" for "+t),o}return s.config.disabled||u.config.disabled?e:(s.warn(s.ddo,e,{prefix:"creating directive with scopeTypes"}),e.controller=o(e.controller,t),t.$inject=["$scope"],e)}var t=void 0===arguments[0]?{disabled:!1,output:f,apiCheckInstance:void 0}:arguments[0],o=t.disabled,n=void 0===o?!1:o,r=t.output,a=void 0===r?f:r,u=t.apiCheckInstance,s=l["default"]({output:a,disabled:n});return i["default"].forEach(c["default"],function(e,t){s[t]=e({scopeTypes:s,disabled:n})}),s.directive=e,u=u||s,s}Object.defineProperty(t,"__esModule",{value:!0});var a=o(2),i=n(a),u=o(1),l=n(u),s=o(5),c=n(s),f={prefix:"angular-scope-types"};t["default"]=r,e.exports=t["default"]},function(e,o){e.exports=t}])}); 3 | //# sourceMappingURL=angular-scope-types.min.js.map -------------------------------------------------------------------------------- /dist/angular-scope-types.min.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["webpack:///webpack/universalModuleDefinition","webpack:///dist/angular-scope-types.min.js","webpack:///webpack/bootstrap 857925f8c38dd1dc86e2","webpack:///./index.js","webpack:///external {\"root\":\"apiCheck\",\"amd\":\"api-check\",\"commonjs2\":\"api-check\",\"commonjs\":\"api-check\"}","webpack:///./angular-fix/index.js","webpack:///./checkers/checkerUtils.js","webpack:///./checkers/ddo.js","webpack:///./checkers/index.js","webpack:///./checkers/injectableFunction.js","webpack:///./scopeTypes.js","webpack:///external \"angular\""],"names":["root","factory","exports","module","require","define","amd","this","__WEBPACK_EXTERNAL_MODULE_1__","__WEBPACK_EXTERNAL_MODULE_8__","modules","__webpack_require__","moduleId","installedModules","id","loaded","call","m","c","p","_interopRequireDefault","obj","__esModule","default","Object","defineProperty","value","_scopeTypes","_scopeTypes2","angular","version","window","noopChecker","nullable","optional","ddo","_ref","undefined","arguments","strictDi","disabled","scopeTypes","_ref$disabled","_checkerUtils2","check","Error","stringOrFunc","oneOfType","string","func","ddoShape","shape","priority","number","template","ifNot","templateUrl","transclude","bool","restrict","oneOf","replace","templateNamespace","scope","objectOf","controller","injectableFunction","controllerAs","bindToController","typeOrArrayOf","compile","link","pre","post","strict","scopeTypesFunction","data","object","_checkerUtils","_injectableFunction","_injectableFunction2","_ddo","_ddo2","_ref$strictDi","$injectProperty","_apiCheck2","withProperties","$inject","arrayOf","arraySyntax","utils","checkerHelpers","setupChecker","val","name","location","Array","isArray","getError","array","type","copy","slice","fn","pop","arrayOfStringsChecker","notArrayOfStrings","isError","types","push","_apiCheck","scopeTypesFactory","validateDirective","scopeTypesController","$scope","checkOption","checker","$scopeTypesResults","apiCheckInstance","context","prefix","updateData","passedCount","failedCount","ignore","_angularFix2","forEach","result","indexOf","passed","__passed","__failed","typeDefinitions","warn","isDefined","isOptional","stopWatching","$watch","oldValue","extendController","originalController","newController","wrappedController","$controller","$element","$attrs","$transclude","$injector","locals","invoke","displayName","getWrappedControllerDisplayName","originalControllerName","config","output","defaultOutput","_ref$output","_checkers2","directive","_angularFix","_checkers"],"mappings":"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","file":"dist/angular-scope-types.min.js","sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory(require(\"api-check\"), require(\"angular\"));\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([\"api-check\", \"angular\"], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"angularScopeTypes\"] = factory(require(\"api-check\"), require(\"angular\"));\n\telse\n\t\troot[\"angularScopeTypes\"] = factory(root[\"apiCheck\"], root[\"angular\"]);\n})(this, function(__WEBPACK_EXTERNAL_MODULE_1__, __WEBPACK_EXTERNAL_MODULE_8__) {\nreturn \n\n\n/** WEBPACK FOOTER **\n ** webpack/universalModuleDefinition\n **/","//! angular-scope-types version 1.0.0-beta.7 built with ♥ by Kent C. Dodds (http://kent.doddsfamily.us) (ó ì_í)=óò=(ì_í ò)\n\n(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory(require(\"api-check\"), require(\"angular\"));\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([\"api-check\", \"angular\"], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"angularScopeTypes\"] = factory(require(\"api-check\"), require(\"angular\"));\n\telse\n\t\troot[\"angularScopeTypes\"] = factory(root[\"apiCheck\"], root[\"angular\"]);\n})(this, function(__WEBPACK_EXTERNAL_MODULE_1__, __WEBPACK_EXTERNAL_MODULE_8__) {\nreturn /******/ (function(modules) { // webpackBootstrap\n/******/ \t// The module cache\n/******/ \tvar installedModules = {};\n/******/\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(installedModules[moduleId])\n/******/ \t\t\treturn installedModules[moduleId].exports;\n/******/\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = installedModules[moduleId] = {\n/******/ \t\t\texports: {},\n/******/ \t\t\tid: moduleId,\n/******/ \t\t\tloaded: false\n/******/ \t\t};\n/******/\n/******/ \t\t// Execute the module function\n/******/ \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n/******/\n/******/ \t\t// Flag the module as loaded\n/******/ \t\tmodule.loaded = true;\n/******/\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/\n/******/\n/******/ \t// expose the modules object (__webpack_modules__)\n/******/ \t__webpack_require__.m = modules;\n/******/\n/******/ \t// expose the module cache\n/******/ \t__webpack_require__.c = installedModules;\n/******/\n/******/ \t// __webpack_public_path__\n/******/ \t__webpack_require__.p = \"\";\n/******/\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(0);\n/******/ })\n/************************************************************************/\n/******/ ([\n/* 0 */\n/***/ function(module, exports, __webpack_require__) {\n\n\t'use strict';\n\t\n\tObject.defineProperty(exports, '__esModule', {\n\t value: true\n\t});\n\t\n\tfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\t\n\tvar _scopeTypes = __webpack_require__(7);\n\t\n\tvar _scopeTypes2 = _interopRequireDefault(_scopeTypes);\n\n\texports['default'] = _scopeTypes2['default'];\n\tmodule.exports = exports['default'];\n\n/***/ },\n/* 1 */\n/***/ function(module, exports) {\n\n\tmodule.exports = __WEBPACK_EXTERNAL_MODULE_1__;\n\n/***/ },\n/* 2 */\n/***/ function(module, exports, __webpack_require__) {\n\n\t// some versions of angular don't export the angular module properly,\n\t// so we get it from window in this case.\n\t'use strict';\n\t\n\tObject.defineProperty(exports, '__esModule', {\n\t value: true\n\t});\n\tvar angular = __webpack_require__(8);\n\t/* istanbul ignore next */\n\tif (!angular.version) {\n\t angular = window.angular;\n\t}\n\texports['default'] = angular;\n\tmodule.exports = exports['default'];\n\n/***/ },\n/* 3 */\n/***/ function(module, exports) {\n\n\t\"use strict\";\n\t\n\tObject.defineProperty(exports, \"__esModule\", {\n\t value: true\n\t});\n\tfunction noopChecker() {}\n\tnoopChecker.nullable = noopChecker;\n\tnoopChecker.nullable.optional = noopChecker;\n\t\n\texports[\"default\"] = { noopChecker: noopChecker };\n\tmodule.exports = exports[\"default\"];\n\n/***/ },\n/* 4 */\n/***/ function(module, exports, __webpack_require__) {\n\n\t'use strict';\n\t\n\tObject.defineProperty(exports, '__esModule', {\n\t value: true\n\t});\n\texports['default'] = ddo;\n\t\n\tfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\t\n\tvar _checkerUtils = __webpack_require__(3);\n\t\n\tvar _checkerUtils2 = _interopRequireDefault(_checkerUtils);\n\t\n\tfunction ddo() {\n\t var _ref = arguments[0] === undefined ? {\n\t strictDi: false, disabled: false\n\t } : arguments[0];\n\t\n\t var scopeTypes = _ref.scopeTypes;\n\t var _ref$strictDi = _ref.strictDi;\n\t var strictDi = _ref$strictDi === undefined ? false : _ref$strictDi;\n\t var _ref$disabled = _ref.disabled;\n\t var disabled = _ref$disabled === undefined ? false : _ref$disabled;\n\t\n\t if (disabled) {\n\t return _checkerUtils2['default'].noopChecker;\n\t }\n\t\n\t var check = scopeTypes;\n\t if (!check) {\n\t throw new Error('Must provide an instance of scopeTypes');\n\t }\n\t var stringOrFunc = scopeTypes.oneOfType([check.string, check.func]);\n\t var ddoShape = check.shape({\n\t priority: check.number.optional,\n\t template: check.shape.ifNot('templateUrl', stringOrFunc).optional,\n\t templateUrl: check.shape.ifNot('template', check.string).optional,\n\t transclude: check.bool.optional,\n\t restrict: check.oneOf(['A', 'E', 'C', 'AE', 'EA', 'AEC', 'AC', 'EC']).optional,\n\t replace: check.bool.optional,\n\t templateNamespace: check.oneOf(['html', 'svg', 'math']).optional,\n\t scope: check.oneOfType([check.bool, check.objectOf(check.string)]).optional, // TODO, make an advanced scope checker\n\t controller: check.injectableFunction.optional,\n\t controllerAs: check.string.optional,\n\t bindToController: check.oneOfType([check.bool, check.objectOf(check.string)]).optional,\n\t // TODO, tell the version of angular and use a scope checker for +1.4\n\t require: check.typeOrArrayOf(check.string).optional, // TODO make a pattern checker.\n\t // 'siblingDirectiveName', // or // ['^parentDirectiveName', '?optionalDirectiveName', '?^optionalParent'],\n\t compile: check.func.optional,\n\t link: check.oneOfType([check.func, check.shape({\n\t pre: check.func.optional,\n\t post: check.func.optional\n\t }).strict]).optional,\n\t scopeTypes: check.func,\n\t scopeTypesFunction: check.oneOf(['warn', 'throw']).optional,\n\t data: check.object.optional\n\t }).strict;\n\t\n\t return check.oneOfType([check.func, ddoShape]);\n\t}\n\t\n\tmodule.exports = exports['default'];\n\n/***/ },\n/* 5 */\n/***/ function(module, exports, __webpack_require__) {\n\n\t'use strict';\n\t\n\tObject.defineProperty(exports, '__esModule', {\n\t value: true\n\t});\n\t\n\tfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\t\n\tvar _injectableFunction = __webpack_require__(6);\n\t\n\tvar _injectableFunction2 = _interopRequireDefault(_injectableFunction);\n\t\n\tvar _ddo = __webpack_require__(4);\n\t\n\tvar _ddo2 = _interopRequireDefault(_ddo);\n\t\n\texports['default'] = {\n\t injectableFunction: _injectableFunction2['default'], ddo: _ddo2['default']\n\t};\n\tmodule.exports = exports['default'];\n\n/***/ },\n/* 6 */\n/***/ function(module, exports, __webpack_require__) {\n\n\t'use strict';\n\t\n\tObject.defineProperty(exports, '__esModule', {\n\t value: true\n\t});\n\texports['default'] = injectableFunction;\n\t\n\tfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\t\n\tvar _apiCheck = __webpack_require__(1);\n\t\n\tvar _apiCheck2 = _interopRequireDefault(_apiCheck);\n\t\n\tfunction injectableFunction() {\n\t var _ref = arguments[0] === undefined ? { strictDi: false, disabled: false } : arguments[0];\n\t\n\t var _ref$strictDi = _ref.strictDi;\n\t var strictDi = _ref$strictDi === undefined ? false : _ref$strictDi;\n\t var _ref$disabled = _ref.disabled;\n\t var disabled = _ref$disabled === undefined ? false : _ref$disabled;\n\t\n\t var $injectProperty = _apiCheck2['default'].func.withProperties({\n\t $inject: _apiCheck2['default'].arrayOf(_apiCheck2['default'].string)\n\t });\n\t\n\t var arraySyntax = _apiCheck2['default'].utils.checkerHelpers.setupChecker(function arraySyntax(val, name, location) {\n\t if (!Array.isArray(val)) {\n\t return _apiCheck2['default'].utils.getError(name, location, _apiCheck2['default'].array.type);\n\t }\n\t var copy = val.slice();\n\t var fn = copy.pop();\n\t var arrayOfStringsChecker = _apiCheck2['default'].arrayOf(_apiCheck2['default'].string);\n\t var notArrayOfStrings = arrayOfStringsChecker(copy);\n\t if (_apiCheck2['default'].utils.isError(notArrayOfStrings)) {\n\t return _apiCheck2['default'].utils.getError(name, location, arrayOfStringsChecker.type);\n\t }\n\t if (typeof fn !== 'function') {\n\t return _apiCheck2['default'].utils.getError(name, location, _apiCheck2['default'].func.type);\n\t }\n\t }, { type: 'angular injectable function (array syntax)' }, disabled);\n\t\n\t var types = [$injectProperty, arraySyntax];\n\t\n\t if (!strictDi) {\n\t types.push(_apiCheck2['default'].func);\n\t }\n\t\n\t return _apiCheck2['default'].oneOfType(types);\n\t}\n\t\n\tmodule.exports = exports['default'];\n\n/***/ },\n/* 7 */\n/***/ function(module, exports, __webpack_require__) {\n\n\t'use strict';\n\t\n\tObject.defineProperty(exports, '__esModule', {\n\t value: true\n\t});\n\t\n\tfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\t\n\tvar _angularFix = __webpack_require__(2);\n\t\n\tvar _angularFix2 = _interopRequireDefault(_angularFix);\n\t\n\tvar _apiCheck = __webpack_require__(1);\n\t\n\tvar _apiCheck2 = _interopRequireDefault(_apiCheck);\n\t\n\tvar _checkers = __webpack_require__(5);\n\t\n\tvar _checkers2 = _interopRequireDefault(_checkers);\n\t\n\tvar defaultOutput = { prefix: 'angular-scope-types' };\n\t\n\texports['default'] = scopeTypesFactory;\n\t\n\tfunction scopeTypesFactory() {\n\t var _ref = arguments[0] === undefined ? {\n\t disabled: false,\n\t output: defaultOutput,\n\t apiCheckInstance: undefined\n\t } : arguments[0];\n\t\n\t var _ref$disabled = _ref.disabled;\n\t var disabled = _ref$disabled === undefined ? false : _ref$disabled;\n\t var _ref$output = _ref.output;\n\t var output = _ref$output === undefined ? defaultOutput : _ref$output;\n\t var apiCheckInstance = _ref.apiCheckInstance;\n\t\n\t var scopeTypes = (0, _apiCheck2['default'])({\n\t output: output,\n\t disabled: disabled\n\t });\n\t // manually adding checkers so we have an instance of scopeTypes to pass them.\n\t _angularFix2['default'].forEach(_checkers2['default'], function (factory, name) {\n\t scopeTypes[name] = factory({ scopeTypes: scopeTypes, disabled: disabled });\n\t });\n\t\n\t scopeTypes.directive = validateDirective;\n\t\n\t apiCheckInstance = apiCheckInstance || scopeTypes;\n\t\n\t return scopeTypes;\n\t\n\t function validateDirective(ddo) {\n\t if (scopeTypes.config.disabled || apiCheckInstance.config.disabled) {\n\t return ddo;\n\t }\n\t scopeTypes.warn(scopeTypes.ddo, ddo, { prefix: 'creating directive with scopeTypes' });\n\t // Would really love to not have to extend the ddo's controller\n\t // like this. Suggestions welcome!\n\t ddo.controller = extendController(ddo.controller, scopeTypesController);\n\t\n\t scopeTypesController.$inject = ['$scope'];\n\t function scopeTypesController($scope) {\n\t var context = $scope;\n\t if (ddo.bindToController) {\n\t context = context[ddo.controllerAs];\n\t }\n\t\n\t var typeDefinitions = ddo.scopeTypes(apiCheckInstance);\n\t scopeTypes.warn(scopeTypes.objectOf(scopeTypes.func).optional, typeDefinitions, { prefix: 'getting scope types for ' + ddo.name });\n\t\n\t $scope.$scopeTypesResults = { __passed: 0, __failed: 0 };\n\t\n\t _angularFix2['default'].forEach(typeDefinitions, function (check, name) {\n\t if (!_angularFix2['default'].isDefined(context[name]) && check.isOptional) {\n\t (function () {\n\t var prefix = ddo.controllerAs ? ddo.controllerAs + '.' : '';\n\t var stopWatching = $scope.$watch('' + prefix + '' + name, function (value, oldValue) {\n\t if (value !== oldValue) {\n\t stopWatching();\n\t checkOption(check, name);\n\t }\n\t });\n\t })();\n\t } else {\n\t checkOption(check, name);\n\t }\n\t });\n\t\n\t function checkOption(checker, name) {\n\t $scope.$scopeTypesResults[name] = apiCheckInstance[ddo.scopeTypesFunction || 'warn'](checker, context[name], { prefix: '' + ddo.name + 'Directive for \"' + name + '\"' });\n\t updateData();\n\t }\n\t\n\t function updateData() {\n\t var passedCount = 0;\n\t var failedCount = 0;\n\t var ignore = ['__passed', '__failed'];\n\t _angularFix2['default'].forEach($scope.$scopeTypesResults, function (result, name) {\n\t if (ignore.indexOf(name) === -1) {\n\t if (result.passed) {\n\t passedCount++;\n\t } else {\n\t failedCount++;\n\t }\n\t }\n\t });\n\t $scope.$scopeTypesResults.__passed = passedCount;\n\t $scope.$scopeTypesResults.__failed = failedCount;\n\t }\n\t }\n\t\n\t return ddo;\n\t\n\t function extendController(originalController, newController) {\n\t if (!_angularFix2['default'].isDefined(originalController)) {\n\t return newController;\n\t }\n\t function wrappedController($scope, $controller, $element, $attrs, $transclude, $injector) {\n\t var locals = { $scope: $scope, $element: $element, $attrs: $attrs, $transclude: $transclude };\n\t $injector.invoke(newController, this, locals);\n\t $injector.invoke(originalController, this, locals);\n\t }\n\t\n\t wrappedController.$inject = ['$scope', '$controller', '$element', '$attrs', '$transclude', '$injector'];\n\t wrappedController.displayName = getWrappedControllerDisplayName(originalController);\n\t return wrappedController;\n\t }\n\t\n\t function getWrappedControllerDisplayName(originalController) {\n\t var originalControllerName = originalController.displayName || originalController.name;\n\t var name = 'angular-scope-types controller wrapper';\n\t if (originalControllerName) {\n\t name = '' + name + ' for ' + originalControllerName;\n\t }\n\t return name;\n\t }\n\t }\n\t}\n\tmodule.exports = exports['default'];\n\n/***/ },\n/* 8 */\n/***/ function(module, exports) {\n\n\tmodule.exports = __WEBPACK_EXTERNAL_MODULE_8__;\n\n/***/ }\n/******/ ])\n});\n;\n\n\n/** WEBPACK FOOTER **\n ** dist/angular-scope-types.min.js\n **/"," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId])\n \t\t\treturn installedModules[moduleId].exports;\n\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\texports: {},\n \t\t\tid: moduleId,\n \t\t\tloaded: false\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.loaded = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(0);\n\n\n\n/** WEBPACK FOOTER **\n ** webpack/bootstrap 857925f8c38dd1dc86e2\n **/","import scopeTypes from './scopeTypes';\n\nexport default scopeTypes;\n\n\n\n\n/** WEBPACK FOOTER **\n ** ../~/eslint-loader!./index.js\n **/","module.exports = __WEBPACK_EXTERNAL_MODULE_1__;\n\n\n/*****************\n ** WEBPACK FOOTER\n ** external {\"root\":\"apiCheck\",\"amd\":\"api-check\",\"commonjs2\":\"api-check\",\"commonjs\":\"api-check\"}\n ** module id = 1\n ** module chunks = 0\n **/","// some versions of angular don't export the angular module properly,\n// so we get it from window in this case.\nvar angular = require('angular');\n/* istanbul ignore next */\nif (!angular.version) {\n angular = window.angular;\n}\nexport default angular;\n\n\n\n/** WEBPACK FOOTER **\n ** ../~/eslint-loader!./angular-fix/index.js\n **/","function noopChecker() {\n}\nnoopChecker.nullable = noopChecker;\nnoopChecker.nullable.optional = noopChecker;\n\nexport default {noopChecker};\n\n\n\n/** WEBPACK FOOTER **\n ** ../~/eslint-loader!./checkers/checkerUtils.js\n **/","import checkerUtils from './checkerUtils';\n\nexport default function ddo({\n scopeTypes, strictDi = false, disabled = false\n } = {\n strictDi: false, disabled: false\n}) {\n if (disabled) {\n return checkerUtils.noopChecker;\n }\n\n const check = scopeTypes;\n if (!check) {\n throw new Error('Must provide an instance of scopeTypes');\n }\n const stringOrFunc = scopeTypes.oneOfType([check.string, check.func]);\n const ddoShape = check.shape({\n priority: check.number.optional,\n template: check.shape.ifNot('templateUrl', stringOrFunc).optional,\n templateUrl: check.shape.ifNot('template', check.string).optional,\n transclude: check.bool.optional,\n restrict: check.oneOf(['A', 'E', 'C', 'AE', 'EA', 'AEC', 'AC', 'EC']).optional,\n replace: check.bool.optional,\n templateNamespace: check.oneOf(['html', 'svg', 'math']).optional,\n scope: check.oneOfType([check.bool, check.objectOf(check.string)]).optional, // TODO, make an advanced scope checker\n controller: check.injectableFunction.optional,\n controllerAs: check.string.optional,\n bindToController: check.oneOfType([check.bool, check.objectOf(check.string)]).optional,\n // TODO, tell the version of angular and use a scope checker for +1.4\n require: check.typeOrArrayOf(check.string).optional, // TODO make a pattern checker.\n // 'siblingDirectiveName', // or // ['^parentDirectiveName', '?optionalDirectiveName', '?^optionalParent'],\n compile: check.func.optional,\n link: check.oneOfType([\n check.func,\n check.shape({\n pre: check.func.optional,\n post: check.func.optional\n }).strict\n ]).optional,\n scopeTypes: check.func,\n scopeTypesFunction: check.oneOf(['warn', 'throw']).optional,\n data: check.object.optional\n }).strict;\n\n return check.oneOfType([check.func, ddoShape]);\n}\n\n\n\n/** WEBPACK FOOTER **\n ** ../~/eslint-loader!./checkers/ddo.js\n **/","import injectableFunction from './injectableFunction';\nimport ddo from './ddo';\n\nexport default {\n injectableFunction, ddo\n};\n\n\n\n/** WEBPACK FOOTER **\n ** ../~/eslint-loader!./checkers/index.js\n **/","import apiCheck from 'api-check';\n\nexport default function injectableFunction({strictDi = false, disabled = false} = {strictDi: false, disabled: false}) {\n const $injectProperty = apiCheck.func.withProperties({\n $inject: apiCheck.arrayOf(apiCheck.string)\n });\n\n const arraySyntax = apiCheck.utils.checkerHelpers.setupChecker(function arraySyntax(val, name, location) {\n if (!Array.isArray(val)) {\n return apiCheck.utils.getError(name, location, apiCheck.array.type);\n }\n let copy = val.slice();\n const fn = copy.pop();\n const arrayOfStringsChecker = apiCheck.arrayOf(apiCheck.string);\n const notArrayOfStrings = arrayOfStringsChecker(copy);\n if (apiCheck.utils.isError(notArrayOfStrings)) {\n return apiCheck.utils.getError(name, location, arrayOfStringsChecker.type);\n }\n if (typeof fn !== 'function') {\n return apiCheck.utils.getError(name, location, apiCheck.func.type);\n }\n }, {type: 'angular injectable function (array syntax)'}, disabled);\n\n const types = [$injectProperty, arraySyntax];\n\n if (!strictDi) {\n types.push(apiCheck.func);\n }\n\n return apiCheck.oneOfType(types);\n}\n\n\n\n/** WEBPACK FOOTER **\n ** ../~/eslint-loader!./checkers/injectableFunction.js\n **/","import angular from 'angular-fix';\nimport apiCheckFactory from 'api-check';\nimport checkerFactories from './checkers';\n\nconst defaultOutput = {prefix: 'angular-scope-types'};\n\nexport default scopeTypesFactory;\n\nfunction scopeTypesFactory({\n disabled = false,\n output = defaultOutput,\n apiCheckInstance\n } = {\n disabled: false,\n output: defaultOutput,\n apiCheckInstance: undefined\n}) {\n const scopeTypes = apiCheckFactory({\n output: output,\n disabled\n });\n // manually adding checkers so we have an instance of scopeTypes to pass them.\n angular.forEach(checkerFactories, (factory, name) => {\n scopeTypes[name] = factory({scopeTypes, disabled});\n });\n\n scopeTypes.directive = validateDirective;\n\n apiCheckInstance = apiCheckInstance || scopeTypes;\n\n return scopeTypes;\n\n function validateDirective(ddo) {\n if (scopeTypes.config.disabled || apiCheckInstance.config.disabled) {\n return ddo;\n }\n scopeTypes.warn(scopeTypes.ddo, ddo, {prefix: 'creating directive with scopeTypes'});\n // Would really love to not have to extend the ddo's controller\n // like this. Suggestions welcome!\n ddo.controller = extendController(ddo.controller, scopeTypesController);\n\n scopeTypesController.$inject = ['$scope'];\n function scopeTypesController($scope) {\n var context = $scope;\n if (ddo.bindToController) {\n context = context[ddo.controllerAs];\n }\n\n let typeDefinitions = ddo.scopeTypes(apiCheckInstance);\n scopeTypes.warn(\n scopeTypes.objectOf(scopeTypes.func).optional,\n typeDefinitions,\n {prefix: `getting scope types for ${ddo.name}`}\n );\n\n $scope.$scopeTypesResults = {__passed: 0, __failed: 0};\n\n angular.forEach(typeDefinitions, (check, name) => {\n if (!angular.isDefined(context[name]) && check.isOptional) {\n let prefix = ddo.controllerAs ? ddo.controllerAs + '.' : '';\n const stopWatching = $scope.$watch(`${prefix}${name}`, (value, oldValue) => {\n if (value !== oldValue) {\n stopWatching();\n checkOption(check, name);\n }\n });\n } else {\n checkOption(check, name);\n }\n });\n\n\n function checkOption(checker, name) {\n $scope.$scopeTypesResults[name] = apiCheckInstance[ddo.scopeTypesFunction || 'warn'](\n checker, context[name], {prefix: `${ddo.name}Directive for \"${name}\"`}\n );\n updateData();\n }\n\n function updateData() {\n let passedCount = 0;\n let failedCount = 0;\n const ignore = ['__passed', '__failed'];\n angular.forEach($scope.$scopeTypesResults, (result, name) => {\n if (ignore.indexOf(name) === -1) {\n if (result.passed) {\n passedCount++;\n } else {\n failedCount++;\n }\n }\n });\n $scope.$scopeTypesResults.__passed = passedCount;\n $scope.$scopeTypesResults.__failed = failedCount;\n }\n\n }\n\n return ddo;\n\n\n function extendController(originalController, newController) {\n if (!angular.isDefined(originalController)) {\n return newController;\n }\n function wrappedController($scope, $controller, $element, $attrs, $transclude, $injector) {\n const locals = {$scope, $element, $attrs, $transclude};\n $injector.invoke(newController, this, locals);\n $injector.invoke(originalController, this, locals);\n }\n\n wrappedController.$inject = ['$scope', '$controller', '$element', '$attrs', '$transclude', '$injector'];\n wrappedController.displayName = getWrappedControllerDisplayName(originalController);\n return wrappedController;\n }\n\n function getWrappedControllerDisplayName(originalController) {\n const originalControllerName = originalController.displayName || originalController.name;\n let name = 'angular-scope-types controller wrapper';\n if (originalControllerName) {\n name = `${name} for ${originalControllerName}`;\n }\n return name;\n }\n }\n}\n\n\n\n/** WEBPACK FOOTER **\n ** ../~/eslint-loader!./scopeTypes.js\n **/","module.exports = __WEBPACK_EXTERNAL_MODULE_8__;\n\n\n/*****************\n ** WEBPACK FOOTER\n ** external \"angular\"\n ** module id = 8\n ** module chunks = 0\n **/"],"sourceRoot":""} -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | module.exports = require('kcd-common-tools/shared/karma.conf'); 2 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-scope-types", 3 | "version": "1.0.0-beta.7", 4 | "description": "checkers and other utilities for using api-check with angular", 5 | "main": "dist/angular-scope-types.js", 6 | "scripts": { 7 | "start": "npm run test", 8 | "test": "COVERAGE=true NODE_ENV=test karma start", 9 | "test:single": "COVERAGE=true NODE_ENV=test karma start --single-run", 10 | "test:debug": "echo 'WARNING: This is currently not working quite right...' && NODE_ENV=test karma start --browsers Chrome", 11 | "build:dist": "NODE_ENV=development webpack --config node_modules/kcd-common-tools/shared/webpack.config.js --progress --colors", 12 | "build:prod": "NODE_ENV=production webpack --config node_modules/kcd-common-tools/shared/webpack.config.js --progress --colors", 13 | "build": "npm run build:dist & npm run build:prod", 14 | "ci": "npm run code-checks && npm run test:single && npm run check-coverage && npm run build", 15 | "check-coverage": "./node_modules/istanbul/lib/cli.js check-coverage --statements 97 --branches 89 --functions 100 --lines 95", 16 | "report-coverage": "cat ./coverage/lcov.info | codecov", 17 | "deploy": "npm run deployClean && npm run deployCopy && npm run deploySurge", 18 | "deploySurge": "surge -p deploy.ignored -d angular-scope-types.surge.sh", 19 | "deployCopy": "cp demo/{index.html,script.js} deploy.ignored/ && cp dist/angular-scope-types.js deploy.ignored/ && cp node_modules/angular/angular.js deploy.ignored/ && cp node_modules/api-check/dist/api-check.js deploy.ignored/", 20 | "deployClean": "rm -rf deploy.ignored/ && mkdir deploy.ignored/", 21 | "only-check": "node node_modules/kcd-common-tools/shared/scripts/only-check.js", 22 | "code-checks": "eslint src/ && npm run only-check", 23 | "release": "npm run build && with-package git commit -am pkg.version && with-package git tag pkg.version && git push && npm publish && git push --tags", 24 | "release:beta": "npm run release && npm run tag:beta", 25 | "tag:beta": "with-package npm dist-tag add pkg.name@pkg.version beta" 26 | }, 27 | "repository": { 28 | "type": "git", 29 | "url": "https://github.com/alianza-dev/angular-scope-types.git" 30 | }, 31 | "keywords": [ 32 | "api-check", 33 | "angular-scope-types", 34 | "react propTypes", 35 | "angular scopeTypes", 36 | "angular", 37 | "angularjs", 38 | "apiCheck.js" 39 | ], 40 | "author": "Kent C. Dodds (http://kent.doddsfamily.us)", 41 | "contributors": [ 42 | "Kent C. Dodds (http://kent.doddsfamily.us)" 43 | ], 44 | "license": "MIT", 45 | "bugs": { 46 | "url": "https://github.com/alianza-dev/angular-scope-types/issues" 47 | }, 48 | "homepage": "https://github.com/alianza-dev/angular-scope-types", 49 | "config": { 50 | "ghooks": { 51 | "pre-commit": "npm run ci" 52 | } 53 | }, 54 | "peerDependencies": { 55 | "angular": "^1.2.x || >= 1.4.0-beta.0 || >= 1.5.0-beta.0", 56 | "api-check": "^7.2.0" 57 | }, 58 | "devDependencies": { 59 | "angular": "1.4.1", 60 | "angular-mocks": "1.4.1", 61 | "api-check": "7.5.0", 62 | "babel": "5.5.8", 63 | "babel-core": "5.5.8", 64 | "babel-eslint": "3.1.17", 65 | "babel-loader": "5.1.4", 66 | "chai": "2.1.0", 67 | "codecov.io": "0.1.4", 68 | "eslint": "0.23.0", 69 | "eslint-loader": "0.14.0", 70 | "ghooks": "0.2.4", 71 | "isparta": "3.0.3", 72 | "isparta-loader": "0.2.0", 73 | "istanbul": "0.3.5", 74 | "karma": "0.12.36", 75 | "karma-chai": "0.1.0", 76 | "karma-chrome-launcher": "0.1.12", 77 | "karma-coverage": "0.4.2", 78 | "karma-firefox-launcher": "0.1.6", 79 | "karma-mocha": "0.1.10", 80 | "karma-sinon": "1.0.4", 81 | "karma-webpack": "1.5.1", 82 | "kcd-common-tools": "1.0.0-beta.9", 83 | "lodash": "3.9.3", 84 | "mocha": "2.1.0", 85 | "node-libs-browser": "^0.5.2", 86 | "sinon": "1.15.3", 87 | "surge": "0.14.2", 88 | "uglify-loader": "1.2.0", 89 | "webpack": "1.9.11", 90 | "with-package": "0.2.0" 91 | }, 92 | "kcdCommon": { 93 | "webpack": "scripts/webpack-overrides.js", 94 | "karma": "scripts/karma-overrides.js" 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /scripts/karma-overrides.js: -------------------------------------------------------------------------------- 1 | var _ = require('lodash'); 2 | var here = require('kcd-common-tools/utils/here'); 3 | 4 | module.exports = function(defaultConfig) { 5 | defaultConfig.files = _.union([ 6 | here('./node_modules/angular/angular.js'), 7 | here('./node_modules/angular-mocks/angular-mocks.js'), 8 | here('./node_modules/api-check/dist/api-check.js') 9 | ], defaultConfig.files); 10 | return defaultConfig; 11 | }; 12 | -------------------------------------------------------------------------------- /scripts/webpack-overrides.js: -------------------------------------------------------------------------------- 1 | var here = require('kcd-common-tools/utils/here'); 2 | var _ = require('lodash'); 3 | module.exports = function(defaultConfig) { 4 | return _.merge(defaultConfig, { 5 | output: { 6 | library: 'angularScopeTypes', 7 | libraryTarget: 'umd' 8 | }, 9 | externals: { 10 | angular: 'angular', 11 | 'api-check': { 12 | root: 'apiCheck', 13 | amd: 'api-check', 14 | commonjs2: 'api-check', 15 | commonjs: 'api-check' 16 | } 17 | }, 18 | resolve: { 19 | alias: { 20 | 'angular-fix': here('src/angular-fix') 21 | } 22 | } 23 | }); 24 | }; 25 | -------------------------------------------------------------------------------- /src/angular-fix/index.js: -------------------------------------------------------------------------------- 1 | // some versions of angular don't export the angular module properly, 2 | // so we get it from window in this case. 3 | var angular = require('angular'); 4 | /* istanbul ignore next */ 5 | if (!angular.version) { 6 | angular = window.angular; 7 | } 8 | export default angular; 9 | -------------------------------------------------------------------------------- /src/checkers/checkerUtils.js: -------------------------------------------------------------------------------- 1 | function noopChecker() { 2 | } 3 | noopChecker.nullable = noopChecker; 4 | noopChecker.nullable.optional = noopChecker; 5 | 6 | export default {noopChecker}; 7 | -------------------------------------------------------------------------------- /src/checkers/ddo.js: -------------------------------------------------------------------------------- 1 | import checkerUtils from './checkerUtils'; 2 | 3 | export default function ddo({ 4 | scopeTypes, strictDi = false, disabled = false 5 | } = { 6 | strictDi: false, disabled: false 7 | }) { 8 | if (disabled) { 9 | return checkerUtils.noopChecker; 10 | } 11 | 12 | const check = scopeTypes; 13 | if (!check) { 14 | throw new Error('Must provide an instance of scopeTypes'); 15 | } 16 | const stringOrFunc = scopeTypes.oneOfType([check.string, check.func]); 17 | const ddoShape = check.shape({ 18 | priority: check.number.optional, 19 | template: check.shape.ifNot('templateUrl', stringOrFunc).optional, 20 | templateUrl: check.shape.ifNot('template', check.string).optional, 21 | transclude: check.bool.optional, 22 | restrict: check.oneOf(['A', 'E', 'C', 'AE', 'EA', 'AEC', 'AC', 'EC']).optional, 23 | replace: check.bool.optional, 24 | templateNamespace: check.oneOf(['html', 'svg', 'math']).optional, 25 | scope: check.oneOfType([check.bool, check.objectOf(check.string)]).optional, // TODO, make an advanced scope checker 26 | controller: check.injectableFunction.optional, 27 | controllerAs: check.string.optional, 28 | bindToController: check.oneOfType([check.bool, check.objectOf(check.string)]).optional, 29 | // TODO, tell the version of angular and use a scope checker for +1.4 30 | require: check.typeOrArrayOf(check.string).optional, // TODO make a pattern checker. 31 | // 'siblingDirectiveName', // or // ['^parentDirectiveName', '?optionalDirectiveName', '?^optionalParent'], 32 | compile: check.func.optional, 33 | link: check.oneOfType([ 34 | check.func, 35 | check.shape({ 36 | pre: check.func.optional, 37 | post: check.func.optional 38 | }).strict 39 | ]).optional, 40 | scopeTypes: check.func, 41 | scopeTypesFunction: check.oneOf(['warn', 'throw']).optional, 42 | data: check.object.optional 43 | }).strict; 44 | 45 | return check.oneOfType([check.func, ddoShape]); 46 | } 47 | -------------------------------------------------------------------------------- /src/checkers/ddo.test.js: -------------------------------------------------------------------------------- 1 | import {expectPass, expectFail, link, controllers} from '../test.utils'; 2 | import scopeTypesFactory from '../scopeTypes'; 3 | 4 | import ddoFactory from './ddo'; 5 | 6 | describe(`ddo checker`, () => { 7 | 8 | describe(`basic checker`, () => { 9 | let checker, scopeTypes; 10 | beforeEach(() => { 11 | scopeTypes = scopeTypesFactory(); 12 | checker = ddoFactory({scopeTypes}); 13 | }); 14 | 15 | it(`should pass with a link function`, () => { 16 | expectPass(checker(link)); 17 | }); 18 | 19 | it(`should fail when the DDO has extra stuff`, () => { 20 | expectFail(checker({ 21 | whatever: 'foo' 22 | })); 23 | }); 24 | 25 | it(`should pass when given a valid DDO`, () => { 26 | expectPass(checker({ 27 | template: 'Hello!', 28 | link, 29 | controllerAs: 'vm', 30 | controller: controllers.$inject, 31 | bindToController: true, 32 | replace: true, 33 | /* istanbul ignore next */ 34 | scopeTypes: st => ({foo: st.shape({})}) 35 | })); 36 | }); 37 | }); 38 | 39 | describe(`disabled`, () => { 40 | let checker, scopeTypes; 41 | beforeEach(() => { 42 | scopeTypes = scopeTypesFactory(); 43 | checker = ddoFactory({scopeTypes, disabled: true}); 44 | }); 45 | 46 | it(`should pass regardless of anything`, () => { 47 | expectPass(checker()); 48 | expectPass(checker('foo')); 49 | expectPass(checker(link)); 50 | expectPass(checker([])); 51 | }); 52 | }); 53 | }); 54 | -------------------------------------------------------------------------------- /src/checkers/index.js: -------------------------------------------------------------------------------- 1 | import injectableFunction from './injectableFunction'; 2 | import ddo from './ddo'; 3 | 4 | export default { 5 | injectableFunction, ddo 6 | }; 7 | -------------------------------------------------------------------------------- /src/checkers/index.test.js: -------------------------------------------------------------------------------- 1 | export * from './injectableFunction.test'; 2 | export * from './ddo.test'; 3 | -------------------------------------------------------------------------------- /src/checkers/injectableFunction.js: -------------------------------------------------------------------------------- 1 | import apiCheck from 'api-check'; 2 | 3 | export default function injectableFunction({strictDi = false, disabled = false} = {strictDi: false, disabled: false}) { 4 | const $injectProperty = apiCheck.func.withProperties({ 5 | $inject: apiCheck.arrayOf(apiCheck.string) 6 | }); 7 | 8 | const arraySyntax = apiCheck.utils.checkerHelpers.setupChecker(function arraySyntax(val, name, location) { 9 | if (!Array.isArray(val)) { 10 | return apiCheck.utils.getError(name, location, apiCheck.array.type); 11 | } 12 | let copy = val.slice(); 13 | const fn = copy.pop(); 14 | const arrayOfStringsChecker = apiCheck.arrayOf(apiCheck.string); 15 | const notArrayOfStrings = arrayOfStringsChecker(copy); 16 | if (apiCheck.utils.isError(notArrayOfStrings)) { 17 | return apiCheck.utils.getError(name, location, arrayOfStringsChecker.type); 18 | } 19 | if (typeof fn !== 'function') { 20 | return apiCheck.utils.getError(name, location, apiCheck.func.type); 21 | } 22 | }, {type: 'angular injectable function (array syntax)'}, disabled); 23 | 24 | const types = [$injectProperty, arraySyntax]; 25 | 26 | if (!strictDi) { 27 | types.push(apiCheck.func); 28 | } 29 | 30 | return apiCheck.oneOfType(types); 31 | } 32 | -------------------------------------------------------------------------------- /src/checkers/injectableFunction.test.js: -------------------------------------------------------------------------------- 1 | import {expect} from 'chai'; 2 | import {expectPass, expectFail, controllers} from '../test.utils'; 3 | import injectableFunction from './injectableFunction'; 4 | 5 | describe(`injectableFunction checker`, () => { 6 | 7 | describe(`basic checker info`, () => { 8 | let checker; 9 | beforeEach(() => { 10 | checker = injectableFunction(); 11 | }); 12 | 13 | it(`should have optional`, () => { 14 | expect(checker.optional).to.be.a('function'); 15 | }); 16 | 17 | it(`should have nullable with optional`, () => { 18 | expect(checker.nullable).to.be.a('function'); 19 | expect(checker.nullable.optional).to.be.a('function'); 20 | }); 21 | 22 | it(`should pass with $inject property`, () => { 23 | expectPass(checker(controllers.$inject)); 24 | }); 25 | 26 | it(`should pass with Array syntax`, () => { 27 | expectPass(checker(controllers.array)); 28 | }); 29 | 30 | it(`should fail when given an array with non-strings before the function`, () => { 31 | expectFail(checker(['foo', 23, controllers.regular])); 32 | }); 33 | 34 | it(`should fail when given an array with the function not last`, () => { 35 | expectFail(checker(['foo', controllers.regular, 'bar'])); 36 | }); 37 | 38 | it(`should fail when not given a function`, () => { 39 | expectFail(checker(['foo', 'baz', 'bar'])); 40 | }); 41 | }); 42 | 43 | describe(`strictDi: false`, () => { 44 | let checker; 45 | beforeEach(() => { 46 | checker = injectableFunction(); 47 | }); 48 | 49 | it(`should pass with a function`, () => { 50 | expectPass(checker(controllers.regular)); 51 | }); 52 | }); 53 | 54 | describe(`strictDi: true`, () => { 55 | let checker; 56 | beforeEach(() => { 57 | checker = injectableFunction({strictDi: true}); 58 | }); 59 | 60 | it(`should fail with a function`, () => { 61 | expectFail(checker(controllers.regular)); 62 | }); 63 | }); 64 | 65 | describe(`disabled: true`, () => { 66 | let checker; 67 | beforeEach(() => { 68 | checker = injectableFunction({disabled: true}); 69 | }); 70 | 71 | it(`should succeed in any case`, () => { 72 | expectPass(checker('foo')); 73 | expectPass(checker(controllers.regular)); 74 | }); 75 | }); 76 | 77 | }); 78 | 79 | 80 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import scopeTypes from './scopeTypes'; 2 | 3 | export default scopeTypes; 4 | 5 | -------------------------------------------------------------------------------- /src/index.test.js: -------------------------------------------------------------------------------- 1 | export * from './checkers/index.test'; 2 | export * from './scopeTypes.test'; 3 | -------------------------------------------------------------------------------- /src/scopeTypes.js: -------------------------------------------------------------------------------- 1 | import angular from 'angular-fix'; 2 | import apiCheckFactory from 'api-check'; 3 | import checkerFactories from './checkers'; 4 | 5 | const defaultOutput = {prefix: 'angular-scope-types'}; 6 | 7 | export default scopeTypesFactory; 8 | 9 | function scopeTypesFactory({ 10 | disabled = false, 11 | output = defaultOutput, 12 | apiCheckInstance 13 | } = { 14 | disabled: false, 15 | output: defaultOutput, 16 | apiCheckInstance: undefined 17 | }) { 18 | const scopeTypes = apiCheckFactory({ 19 | output: output, 20 | disabled 21 | }); 22 | // manually adding checkers so we have an instance of scopeTypes to pass them. 23 | angular.forEach(checkerFactories, (factory, name) => { 24 | scopeTypes[name] = factory({scopeTypes, disabled}); 25 | }); 26 | 27 | scopeTypes.directive = validateDirective; 28 | 29 | apiCheckInstance = apiCheckInstance || scopeTypes; 30 | 31 | return scopeTypes; 32 | 33 | function validateDirective(ddo) { 34 | if (scopeTypes.config.disabled || apiCheckInstance.config.disabled) { 35 | return ddo; 36 | } 37 | scopeTypes.warn(scopeTypes.ddo, ddo, {prefix: 'creating directive with scopeTypes'}); 38 | // Would really love to not have to extend the ddo's controller 39 | // like this. Suggestions welcome! 40 | ddo.controller = extendController(ddo.controller, scopeTypesController); 41 | 42 | scopeTypesController.$inject = ['$scope']; 43 | function scopeTypesController($scope) { 44 | var context = $scope; 45 | if (ddo.bindToController) { 46 | context = context[ddo.controllerAs]; 47 | } 48 | 49 | let typeDefinitions = ddo.scopeTypes(apiCheckInstance); 50 | scopeTypes.warn( 51 | scopeTypes.objectOf(scopeTypes.func).optional, 52 | typeDefinitions, 53 | {prefix: `getting scope types for ${ddo.name}`} 54 | ); 55 | 56 | $scope.$scopeTypesResults = {__passed: 0, __failed: 0}; 57 | 58 | angular.forEach(typeDefinitions, (check, name) => { 59 | if (!angular.isDefined(context[name]) && check.isOptional) { 60 | let prefix = ddo.controllerAs ? ddo.controllerAs + '.' : ''; 61 | const stopWatching = $scope.$watch(`${prefix}${name}`, (value, oldValue) => { 62 | if (value !== oldValue) { 63 | stopWatching(); 64 | checkOption(check, name); 65 | } 66 | }); 67 | } else { 68 | checkOption(check, name); 69 | } 70 | }); 71 | 72 | 73 | function checkOption(checker, name) { 74 | $scope.$scopeTypesResults[name] = apiCheckInstance[ddo.scopeTypesFunction || 'warn']( 75 | checker, context[name], {prefix: `${ddo.name}Directive for "${name}"`} 76 | ); 77 | updateData(); 78 | } 79 | 80 | function updateData() { 81 | let passedCount = 0; 82 | let failedCount = 0; 83 | const ignore = ['__passed', '__failed']; 84 | angular.forEach($scope.$scopeTypesResults, (result, name) => { 85 | if (ignore.indexOf(name) === -1) { 86 | if (result.passed) { 87 | passedCount++; 88 | } else { 89 | failedCount++; 90 | } 91 | } 92 | }); 93 | $scope.$scopeTypesResults.__passed = passedCount; 94 | $scope.$scopeTypesResults.__failed = failedCount; 95 | } 96 | 97 | } 98 | 99 | return ddo; 100 | 101 | 102 | function extendController(originalController, newController) { 103 | if (!angular.isDefined(originalController)) { 104 | return newController; 105 | } 106 | function wrappedController($scope, $controller, $element, $attrs, $transclude, $injector) { 107 | const locals = {$scope, $element, $attrs, $transclude}; 108 | $injector.invoke(newController, this, locals); 109 | $injector.invoke(originalController, this, locals); 110 | } 111 | 112 | wrappedController.$inject = ['$scope', '$controller', '$element', '$attrs', '$transclude', '$injector']; 113 | wrappedController.displayName = getWrappedControllerDisplayName(originalController); 114 | return wrappedController; 115 | } 116 | 117 | function getWrappedControllerDisplayName(originalController) { 118 | const originalControllerName = originalController.displayName || originalController.name; 119 | let name = 'angular-scope-types controller wrapper'; 120 | if (originalControllerName) { 121 | name = `${name} for ${originalControllerName}`; 122 | } 123 | return name; 124 | } 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/scopeTypes.test.js: -------------------------------------------------------------------------------- 1 | /* eslint no-console:0 */ 2 | /* eslint max-nested-callbacks:0 */ 3 | import {expect} from 'chai'; 4 | import angular from 'angular-fix'; 5 | import apiCheck from 'api-check'; 6 | 7 | import scopeTypesFactory from './scopeTypes'; 8 | 9 | describe(`scopeTypes`, () => { 10 | let scopeTypes, originalWarn, warnings; 11 | beforeEach(() => { 12 | warnings = []; 13 | originalWarn = console.warn; 14 | console.warn = fakeWarn; 15 | scopeTypes = scopeTypesFactory(); 16 | }); 17 | 18 | describe(`directive`, () => { 19 | it(`should fail when the DDO has extra stuff`, () => { 20 | scopeTypes.directive({ 21 | whatever: 'foo' 22 | }); 23 | expectWarning(/whatever(.|\n)*?foo/); 24 | }); 25 | 26 | describe(`creating directives`, () => { 27 | let scope, el; 28 | 29 | const basicTemplate = ''; 30 | 31 | it(`should allow me to create a type checked directive`, () => { 32 | createDirective(); 33 | compileAndDigest({ 34 | baz: 'hi', 35 | foo: {isFoo: true, isBar: false, someNum: 23} 36 | }); 37 | expectNoWarning(); 38 | }); 39 | 40 | it(`should warn me when I pass something wrong to the directive`, () => { 41 | createDirective(); 42 | compileAndDigest({ 43 | baz: 'hi', 44 | foo: {isFoo: 'not a boolean', isBar: false, someNum: 23} 45 | }); 46 | expectWarning(/not a boolean/); 47 | }); 48 | 49 | it(`should warn if something that is not optional is not passed`, () => { 50 | createDirective(); 51 | compileAndDigest({ 52 | // missing baz 53 | }); 54 | expectWarning(/Required/); 55 | }); 56 | 57 | 58 | it(`should be able to be disabled`, () => { 59 | const myDisabledScopeTypes = scopeTypesFactory({disabled: true}); 60 | const myDirName = 'dirName'; 61 | const controller = sinon.spy(); 62 | const scopeTypesSpy = sinon.spy(getScopeTypes); 63 | createDirective(myDirName, {controller}, myDisabledScopeTypes); 64 | 65 | compileAndDigest({ 66 | baz: 'hi' 67 | }, ''); 68 | 69 | angular.mock.inject(['$injector', $injector => { 70 | const ddo = $injector.get(`${myDirName}Directive`); 71 | 72 | expect(ddo[0].controller).to.eq(controller); 73 | expect(controller).to.have.been.called; 74 | expect(scopeTypesSpy).to.not.have.been.called; 75 | expectNoWarning(); 76 | }]); 77 | }); 78 | 79 | it(`should still allow the directive controller to use it's controller as`, () => { 80 | createDirective(undefined, { 81 | controller, 82 | controllerAs: 'vm', 83 | bindToController: true 84 | }); 85 | 86 | function controller() { 87 | const vm = this; 88 | 89 | expect(vm.bar).to.eq('barString'); 90 | } 91 | compileAndDigest({baz: 'hey'}); 92 | expectNoWarning(); 93 | }); 94 | 95 | it(`should allow you to pass your own instance of an apiCheck`, () => { 96 | const myApiCheck = apiCheck({}); 97 | const myScopeTypes = scopeTypesFactory({apiCheckInstance: myApiCheck}); 98 | const myDirName = 'dirName'; 99 | const scopeTypesSpy = sinon.spy(); 100 | createDirective(myDirName, {scope: {}, scopeTypes: scopeTypesSpy}, myScopeTypes); 101 | compileAndDigest({}, ''); 102 | angular.mock.inject(['$injector', $injector => { 103 | expect(scopeTypesSpy).to.have.been.called; 104 | expectNoWarning(); 105 | }]); 106 | }); 107 | 108 | it(`should allow you to pass your own scopeTypesFunction function`, () => { 109 | createDirective(undefined, {scopeTypesFunction: 'throw'}); 110 | expect(() => compileAndDigest({})).to.throw(); 111 | expectNoWarning(); 112 | }); 113 | 114 | function createDirective(name, definition, scopeTypesInstance = scopeTypes) { 115 | angular.mock.module(['$provide', '$compileProvider', function($provide, $compileProvider) { 116 | $provide.constant('myScopeTypes', scopeTypesInstance); 117 | $compileProvider.directive(name || 'scopeTypeDir', ['myScopeTypes', function(myScopeTypes) { 118 | return myScopeTypes.directive(angular.extend({ 119 | template: 'foo', 120 | scope: {foo: '=', bar: '@', baz: '='}, 121 | scopeTypes: getScopeTypes, 122 | controllerAs: 'vm', 123 | bindToController: true, 124 | controller: angular.noop 125 | }, definition)); 126 | }]); 127 | }]); 128 | } 129 | 130 | 131 | function compileAndDigest(extraProps = {}, template = basicTemplate) { 132 | angular.mock.inject(['$compile', '$rootScope', ($compile, $rootScope) => { 133 | scope = $rootScope.$new(); 134 | angular.extend(scope, extraProps); 135 | el = $compile(template)(scope); 136 | scope.$digest(); 137 | }]); 138 | return el; 139 | } 140 | 141 | function getScopeTypes(st) { 142 | return { 143 | foo: st.shape({ 144 | isFoo: st.bool, 145 | isBar: st.bool, 146 | someNum: st.number, 147 | someOptional: st.object.optional 148 | }).strict.optional, 149 | bar: st.oneOf(['fooString', 'barString']).optional, 150 | baz: st.string 151 | }; 152 | } 153 | }); 154 | }); 155 | 156 | afterEach(() => { 157 | console.warn = originalWarn; 158 | }); 159 | 160 | function fakeWarn() { 161 | warnings.push(arguments); 162 | } 163 | 164 | function expectWarning(warning) { 165 | if (!warnings.length) { 166 | throw new Error('Expected a warning, but non was logged'); 167 | } 168 | expect(warnings[0]).to.have.length(1); 169 | expect(warnings[0][0]).to.match(warning); 170 | } 171 | 172 | function expectNoWarning() { 173 | if (warnings.length) { 174 | console.log(warnings); 175 | throw new Error('Expected no warning to be logged, but one was'); 176 | } 177 | } 178 | 179 | }); 180 | -------------------------------------------------------------------------------- /src/test.utils.js: -------------------------------------------------------------------------------- 1 | import {expect} from 'chai'; 2 | 3 | /* istanbul ignore next */ 4 | const controllers = { 5 | regular: function RegularCtrl() { 6 | }, 7 | array: ['foo', function ArrayCtrl(foo) { 8 | }], 9 | $inject: function $InjectCtrl(bar) { 10 | } 11 | }; 12 | controllers.$inject.$inject = ['bar']; 13 | 14 | export {expectPass, expectFail, link, controllers}; 15 | 16 | 17 | function expectPass(val) { 18 | expect(val).to.be.undefined; 19 | } 20 | 21 | function expectFail(val) { 22 | expect(val).to.be.an.instanceOf(Error); 23 | } 24 | 25 | /* istanbul ignore next */ 26 | function link(scope, el, attrs, ctrl, transclude) { 27 | } 28 | 29 | 30 | --------------------------------------------------------------------------------