1010 splice,
1111 push,
1212 toString,
13+ objectMaxDepthInErrorMessage,
14+ errorHandlingConfig,
15+ isValidObjectMaxDepth,
1316 ngMinErr,
1417 angularModule,
1518 uid,
@@ -125,6 +128,50 @@ var VALIDITY_STATE_PROPERTY = 'validity';
125128
126129var hasOwnProperty = Object . prototype . hasOwnProperty ;
127130
131+ var objectMaxDepthInErrorMessage = 5 ;
132+
133+ /**
134+ * @ngdoc function
135+ * @name angular.errorHandlingConfig
136+ * @module ng
137+ * @kind function
138+ *
139+ * @description
140+ * Configure several aspects of error handling in AngularJS if used as a setter or return the
141+ * current configuration if used as a getter. The following options are supported:
142+ *
143+ * - **objectMaxDepth**: The maximum depth to which objects are traversed when stringified for error messages.
144+ *
145+ * Omitted or undefined options will leave the corresponding configuration values unchanged.
146+ *
147+ * @param {Object= } config - The configuration object. May only contain the options that need to be
148+ * updated. Supported keys:
149+ *
150+ * * `objectMaxDepth` **{Number}** - The max depth for stringifying objects. Setting to a
151+ * non-positive or non-numeric value, removes the max depth limit.
152+ * Default: 5
153+ */
154+ function errorHandlingConfig ( config ) {
155+ if ( isObject ( config ) ) {
156+ if ( isDefined ( config . objectMaxDepth ) ) {
157+ objectMaxDepthInErrorMessage = isValidObjectMaxDepth ( config . objectMaxDepth ) ? config . objectMaxDepth : NaN ;
158+ }
159+ } else {
160+ return {
161+ objectMaxDepth : objectMaxDepthInErrorMessage
162+ } ;
163+ }
164+ }
165+
166+ /**
167+ * @private
168+ * @param {Number } maxDepth
169+ * @return {boolean }
170+ */
171+ function isValidObjectMaxDepth ( maxDepth ) {
172+ return isNumber ( maxDepth ) && maxDepth > 0 ;
173+ }
174+
128175/**
129176 * @ngdoc function
130177 * @name angular.lowercase
@@ -796,6 +843,7 @@ function arrayRemove(array, value) {
796843 * are deleted and then all elements/properties from the source are copied to it.
797844 * * If `source` is not an object or array (inc. `null` and `undefined`), `source` is returned.
798845 * * If `source` is identical to `destination` an exception will be thrown.
846+ * * If `maxDepth` is supplied, all properties of the source will be copied until reaching the max depth.
799847 *
800848 * <br />
801849 * <div class="alert alert-warning">
@@ -807,6 +855,7 @@ function arrayRemove(array, value) {
807855 * Can be any type, including primitives, `null`, and `undefined`.
808856 * @param {(Object|Array)= } destination Destination into which the source is copied. If
809857 * provided, must be of the same type as `source`.
858+ * @param {Number= } maxDepth All properties of the source will be copied until reaching the max depth.
810859 * @returns {* } The copy or updated `destination`, if `destination` was specified.
811860 *
812861 * @example
@@ -847,9 +896,10 @@ function arrayRemove(array, value) {
847896 </file>
848897 </example>
849898 */
850- function copy ( source , destination ) {
899+ function copy ( source , destination , maxDepth ) {
851900 var stackSource = [ ] ;
852901 var stackDest = [ ] ;
902+ maxDepth = isValidObjectMaxDepth ( maxDepth ) ? maxDepth : NaN ;
853903
854904 if ( destination ) {
855905 if ( isTypedArray ( destination ) || isArrayBuffer ( destination ) ) {
@@ -872,43 +922,47 @@ function copy(source, destination) {
872922
873923 stackSource . push ( source ) ;
874924 stackDest . push ( destination ) ;
875- return copyRecurse ( source , destination ) ;
925+ return copyRecurse ( source , destination , maxDepth ) ;
876926 }
877927
878- return copyElement ( source ) ;
928+ return copyElement ( source , maxDepth ) ;
879929
880- function copyRecurse ( source , destination ) {
930+ function copyRecurse ( source , destination , maxDepth ) {
931+ maxDepth -- ;
932+ if ( maxDepth < 0 ) {
933+ return '...' ;
934+ }
881935 var h = destination . $$hashKey ;
882936 var key ;
883937 if ( isArray ( source ) ) {
884938 for ( var i = 0 , ii = source . length ; i < ii ; i ++ ) {
885- destination . push ( copyElement ( source [ i ] ) ) ;
939+ destination . push ( copyElement ( source [ i ] , maxDepth ) ) ;
886940 }
887941 } else if ( isBlankObject ( source ) ) {
888942 // createMap() fast path --- Safe to avoid hasOwnProperty check because prototype chain is empty
889943 for ( key in source ) {
890- destination [ key ] = copyElement ( source [ key ] ) ;
944+ destination [ key ] = copyElement ( source [ key ] , maxDepth ) ;
891945 }
892946 } else if ( source && typeof source . hasOwnProperty === 'function' ) {
893947 // Slow path, which must rely on hasOwnProperty
894948 for ( key in source ) {
895949 if ( source . hasOwnProperty ( key ) ) {
896- destination [ key ] = copyElement ( source [ key ] ) ;
950+ destination [ key ] = copyElement ( source [ key ] , maxDepth ) ;
897951 }
898952 }
899953 } else {
900954 // Slowest path --- hasOwnProperty can't be called as a method
901955 for ( key in source ) {
902956 if ( hasOwnProperty . call ( source , key ) ) {
903- destination [ key ] = copyElement ( source [ key ] ) ;
957+ destination [ key ] = copyElement ( source [ key ] , maxDepth ) ;
904958 }
905959 }
906960 }
907961 setHashKey ( destination , h ) ;
908962 return destination ;
909963 }
910964
911- function copyElement ( source ) {
965+ function copyElement ( source , maxDepth ) {
912966 // Simple values
913967 if ( ! isObject ( source ) ) {
914968 return source ;
@@ -937,7 +991,7 @@ function copy(source, destination) {
937991 stackDest . push ( destination ) ;
938992
939993 return needsRecurse
940- ? copyRecurse ( source , destination )
994+ ? copyRecurse ( source , destination , maxDepth )
941995 : destination ;
942996 }
943997
0 commit comments