Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/zadr/j2s

A macOS app to convert JSON to Swift structs
https://github.com/zadr/j2s

Last synced: 11 days ago
JSON representation

A macOS app to convert JSON to Swift structs

Awesome Lists containing this project

README

        

## What's this?
`j2s` is a macOS app that converts [`JSON`](https://en.wikipedia.org/wiki/JSON) dictionaries into [Swift](https://swift.org) `struct`s.

![Screenshot](Screenshot.png?raw=true)

## That's it? Can I make it do anything else?
No, yeah, that's it. You give `j2s` a `json` file, and it gives you Swift `struct`s. You can pick if it outputs to one file or a _n_ files for _n_ `struct`s.

If you want to make it do anything else, you'll have to write some more code. I'll probably accept pull requests, but, you should probably look into other tools like [Sourcery](https://github.com/krzysztofzablocki/Sourcery) instead.

## Codable-compliant `struct`s, right?
Yup.

## Cool
Yeah. `j2s` will also convert `snake_case_key_names` into `camelCasePropertyNames`, and if you have a key where the value is an array of of dictionaries, the key name will be — naively — [depluralized](https://github.com/zadr/j2s/blob/main/j2s/StringTransformations.swift#L14) (exact line of code may change, but look around there for the algorithm).

And, if your `JSON` value is a string that's secretly a `Date` in a format that `j2s` understands (Currently: `ISO8601`), the generated code will use the correct (`Date`) type.

Also, an integer like `5` is an `Int` and a floating point number like `5.0` is a `Double`. Because, you know, thats how these things should work.

## What version of Swift does this target?
`j2s.xcodeproj` requires Swift 4 (Xcode 9 or greater) to build. The code it outputs requires Swift 4. If you need Swift 3 support, try looking back in commit history for an older version.

## What's the generated code look like?

`j2s` can take in the following `JSON`:

```json
{
"outer" : true,
"nested" : {
"what_if_i_want_to" : [
"boogie? wouldn't dream of stopping you"
],
"when" : "2017-06-27T17:58:28+00:00",
"cool" : true
}
}
```

and turn it into Swift code that looks like this:

```swift
public struct Root: Codable {
public let nested: Nested
public let outer: Bool

public struct Nested: Codable {
public let cool: Bool
public let whatIfIWantTo: [String]
public let when: Date
}
}

// MARK: -

public extension Root {
static func create(with data: Data) throws -> Root {
return try JSONDecoder().decode(Root.self, from: data)
}

static func create(with data: Data) throws -> [Root] {
return try JSONDecoder().decode([Root].self, from: data)
}
}

// MARK: -

public extension Root.Nested {
static func create(with data: Data) throws -> Root.Nested {
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
return try decoder.decode(Root.Nested.self, from: data)
}

static func create(with data: Data) throws -> [Root.Nested] {
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
return try decoder.decode([Root.Nested].self, from: data)
}
}
```

## What about `Optional`s? I heard Swift has `Optional`s, but, I don't see any `Optional`s.
`Optional`s are sort of handled by `j2s`. `JSON` doesn't have `Optional`s, so it's hard to map them over automatically.

While parsing, if `j2s` is told to create the same `struct` multiple times, it considers any properties that don't exist in both models to be [`Optional`](http://swiftdoc.org/v3.0/type/Optional/).

The same is also true for properties that show up as `null` and as a `Type`.

`null`s are turned into `Any?`.

## Oh.
Yeah. Usually happens in the case of an array of dictionaries. This `JSON`:

```json
{
"outer" : true,
"nested" : {
"im_going_to_" : [
"type? sure, but uncheck the \"Pretty-Print JSON\" box down there --v",
"boogie? wouldn't dream of stopping you"
],
"what" : "paste json here"
}
}
```

will generate this Swift code:

```swift
public struct Demo: Codable {
public let nested: Nested
public let outer: Bool

public struct Nested: Codable {
public let imGoingTo: [String]
public let what: String
}
}

// MARK: -

public extension Nested {
public static func create(with data: Data) throws -> Nested {
return try JSONDecoder().decode(Nested.self, from: data)
}

public static func create(with data: Data) throws -> [Nested] {
return try JSONDecoder().decode([Nested].self, from: data)
}
}

// MARK: -

public extension Demo {
public static func create(with data: Data) throws -> Demo {
return try JSONDecoder().decode(Demo.self, from: data)
}

public static func create(with data: Data) throws -> [Demo] {
return try JSONDecoder().decode([Demo].self, from: data)
}
}
```

## Why build this and not use some other tool?
Seemed like a good idea. This was before `Codable` was a thing.

## Still hung up on depluralization? (Singularity?)
A `JSON` dictionary with a key named `potatoes`, where the value is a list of dictionaries will be given the Swift type `[Potato]`. Similarly, `soliloquies` becomes `[Soliloquy]`, `dwarves` and `[Dwarf]`, and so on. Depluralization is a giant `if` statement though, so while `indices` becomes `[Index]`, `matrices` incorrectly becomes `matrex`. If Anyone wanted to do some natural language processing to solve this, that would be cool.

## Okay then
Before you go, remember that `j2s` code is released under a [2-Clause BSD License](LICENSE.md) and all contributions and project activity should be in line with our [Code of Conduct](CODE_OF_CONDUCT.md).