A tool for generating immutable model objects

Overview

Plank logo

Plank

Plank is a command-line tool for generating robust immutable models from JSON Schemas. It will save you time writing boilerplate and eliminate model errors as your application scales in complexity.

We currently support the following languages:

Schema-defined

Models are defined in JSON, a well-defined, extensible and language-independent specification.

Immutable Classes

Model classes are generated to be immutable. Each class provides a “Builder” class to handle mutation.

Type safe

Based on the type information specified in the schema definition, each class provides type validation and null reference checks to ensure model integrity.

Installation

MacOS

$ brew install plank

Linux

Plank supports building in Ubuntu Linux via Docker. The Dockerfile in the repository will fetch the most recent release of plank and build dependencies including the Swift snapshot.

$ docker build -t plank .

Build from source

Plank is built using the Swift Package Manager. Although you’ll be able to build Plank using swift build directly, for distribution of the binary we’d recommend using the commands in the Makefile since they will pass the necessary flags to bundle the Swift runtime.

$ make archive

Getting Started

Keep reading to learn about Plank’s features or get your try it yourself with the tutorial.

Defining a schema

Plank takes a schema file as an input. Schemas are based on JSON, a well-defined, extensible and language-independent specification. Defining schemas in JSON allowed us to avoid writing unnecessary parser code and opened up the possibility of generating code from the same type system used on the server.

{
    "id": "pin.json",
    "title": "pin",
    "description" : "Schema definition of a Pin",
    "$schema": "http://json-schema.org/schema#",
    "type": "object",
    "properties": {
        "id": { "type": "string" },
        "link": { "type": "string", "format": "uri"}
    }
}

You’ll notice we specify the name of the model and a list of its properties. Note that link specifies an additional format attribute which tells Plank to use a more concrete type like NSURL or NSDate.

Generating a model

Generate a schema file (pin.json) using Plank using the format plank [options] file1 file2 file3 ...

$ plank pin.json

This will generate files (Pin.h, Pin.m) in the current directory:

$ ls
pin.json Pin.h Pin.m

Learn more about usage on the installation page.

Generated Output

Plank will generate the necessary header and implementation file for your schema definition. Here is the output of the Pin.h header.

@interface Pin
@property (nonatomic, copy, readonly) NSString *identifier;
@property (nonatomic, strong, readonly) NSURL *link;
@end

All properties are readonly, as this makes the class immutable. Populating instances of your model with values is performed by builder classes.

Mutations through builders

Model mutations are performed through a builder class. The builder class is a separate type which contains readwrite properties and a build method that will create a new object. Here is the header of the builder that Plank generated for the Pin model:

@interface PinBuilder
@property (nonatomic, copy, readwrite) NSString *identifier;
@property (nonatomic, strong, readwrite) NSURL *link;
- (Pin *)build;
@end

@interface Pin (BuilderAdditions)
- (instancetype)initWithBuilder:(PinBuilder *)builder;
@end

JSON parsing

Plank will create an initializer method called initWithModelDictionary: that handles parsing NSDictionary objects that conform to your schema. The generated implementation will perform validation checks based on the schema’s types, avoiding the dreaded [NSNull null] showing up in your objects:

@interface Pin (JSON)
- (instancetype)initWithModelDictionary:(NSDictionary *)dictionary;
@end

Serialization

All Plank generated models implement methods to conform to NSSecureCoding, providing native serialization support out of the box.

+ (BOOL)supportsSecureCoding {
    return YES;
}

- (instancetype)initWithCoder:(NSCoder *)aDecoder {
    if (!(self = [super init])) { return self; }
    _identifier = [aDecoder decodeObjectOfClass:[NSString class] forKey:@"identifier"];
    _link = [aDecoder decodeObjectOfClass:[NSURL class] forKey:@"link"];
    return self;
}

- (void)encodeWithCoder:(NSCoder *)aCoder {
    [aCoder encodeObject:self.identifier forKey:@"identifier"];
    [aCoder encodeObject:self.link forKey:@"link"];
}

With this implementation objects are serialized using NSKeyedArchiver:

// Create a pin from a server response
Pin *pin = [[Pin alloc] initWithModelDictionary:/* server response */];
// Cache the pin
[NSKeyedArchiver archiveRootObject:pin toFile:/* cached pin path */];
// App goes on, terminates, restarts...
// Load the cached object
Pin *cachedPin = [NSKeyedUnarchiver unarchiveObjectWithFile:/* cached pin path */];

Model merging and partial data

Plank models support merging and partial object materialization through a conventional “last writer wins” approach. By calling the mergeWithModel: on a generated model with a newer instance, the properties set on the newer instance will be preserved. To know which properties are set, the information is tracked internally within the model during initialization or through any mutation methods. In this example, an identifier property is used as a primary key for object equality:

