Skip to content

Commit 8a2487c

Browse files
committed
Add input validation to modifier methods
Add isFinite checks to prevent crashes from NaN/Infinity values.
1 parent d7a72e1 commit 8a2487c

2 files changed

Lines changed: 346 additions & 1 deletion

File tree

Sources/HeroModifier.swift

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ extension HeroModifier {
5454
- position: position for the view to animate from/to
5555
*/
5656
public static func position(_ position: CGPoint) -> HeroModifier {
57+
guard position.x.isFinite, position.y.isFinite else {
58+
assertionFailure("Hero: Invalid position values (NaN or Infinity). Position: \(position)")
59+
return HeroModifier { _ in }
60+
}
5761
return HeroModifier { targetState in
5862
targetState.position = position
5963
}
@@ -65,6 +69,10 @@ extension HeroModifier {
6569
- size: size for the view to animate from/to
6670
*/
6771
public static func size(_ size: CGSize) -> HeroModifier {
72+
guard size.width.isFinite, size.height.isFinite else {
73+
assertionFailure("Hero: Invalid size values (NaN or Infinity). Size: \(size)")
74+
return HeroModifier { _ in }
75+
}
6876
return HeroModifier { targetState in
6977
targetState.size = size
7078
}
@@ -90,6 +98,10 @@ extension HeroModifier {
9098
- perspective: set the camera distance of the transform
9199
*/
92100
public static func perspective(_ perspective: CGFloat) -> HeroModifier {
101+
guard perspective.isFinite, perspective != 0 else {
102+
assertionFailure("Hero: Invalid perspective value (NaN, Infinity, or zero). Perspective: \(perspective)")
103+
return HeroModifier { _ in }
104+
}
93105
return HeroModifier { targetState in
94106
var transform = targetState.transform ?? CATransform3DIdentity
95107
transform.m34 = 1.0 / -perspective
@@ -105,6 +117,10 @@ extension HeroModifier {
105117
- z: scale factor on z axis, default 1
106118
*/
107119
public static func scale(x: CGFloat = 1, y: CGFloat = 1, z: CGFloat = 1) -> HeroModifier {
120+
guard x.isFinite, y.isFinite, z.isFinite else {
121+
assertionFailure("Hero: Invalid scale values (NaN or Infinity). x: \(x), y: \(y), z: \(z)")
122+
return HeroModifier { _ in }
123+
}
108124
return HeroModifier { targetState in
109125
targetState.transform = CATransform3DScale(targetState.transform ?? CATransform3DIdentity, x, y, z)
110126
}
@@ -127,6 +143,10 @@ extension HeroModifier {
127143
- z: translation distance on z axis in display pixel, default 0
128144
*/
129145
public static func translate(x: CGFloat = 0, y: CGFloat = 0, z: CGFloat = 0) -> HeroModifier {
146+
guard x.isFinite, y.isFinite, z.isFinite else {
147+
assertionFailure("Hero: Invalid translate values (NaN or Infinity). x: \(x), y: \(y), z: \(z)")
148+
return HeroModifier { _ in }
149+
}
130150
return HeroModifier { targetState in
131151
targetState.transform = CATransform3DTranslate(targetState.transform ?? CATransform3DIdentity, x, y, z)
132152
}
@@ -144,6 +164,10 @@ extension HeroModifier {
144164
- z: rotation on z axis in radian, default 0
145165
*/
146166
public static func rotate(x: CGFloat = 0, y: CGFloat = 0, z: CGFloat = 0) -> HeroModifier {
167+
guard x.isFinite, y.isFinite, z.isFinite else {
168+
assertionFailure("Hero: Invalid rotate values (NaN or Infinity). x: \(x), y: \(y), z: \(z)")
169+
return HeroModifier { _ in }
170+
}
147171
return HeroModifier { targetState in
148172
targetState.transform = CATransform3DRotate(targetState.transform ?? CATransform3DIdentity, x, 1, 0, 0)
149173
targetState.transform = CATransform3DRotate(targetState.transform!, y, 0, 1, 0)
@@ -342,10 +366,18 @@ extension HeroModifier {
342366
Sets the duration of the animation for a given view. If not used, Hero will use determine the duration based on the distance and size changes.
343367
- Parameters:
344368
- duration: duration of the animation
345-
369+
346370
Note: a duration of .infinity means matching the duration of the longest animation. same as .durationMatchLongest
347371
*/
348372
public static func duration(_ duration: TimeInterval) -> HeroModifier {
373+
guard duration.isFinite || duration == .infinity else {
374+
assertionFailure("Hero: Invalid duration value (NaN). Duration: \(duration)")
375+
return HeroModifier { _ in }
376+
}
377+
guard duration >= 0 else {
378+
assertionFailure("Hero: Duration must be non-negative. Duration: \(duration)")
379+
return HeroModifier { _ in }
380+
}
349381
return HeroModifier { targetState in
350382
targetState.duration = duration
351383
}
@@ -364,6 +396,14 @@ extension HeroModifier {
364396
- delay: delay of the animation
365397
*/
366398
public static func delay(_ delay: TimeInterval) -> HeroModifier {
399+
guard delay.isFinite else {
400+
assertionFailure("Hero: Invalid delay value (NaN or Infinity). Delay: \(delay)")
401+
return HeroModifier { _ in }
402+
}
403+
guard delay >= 0 else {
404+
assertionFailure("Hero: Delay must be non-negative. Delay: \(delay)")
405+
return HeroModifier { _ in }
406+
}
367407
return HeroModifier { targetState in
368408
targetState.delay = delay
369409
}
@@ -439,6 +479,10 @@ extension HeroModifier {
439479
default is 1.
440480
*/
441481
public static func arc(intensity: CGFloat = 1) -> HeroModifier {
482+
guard intensity.isFinite else {
483+
assertionFailure("Hero: Invalid arc intensity value (NaN or Infinity). Intensity: \(intensity)")
484+
return HeroModifier { _ in }
485+
}
442486
return HeroModifier { targetState in
443487
targetState.arc = intensity
444488
}

0 commit comments

Comments
 (0)