Skip to content

Commit

Permalink
🛠 Refactor: Split RNIDictionarySynthesizable
Browse files Browse the repository at this point in the history
Summary: Extract extension in `RNIDictionarySynthesizable` into its own file in `os/src_library/React Native/RNIDictionarySynthesizable/RNIDictionarySynthesizable+Default`.

empty
  • Loading branch information
dominicstop committed Apr 26, 2023
1 parent 7002f39 commit 2573bb0
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 83 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
//
// RNIDictionarySynthesizable+Default.swift
// react-native-ios-modal
//
// Created by Dominic Go on 4/27/23.
//

import Foundation

extension RNIDictionarySynthesizable {

// MARK: - Static Properties
// -------------------------

public static var synthesizedDictionaryIgnore: [String] {
[];
};

public static var synthesizedDictionaryInlinedProperties: [PartialKeyPath<Self>] {
[];
};

// MARK: - Static Functions
// ------------------------

fileprivate static func recursivelyParseValue(
_ value: Any,
isJSDict: Bool
) -> Any {

if let synthesizableDict = value as? (any RNIDictionarySynthesizable) {
return synthesizableDict.synthesizedDictionary(isJSDict: isJSDict);

} else if isJSDict, let rawValue = value as? any RawRepresentable {
return rawValue.rawValue;

} else if isJSDict, let array = value as? Array<Any> {
return array.map {
return Self.recursivelyParseValue($0, isJSDict: isJSDict);
};
};

return value;
};

// MARK: - Public Functions
// ------------------------

public func synthesizedDictionary(
isJSDict: Bool
) -> Dictionary<String, Any> {

let mirror = Mirror(reflecting: self);
let properties = mirror.children;

#if DEBUG
/// Runtime Check - Verify if `synthesizedDictionaryIgnore` is valid
for propertyKeyToIgnore in Self.synthesizedDictionaryIgnore {
if !properties.contains(where: { $0.label == propertyKeyToIgnore }) {
fatalError(
"Invalid value of '\(propertyKeyToIgnore)' in "
+ "'synthesizedDictionaryIgnore' for '\(Self.self)' - "
+ "No property named '\(propertyKeyToIgnore)' in '\(Self.self)'"
);
};
};
#endif

let propertyValueMap = properties.lazy.map { (
propertyKey: String?, value: Any) -> (String, Any)? in

guard let propertyKey = propertyKey,
!Self.synthesizedDictionaryIgnore.contains(propertyKey)
else { return nil };

let parsedValue = Self.recursivelyParseValue(value, isJSDict: isJSDict);
return (propertyKey, parsedValue);
};

var baseDict = Dictionary(
uniqueKeysWithValues: propertyValueMap.compactMap { $0 }
);

Self.synthesizedDictionaryInlinedProperties.forEach {
guard let value = self[keyPath: $0] as? (any RNIDictionarySynthesizable)
else { return };

let inlinedDict = value.synthesizedDictionary(isJSDict: isJSDict);
baseDict = baseDict.merging(inlinedDict){ old, _ in old };
};

return baseDict;
};

public var synthesizedJSDictionary: Dictionary<String, Any> {
self.synthesizedDictionary(isJSDict: true);
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -7,99 +7,23 @@

import Foundation


/// Any type that conforms to this protocol will be able to create a dictionary
/// representing the keys and values inside that type
///
public protocol RNIDictionarySynthesizable {

/// The names/identifiers of the property to be ignored when
/// `synthesizedDictionary` is created.
///
static var synthesizedDictionaryIgnore: [String] { get };

/// The key path to the property that will be inlined/"squashed together" into
/// `synthesizedDictionary`.
/// The key path to the property that will be inlined/"squashed together"
/// into `synthesizedDictionary`.
///
static var synthesizedDictionaryInlinedProperties: [PartialKeyPath<Self>] { get };
static var synthesizedDictionaryInlinedProperties:
[PartialKeyPath<Self>] { get };

/// A map of the property names and their respective values
func synthesizedDictionary(isJSDict: Bool) -> Dictionary<String, Any>;
};

extension RNIDictionarySynthesizable {

public static var synthesizedDictionaryIgnore: [String] {
[];
};

public static var synthesizedDictionaryInlinedProperties: [PartialKeyPath<Self>] {
[];
};

fileprivate static func recursivelyParseValue(
_ value: Any,
isJSDict: Bool
) -> Any {

if let synthesizableDict = value as? (any RNIDictionarySynthesizable) {
return synthesizableDict.synthesizedDictionary(isJSDict: isJSDict);

} else if isJSDict, let rawValue = value as? any RawRepresentable {
return rawValue.rawValue;

} else if isJSDict, let array = value as? Array<Any> {
return array.map {
return Self.recursivelyParseValue($0, isJSDict: isJSDict);
};
};

return value;
};

public func synthesizedDictionary(
isJSDict: Bool
) -> Dictionary<String, Any> {

let mirror = Mirror(reflecting: self);
let properties = mirror.children;

#if DEBUG
for propertyKeyToIgnore in Self.synthesizedDictionaryIgnore {
if !properties.contains(where: { $0.label == propertyKeyToIgnore }) {
fatalError(
"Invalid value of '\(propertyKeyToIgnore)' in "
+ "'synthesizedDictionaryIgnore' for '\(Self.self)' - "
+ "No property named '\(propertyKeyToIgnore)' in '\(Self.self)'"
);
};
};
#endif

let propertyValueMap = properties.lazy.map { (
propertyKey: String?, value: Any) -> (String, Any)? in

guard let propertyKey = propertyKey,
!Self.synthesizedDictionaryIgnore.contains(propertyKey)
else { return nil };

let parsedValue = Self.recursivelyParseValue(value, isJSDict: isJSDict);
return (propertyKey, parsedValue)
};

var baseDict = Dictionary(
uniqueKeysWithValues: propertyValueMap.compactMap { $0 }
);

Self.synthesizedDictionaryInlinedProperties.forEach {
guard let value = self[keyPath: $0] as? (any RNIDictionarySynthesizable)
else { return };

let inlinedDict = value.synthesizedDictionary(isJSDict: isJSDict);
baseDict = baseDict.merging(inlinedDict){ old, _ in old };
};

return baseDict;
};

public var synthesizedJSDictionary: Dictionary<String, Any> {
self.synthesizedDictionary(isJSDict: true);
};
};

0 comments on commit 2573bb0

Please sign in to comment.