static inline id valueOrNil(NSDictionary *dict, NSString *key);
struct PinSetProperties {
  unsigned int Identifier:1;
  unsigned int Link:1;
};
- (instancetype)initWithModelDictionary:(NSDictionary *)modelDictionary {
  [modelDictionary enumerateKeysAndObjectsUsingBlock:^(NSString *  _Nonnull key, id obj, BOOL *stop){
    if ([key isEqualToString:@"identifier"]) {
        // ... Set self.identifier
        self->_pinSetProperties.Identifier = 1;
    }
    if ([key isEqualToString:@"link"]) {
        // ... Set self.link
        self->_pinSetProperties.Link = 1;
    }
  }];
  // Post notification
  [[NSNotificationCenter defaultCenter] postNotificationName:@"kPlankModelDidInitializeNotification" object:self];
}

With immutable models, you have to think through how data flows through your application and how to keep a consistent state. At the end of every model class initializer, there’s a notification posted with the updated model. This is useful for integrating with your data consistency framework. With this you can track whenever a model has updated and can use internal tracking to merge the new model.

@implementation Pin(ModelMerge)
- (instancetype)mergeWithModel:(Pin *)modelObject {
    PinBuilder *builder = [[PinBuilder alloc] initWithModelObject:self];
    if (modelObject.pinSetProperties.Identifier) {
        builder.identifier = modelObject.identifier;
    }
    if (modelObject.pinSetProperties.Link) {
        builder.link = modelObject.link;
    }
    return [builder build];
}
@end

Algebraic data types

Plank provides support for specifying multiple model types in a single property, commonly referred to as an Algebraic Data Type (ADT). In this example, the Pin schema receives an attribution property that will be either a User, Board, or Interest. Assume we have separate schemas defined in files user.json, board.json and interest.json, respectively.

{
    "title": "pin",
    "properties": {
        "identifier": { "type": "string" },
        "link": { "type": "string", "format": "uri"},
        "attribution": {
          "oneOf": [
            { "$ref": "user.json" },
            { "$ref": "board.json" },
            { "$ref": "interest.json" }
          ]
        }
    }
}

Plank takes this definition of attribution and creates the necessary boilerplate code to handle each possibility. It also provides additional type-safety by generating a new class to represent your ADT.

@interface PinAttribution : NSObject<NSCopying, NSSecureCoding>
+ (instancetype)objectWithUser:(User *)user;
+ (instancetype)objectWithBoard:(Board *)board;
+ (instancetype)objectWithInterest:(Interest *)interest;
- (void)matchUser:(void (^)(User * pin))userMatchHandler
          orBoard:(void (^)(Board * board))boardMatchHandler
       orInterest:(void (^)(Interest * interest))interestMatchHandler;
@end

Note there’s a “match” function declared in the header. This is how you extract the true underlying value of your ADT instance. This approach guarantees at compile-time you have explicitly handled every possible case preventing bugs and reducing the needs to use runtime reflection which hinders performance. The example below shows how you’d use this match function.

PinAttribution *attribution;
[attribution matchUser:^(User *user) {
   // Do something with "user"
} orBoard:^(Board *board) {
   // Do something with "board"
} orInterest:^(Interest *interest) {
   // Do something with "interest"
}];

Contributing

Pull requests for bug fixes and features welcomed.

License

Copyright 2019 Pinterest, Inc.

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

Comments
  • [WIP] Kotlin support

    [WIP] Kotlin support

    Very much WIP. Currently builds off the other Swift PR.

    Still determining a design strategy for the models, likely will use a hybrid of data classes and the builder pattern. Open to suggestions.

    opened by levi 14
  • Proposal: A GreenDAO option for Java Models

    Proposal: A GreenDAO option for Java Models

    An option would be added to make the generated Java model a GreenDAO entity. It might work something like this:

    plank --lang=java --java-greedao=board_greendao_config.json board.json

    board.json:

    {
        "id":"board.json",
        "title":"board",
        "description":"Schema definition of a Board",
        "$schema":"http://json-schema.org/schema#",
        "type":"object",
        "properties":{
            "id":{
                "type":"string"
            },
            "transient_field":{
                "type":"string"
            },
            "my_property":{
                "$ref":"my_property.json"
            }
        },
        "required": ["id"],
        "primary_key": ["id"] // array to support composite keys
    }
    

    board_greendao_config.json:

    {  
        "transient" : ["transient_field"],
        "property_converters": {  
            "my_property" : {  
                "converter" : "MyPropertyConverter",          
                "columnType" : "string"
            }
        }
    }
    

    The following changes would be made to the model:

    1. An @Entity annotation is added to the model class.
    2. A @Generated annotation is added to the constructor.
    3. An @Id annotation is added to the field marked as primary_key in the schema. If no primary key is specified, no field is annotated. GreenDAO does not support composite keys with @Id annotation but a unique index could be added through the @Entity annotation if multiple fields are specified in the primary_key array.
    4. A @Transient annotation is added to fields listed in the transient array to indicate that no column should be created for the field in the table.
    5. For each element in the property_converters element, a @PropertyConverter annotation is added to allow for conversion of the property into a format that is suitable for storage into a GreenDAO table. The converter class is not generated by Plank, and is assumed to be class that already exists within the same package.

    In this example, the Board model would look like:

    @Entity
    public class Board {
        @Id 
        @SerializedName("id") private String id;
        
        @Transient 
        @SerializedName("transient_field") private String transientField
        
        @PropertyConverter(converter=MyPropertyConverter.class columnType=String.class)
        @SerializedName("my_property") private MyProperty myProperty
    
        @Generated
        public Board(String id, String transientField, MyProperty myProperty, Integer _bits) {
            this.id = id;
            this.transientField = transientField;
            this.myProperty = myProperty;
            this._bits = _bits;
        }
    }
    

    References:

    @Entity, @Id, @Transient: http://greenrobot.org/greendao/documentation/modelling-entities/ @PropertyConverter: http://greenrobot.org/greendao/documentation/custom-types/ @Generated: http://greenrobot.org/greendao/documentation/modelling-entities/#Modifying_generated_code

    opened by RicoYao 12
  • Add Flow Type Support

    Add Flow Type Support

    Further details #56

    TODOs:

    • [x] Add flow type verification step for integration test
    • [x] Add non nullable and non optional id field

    Follow Up (No blocker):

    • Add documentation for flow support
      • Update CLI help command
      • Add documentation for the website
      • Change tagline of project
    • Add dynamic spaces support (JS usually uses 2 spaces) #61
    • Generate an index.js file that exports all the flow types
    opened by maicki 11
  • Use copy for NSURL and NSDate

    Use copy for NSURL and NSDate

    This is pretty pedantic, but technically correct and it will improve the world for the 0 developers who created MYMutableDate : NSDate and set that on a builder object.

    opened by Adlai-Holler 10
  • Migrate type of URI properties to android.net.URI

    Migrate type of URI properties to android.net.URI

    At the time of the initial implementation, it was quickly decided that URI properties should just remains strings but it seems like we might lose some useful type information / encoding logic by not using a more concrete type.

    I wanted to know what the opinions of using android.net.URI are and if it makes sense to migrate our current logic.

    /cc @jparise @RicoYao

    question java 
    opened by rahul-malik 8
  • Add version to CLI

    Add version to CLI

    Would love some thoughts on how best to fetch the version number to display. Right now it is static and set within the handleVersionCommand function.

    Also added the additional command line options to the reference.

    This tackles #141.

    opened by ay8s 8
  • default property doesn't get renamed causing error

    default property doesn't get renamed causing error

    We have a boolean called default from one of our API responses, this doesn't seem to get renamed in the same way as identifier or description_text does.

    Confirmed that default is included in objectiveCReservedWords.

    Not sure if I'm missing a trick to rename etc.

    opened by ay8s 8
  • Fix compilation issues in `dictionaryObjectRepresentation`

    Fix compilation issues in `dictionaryObjectRepresentation`

    This method was added but has some schema combinations that actually have preventing it from compiling. The scenario I found that errored was a property of type Map<String,Array<String>>

    We should also add a integration test case that is exhaustive of all schema types to prevent this from happening

    opened by rahul-malik 8
  • Serialisation to JSON

    Serialisation to JSON

    Is there possibility to serialise generated object to JSON? We can do initWithDictionary, but what about to have something like dictionary method, which will return dictionary to be send as JSON via REST?

    enhancement 
    opened by matelo 8
  • iOS reserved property name

    iOS reserved property name

    I had issues with a few variable names that are reserved, I know that plank handle a few of them (id, description), but not all. I had issues with "class" and "continue".

    Is there anything that I can do to avoid this problem?

    opened by brurend 7
  • Depend on SwiftCheck when running tests

    Depend on SwiftCheck when running tests

    Add SwiftCheck as a test dependency so that when toJson lands, we can make a SwiftCheck test that does toJson(fromJson(arbitrarySchema)) == arbitrarySchema.

    SwiftPM doesn't have a legit test dependency solution right now, but the strategy most SwiftPM authors are following right now is to define an environment variable of the form SWIFTPM_TEST_libname and conditioning on that in the Package.swift (see ReactiveSwift and Algebra)

    opened by bkase 7
  • [Security] Workflow ci.yml is using vulnerable action actions/checkout

    [Security] Workflow ci.yml is using vulnerable action actions/checkout

    The workflow ci.yml is referencing action actions/checkout using references v1. However this reference is missing the commit a6747255bd19d7a757dbdda8c654a9f84db19839 which may contain fix to the some vulnerability. The vulnerability fix that is missing by actions version could be related to: (1) CVE fix (2) upgrade of vulnerable dependency (3) fix to secret leak and others. Please consider to update the reference to the action.

    opened by fockboi-lgtm 0
  • iOS plank -initWithModelDictionary:error: assumes dictionary is dictionary

    iOS plank -initWithModelDictionary:error: assumes dictionary is dictionary

    This is reading JSON data from the network. If the type behind a key changes, it is simple to crash models if casting is used to pass a non-dictionary in.

    Trust but Verify.

    opened by bolsinga 0
  • 'extends' isn't not a keyword in JSON-schema spec

    'extends' isn't not a keyword in JSON-schema spec

    Currently extends is used for models inheritance in Plank schema.

    Pros:

    • Support of inheritance in schema just makes it easier.

    Cons:

    • It is really "allOf" other than having a base class.

    • In the generated models, for common methods, it may confuses the complier. I.e, `Class A :

      • aStandardMethodWith:(ClassA)obj

      Class B : ClassA

      • aStandardMethodWith:(ClassB)obj ` This pattern is either explicitly not allowed or behaving unexpectedly in most programing languages.
    • Its not a standard keyword thus most existing JSON schema validators don't support that, or we have to make/use Plank's own validator tools on both provider-consumer sides.

    • It may encourages 'polymorphicTypeIdentifier' or similar kind of field in the schema to tell real type of model.

    AFAIK, Inheritance isn't supported in most popular model-gen(GraphQL, protoBuf, and etc) tools. I guess the main reasons is that IDL is more for defining constraints on model, not primarily on OOP.

    Possible solutions:

    • support allOf then deprecate extends This shouldn't lose any property or method from the base class but base class itself.

    • A new build option to treat extends as allOf For existing extends users, they may assume base class of the models, this is a breaking change in that case. A possible workaround is to specify a base class in the build option mentioned above? And users of "extend" would take care of the base class and its compliance in their code base.

    I created this issue to capture what @jparise and me discussed a while go.

    Your thoughts are appreciated.

    opened by woshimaliang 2
  • Any plans for dart/flutter support?

    Any plans for dart/flutter support?

    Hi, I migrated from swfit/objc to flutter few months ago, and I used to use plank for all my iOS projects. I couldn't find any immutable model generator for dart yet.

    Do you guys have any plan to do it?

    opened by CavalcanteLeo 1
  • Java documentation is outdated

    Java documentation is outdated

    The latest version needs to reflect:

    • No more use of AutoValue
    • Ability to check which fields are "set"
    • Updated usage pattern for TypeAdapters
    • Other minor changes
    java 
    opened by RicoYao 0
  • Use Kotlin-friend Java method names for Boolean accessors

    Use Kotlin-friend Java method names for Boolean accessors

    From Calling Java code from Kotlin:

    Boolean accessor methods (where the name of the getter starts with is and the name of the setter starts with set) are represented as properties which have the same name as the getter method.

    This could be a nice improvement for our generated "is set" methods. We currently name them get{Property}IsSet() (e.g. getHeightIsSet()), but we could instead name them is{Property}Set() (e.g. isHeightSet()).

    We could also consider doing something similar for declared Boolean property accessors, but we'd need to be more thoughtful about unexpected results if we start changing property names to match this convention.

    java 
    opened by jparise 0
Releases(v100)
  • v1.6(Jan 7, 2020)

    Updates

    General

    Nested object definitions.

    Previously it was required to create a new file for each schema. Now we support declaring types within types which can be useful for ones that only make sense in a certain scope or are fairly minimal.

    Example schema declaration:

    {
        "some_property" : {
            "type": "object",
            "title": "nested",
            "properties": {
                "id": { "type": "integer" },
                "name": { "type": "string" }
            }
        }
    }
    

    JSON dependency graph output

    The behavior of the --print_deps output has changed to be JSON by default. This allows for tooling to be built to visualize or analyze dependency graph of your schemas.

    Given this command using our example schemas:

    plank --print_deps Examples/PDK/pin.json                                                                                                                                                     
    

    You'll get an output with it's dependencies and any inherited types (via extends keyword)

    {
      "pin" : [
        "image",
        "board",
        "user"
      ]
    }
    

    CI

    We've migrated our CI entirely to Github Actions which will make it easier for contributors to analyze logs and build failures.

    Objective-C

    • Optimizations around memory footprint of properties
    • Test updates for equality methods

    Java

    • Removed AutoValue as a dependency
    • Support for tracking properties which are set
    • ADT, equality and nullability support
    • TypeAdapters derived from Schema definitions

    Changes

    8ee84c2 Mention nested object types in the documentation (#258) 2346a29 Support nested object type definitions (#256) 85e802f Mark generated files using 'linguist-generated' (#257) e4e5e72 Remove trailing space after integer-based enums (#255) 9e5c65f Missing @SerializedName annotation on integer-based enums (#253) fbcd34f Convert deps command output to produce JSON (#252) c232819 Java model potentially missing import for types contained in maps and lists (#251) 921c98f Upgrade swiftformat and swiftlint (#250) 979e358 Java ADT partial implementation (#249) 41c25a8 Migrate CI to Github CI/CD (#239) eeb4918 Support configurable URI types for Java (#245) 618acaa Optionally log unknown properties in TypeAdapter.read (#243) 9d367a5 Java equals() should evaluate primitives first (#244) a27b144 Check _bits directly in internal calls (#242) f650f01 Order modifiers according to the Java spec (#241) 42a168b Make generated TypeAdapter classes private (#240) 690a266 Only allocate _bits when necessary (#238) 55b0a25 Use transitiveProperties to gather Java imports (#237) fa2e15e Only import the necessary set of types (#235) 920dcee Stop importing java.lang.annotation.Retention{Policy} (#234) 01cf3e9 Stop importing com.google.gson.JsonElement (#233) 6253078 Add the Plank project URL to the file comment header (#232) 4c794b2 Java model property annotations should be sorted deterministically (#231) bf771de Java model TypeAdapter write method should not use delegateAdapter. (#227) 730f8e1 Add more nullability annotations to Java models (#228) f683102 Java model TypeAdapter should not not instantiate its inner TypeAdapters until needed (#226) 102d645 Java models should not include null fields when serialized into Json (#225) faadfa9 Java Model Builder.build method should be annotated with NonNull (#223) 7b054be Java model - _bits field should be deserialized if it's present in the JSON (#221) bc8c8fd Java Model Decorators (beta) (#217) 738fb3e Builder property variables should not have @SerializedName annotation (#220) d4a714d Emit BOOL properties as bitfields (#208) 47fb542 Add equality tests for ObjC (#219) c7fe044 Missing call to set tracking isSet-bit in Java model merging (#218) d3c6322 Use smaller enum types to reduce object sizes. (#207) ef88906 Use a boolean[] array for tracking set-bits so we can accommodate models with more than 32 fields (fixes integer overflow) (#216) 32f2fe5 Add option to generate Java private setters (#212) 8d23c9b Fix invalid call to Builder-setter from Java TypeAdapter (#211) 427edd4 Add support for androidx Nullability annotations (#204) f368cd1 Add a static TYPE variable to java models (#201) bdd00b0 Toolchain updates (#196) a8e91d3 Remove local shadow variable self.properties should be used for clarity. (#202) a2d1022 Fix archive command to work also with Swift 5 (#200) d467436 Avoid use of reflection-based deserialization in Java model (#194) 02d18ba Add linter for making sure linux main is kept up to date (#192) 5e5ed22 Don't use ObjectiveC-based handling of reserved keywords for Java (#187) 2dd9ed8 Add missing check for null json token (#188) 06925b8 Use standard Java enum types for enum properties (#184) e63f15c For Boolean, Double and Integer properties, getters should be NonNull (#178) efe3c84 Build Java sources during integration tests (#176) 47ad603 Add custom TypeAdapter for Java models that will allow for setting _bits field (#177) f38aa84 Fix missing comma in Java model constructor (#175) 3cb4722 Update docs to reflect that plank is for more than Objective-C (#173) 7d17623 Remove AutoValue from Java generated models (#159) 4372837 Update variable name substitution logic (#157) fd4dea5 Remove unused CI directory 1d44870 Add swiftlint / swiftformat in Package.swift, fix issues (#168)

    Source code(tar.gz)
    Source code(zip)
  • v1.5(Feb 27, 2019)

    This release contains a lot of internal cleanup as well as new functionality.

    Updates

    Objective-C

    Added isSet methods for each property which will allow callers to differentiate if a property has been set: This is useful for differentiating:

    • Default values for primitive types (i.e. int properties will still be 0 if not set)
    • nil values for reference types (i.e. pointers to objects are nil if not set)

    Bazel

    Initial support for building plank and integrating it within your local bazel project.

    First add plank to your WORKSPACE file

    git_repository(
        name = "plank",
        remote = "https://github.com/pinterest/plank.git",
        tag = "1.5"
    )
    

    Then you can run plank using: bazel run @plank//:plank -- [YOUR ARGS HERE]

    Java (alpha)

    • Initial support is available and depends on AutoValue and GSON. AutoValue is likely to be removed soon as a requirement.
    • Java support is in active development and breaking changes are likely
    • Audience is focused on Android development which could influence some of the design decisions / dependencies

    Changes

    eaaccea [Objective-C] Option for adding abilities to tell if a method is set. fa1a00d [Objective-C] Fix issues that cause unstable output (#160) bec7ec9 Update WORKSPACE to latest rules_swift dependencies (#163) e041f8e Enable Swiftlint for PRs (#154) 27f2219 Update README.md ce0dbea Migrate Plank to Travis CI (#152) 71a3a5c Fix typo (#146) c387215 Update bazel build to use rules_swift 7328fa0 Refactor version number to use a struct (#145) 8053ab1 Add version to CLI (#144) 87197a3 Add flag to avoid runtime files from getting generated (#137) 9439de7 Fix nil-checking issue in dictionary representation (#135) 0c2bf4e Update to Swift 4.1, fix inheritance issue with equality (#133) 42838c3 Update Java enum rendering to avoid collisions when multiple enums are (#130) db6c647 Use fancy string enums and remove unused runtime function (#128) 6eb769b Fix linux build (#127) 153ebe7 Use @NonNull for nonnull Java properties. Add nullability to documentation 1b4641c Add initial Java documentation 7a0b6aa Separate CLI reference into its own page 56097d2 Add flow documenation overview a86117d Initial support for Java (#106)

    Source code(tar.gz)
    Source code(zip)
  • v1.4.1(Mar 9, 2018)

    Overview

    This release contains additional fixes to the generation of dictionaryObjectRepresentation for cases where you have model schema with nested collections (lists within lists, maps within maps, lists within maps, ...).

    Changes

    a5e132e Fix issues with nested collections in dictionaryObjectRepresentation (#126)

    Source code(tar.gz)
    Source code(zip)
  • v1.4(Mar 5, 2018)

    Additions

    • Objective-C models can now render themselves to Dictionaries This was previously supported but had a number of edge cases where issues were present. We have now addressed those issues and we are ready to support this capability.
    • A foundation for writing more integration tests between Objective-C and Flow bridging. This can be helpful if you share schemas between them.
    • Generated ObjC models test coverage has improved for testing initialization and dictionary representation. We will continue this trend for other capabilities.

    Changes

    aa069d2 Add basic Objective-C and JS bridging test (#124) f09ae27 Fix Docker builds (#125) fe78418 Restore dictionaryObjectRepresentation for Objective-C (#122)

    Source code(tar.gz)
    Source code(zip)
  • v1.3(Feb 14, 2018)

    Whats in this release?

    Breaking changes

    For Objective-C, an enum type will no longer have "Type" added to it's name. This introduced issues (https://github.com/pinterest/plank/issues/119) and was inconsistent with the logic we use for Flow.

    Previous behavior: A enum property some_prop on a type Foo would generate a enum named FooSomePropType

    New behavior: A enum property some_prop on a type Foo will generate a enum named FooSomeProp

    If you are currently using Enums you'll likely need to update references to these types in your code base but the functionality remains the same. In the future we'll strive to keep these naming strategies consistent between languages.

    Notable bug fixes

    • Improve the nullability support for Objective-C
    • Fix the ordering of properties during generation to ensure we don't have variance in our generation.

    Changes

    991a465 Align naming logic between Flow and ObjC for enums. Fix naming collis… (#120) f8f7c17 Correct extends field example (#117) a8d8676 Fixed missing "" (#118) 0e2668c Update README.md (#114) 47fdfdd Builder setter should consider copy memoryAssignmentType (#113) bcc7bef Enumeration of schema properties should occur in a specific order to ensure a (#110) df1e444 Update homebrew installation instructions

    Source code(tar.gz)
    Source code(zip)
  • v1.2.1(Jan 17, 2018)

    Summary

    • Added make install to Makefile. Use PREFIX to specify a different installation path than /usr/local

    Basic Usage:

    make install
    

    Usage with custom installation path:

    make install PREFIX=/usr/local/Cellar/plank/1.2.1
    
    • Address issues identified by SwiftLint
    • Add documentation for Set type

    Commits

    56012d6 Add make install target to Makefile (#109) 4c3f228 Add autocorrect step to Swiftlint (#107) 3bdc34f Add Set to docs on property fields (#105)

    Source code(tar.gz)
    Source code(zip)
  • v1.2(Dec 15, 2017)

    In this release:

    • Support NSSet for Objective-C, Flow
    • Updates to nullability, equality and memory assignment for ObjC
    • Fix archiving to disable sandboxing and homebrew installation
    • Update documentation

    Commits -

    801d97e Use copy for NSURL and NSDate 4bdf16d Build archives with sandboxing disabled to allow homebrew installations (#102) 386c378 Update the .PHONY target list (#98) 5612063 Address lint warnings under swiftlint 0.24.0 (#99) 6bd7921 Don't generate dictionary representation until we can verify it compiles (#96) b870223 Correct integer example (#95) 91d26a0 Rename dictionaryRepresentation method so it doesn't conflict with Foundation's one (#94) 56a6d99 Removes usage of deprecated characters from String (#93) d480449 Added support for NSSet properties (#91) 4de2627 Update ObjC builder extension to be aware of nullability of properties (#88) 8d84d74 Remove default case that will never be executed (#87) ad1aed3 Fix issue with generating the dictionaryRepresentation method for schemas that (#85) c5ed50a Expand list of reserved objc keywords to cover most conflicting case (#79) 3fc1bea Fix make clean command(#65) 6399daf ObjectiveCDictionaryExtension to correctly handle maps of root objects (#81) 9bc92b3 Compare NSArrays using -isEqualToArray: (#83) c855031 Update indentation settings in plank.xcodeproj (#82) f8378f6 Objective-C init extension to better handle null model dictionary in prod builds (#80) 92c9a3f Bazel build support for Plank (#75)

    Source code(tar.gz)
    Source code(zip)
  • v1.1(Aug 17, 2017)

    Version 1.1

    New CLI options

        --print_deps - Just print the path to the dependent schemas necessary to generate the schemas provided and exit.
        --no_recursive - Don't generate files recursively. Only generate the one file I ask for.
        --only_runtime - Only generate runtime files and exit.
        --lang - Comma separated list of target language(s) for generating code. Default: "objc"
        --help - Show this text and exit.
    

    Flow Support

    This release contains an early experimental implementation of Flow type generation. Now your schema files can be used to generate multiple languages by using the --lang command line option.

    How do I use it?

    • Try it out by specifying --lang flow
    • Generate both ObjC and Flow --lang flow,objc

    More documentation on Flow is coming soon but you can see the current output in the Examples.

    Objective-C Generation

    • Nullability: Specifying a field as required will now influence if it is nonnull or nullable. Previously all methods were nullable.
    • New Method: "- (NSDictionary *)dictionaryRepresentation" allows your models to output a dictionary representation of themselves. This is intended to be the inverse of initWithModelDictionary.
    • Bug fixes: Small number of fixes to the generated code have been made.

    Notable commits in this release:

    864abac Nullability support in Plank: (#64) 6808341 Add dictionary representation to Objc models (#67) fc967d5 Add tests for generated models to the integration tests pipeline (#69) 116b818 Copy the value to an ivar backed by a copy property (#72) 0d50564 Add custom indentation support (#61) 37a6bc3 Don't camel case the description for EnumValue by default (#60) 12db0da Add Flow Type Support (#57) 6d226ec Fix lint warnings (#58) 332af42 Use relative schema urls internally (#59) 46d340f Fix critical bug where deep equality comparison contained a pointer equality (#50) 658c73f Add initial support for integration testing. (#48) aba7ecc Remove FilePrinter protocol (#46) 86873d0 Update to newest CI (#44) 69e6d20 Add lang attribute to provide future flexibility for additional languages in (#42) d69c8e6 Simplify initWithModelDictionary and improve performance (#40) e8d35e3 Update Plank to Swift 3.1 (#39) 38f6da3 Makes the code more readable via early returns / fatal errors in guards (#35) 9fefe3a Support for no_recursive and only_runtime flags. Fix print_deps output (#32) 120e4d2 Add cli option for printing the dependencies of a schema (#30)

    Source code(tar.gz)
    Source code(zip)
  • v1.0(Mar 14, 2017)

Owner
Pinterest
Pinterest's Open Source Projects
Pinterest
An adorable little framework and command line tool for interacting with SourceKit.

SourceKitten An adorable little framework and command line tool for interacting with SourceKit. SourceKitten links and communicates with sourcekitd.fr

JP Simard 2.1k Jan 5, 2023
Xcode-compatible build tool.

xcbuild xcbuild is an Xcode-compatible build tool with the goal of providing faster builds, better documentation of the build process and running on m

Meta Archive 2k Dec 11, 2022
A fast, convenient and nonintrusive conversion framework between JSON and model. Your model class doesn't need to extend any base class. You don't need to modify any model file.

MJExtension A fast, convenient and nonintrusive conversion framework between JSON and model. 转换速度快、使用简单方便的字典转模型框架 ?? ✍??Release Notes: more details Co

M了个J 8.5k Jan 3, 2023
DevTool - A simple UI and powerful Mac OS application, Such as JSON-Formatting tool, JSON-to-model tool, AppIcon generator, Network-Request tool...

?? ?? ?? A simple UI and powerful Mac OS application. It is a collection of tools commonly used in my development work. Such as JSON-Formatting tool, JSON-to-model tool, AppIcon generator, Network-Request tool...

渠晓友 3 Dec 21, 2022
A caching and consistency solution for immutable models.

?? Data Rocket Data is a model management system with persistence for immutable models. Motivation Immutability has many benefits, but keeping models

Peter Livesey 652 Nov 11, 2022
HandyJSON is a framework written in Swift which to make converting model objects to and from JSON easy on iOS.

HandyJSON To deal with crash on iOS 14 beta4 please try version 5.0.3-beta HandyJSON is a framework written in Swift which to make converting model ob

Alibaba 4.1k Dec 29, 2022
ObjectMapper is a framework written in Swift that makes it easy for you to convert your model objects to and from JSON.

ObjectMapper is a framework written in Swift that makes it easy for you to convert your model objects (classes and structs) to and from J

Tristan Himmelman 9k Jan 2, 2023
DBNetworkStack is a network abstraction for fetching request and mapping them to model objects

DBNetworkStack Main Features ?? Typed network resources ?? Value oriented architecture ?? Exchangeable implementations ?? Extendable API ?? Composable

DB Systel GmbH 33 Jan 10, 2022
JSONExport is a desktop application for Mac OS X which enables you to export JSON objects as model classes with their associated constructors, utility methods, setters and getters in your favorite language.

JSONExport JSONExport is a desktop application for Mac OS X written in Swift. Using JSONExport you will be able to: Convert any valid JSON object to a

Ahmed Ali 4.7k Dec 30, 2022
Command line tool for exporting resources and generating code from your Figma files

Fugen Fugen is a command line tool for exporting resources and generating code from your Figma files. Currently, Fugen supports the following entities

Almaz Ibragimov 69 Dec 17, 2022
A Swift command line tool for generating your Xcode project

XcodeGen XcodeGen is a command line tool written in Swift that generates your Xcode project using your folder structure and a project spec. The projec

Yonas Kolb 5.9k Jan 9, 2023
A command-line tool and Swift Package for generating class diagrams powered by PlantUML

SwiftPlantUML Generate UML class diagrams from swift code with this Command Line Interface (CLI) and Swift Package. Use one or more Swift files as inp

null 374 Jan 3, 2023
Tool for generating Acceptance Tests in Xcode, inspired by Fitnesse

AcceptanceMark is a tool for generating Acceptance Tests in Xcode, inspired by Fitnesse. Read this blog post for a full introduction to AcceptanceMark

Andrea Bizzotto 64 Jun 18, 2022
The repository for a command line / build pipeline tool for generating colors from a human-readable text file that designers can also use.

ColorPaletteGenerator ColorPaletteGenerator is a tool that takes a human-readable input file describing a color palette, and generates the associated

horseshoe7 0 Dec 7, 2021
Scaffold is a tool for generating code from Stencil templates, similar to rails gen.

?? Scaffold Scaffold is a tool for generating code from Stencil templates, similar to rails gen. It happens to be written in Swift, but it can output

Joshua Kaplan 33 Apr 5, 2022
CoreMLSample - CoreML Example for in app model and download model

CoreMLSample Sample for CoreML This project is CoreML Example for in app model a

Kim Seonghun 2 Aug 31, 2022
Differific is a diffing tool that helps you compare Hashable objects using the Paul Heckel's diffing algorithm

Differific is a diffing tool that helps you compare Hashable objects using the Paul Heckel's diffing algorithm. Creating a chan

Christoffer Winterkvist 127 Jun 3, 2022
JSONNeverDie - Auto reflection tool from JSON to Model, user friendly JSON encoder / decoder, aims to never die

JSONNeverDie is an auto reflection tool from JSON to Model, a user friendly JSON encoder / decoder, aims to never die. Also JSONNeverDie is a very important part of Pitaya.

John Lui 454 Oct 30, 2022
Fastbot is a model-based testing tool for modeling GUI transitions to discover app stability problems

Fastbot is a model-based testing tool for modeling GUI transitions to discover app stability problems. It combines machine learning and reinforcement learning techniques to assist discovery in a more intelligent way.

Bytedance Inc. 446 Dec 29, 2022
Auto reflection tool from JSON to Model, user friendly JSON encoder / decoder, aims to never die

JSONNeverDie is an auto reflection tool from JSON to Model, a user friendly JSON encoder / decoder, aims to never die. Also JSONNeverDie is a very imp

John Lui 454 Oct 30, 2022