├── src ├── assets │ ├── CNAME │ ├── images │ │ ├── xebia-fr-logo.png │ │ └── logo.svg │ ├── css │ │ └── style.css │ ├── js │ │ └── index.js │ └── index.html └── javascript │ ├── exports.js │ ├── writers │ ├── nsObject.js │ ├── unbox.js │ ├── class.js │ ├── index.js │ ├── base.js │ ├── argo.js │ ├── realm.js │ └── jsonJoy.js │ ├── entity.js │ ├── main.js │ └── property.js ├── .babelrc ├── .gitignore ├── test ├── data │ ├── bool.swift │ ├── int.swift │ ├── double.swift │ ├── optional.swift │ ├── string.swift │ ├── uint.swift │ ├── arrayOfBools.swift │ ├── arrayOfStrings.swift │ ├── arrayOfUIntegers.swift │ ├── multipleKeys.swift │ ├── realm-uint.swift │ ├── realm-bool.swift │ ├── realm-double.swift │ ├── realm-string.swift │ ├── class-uint.swift │ ├── class-arrayOfStrings.swift │ ├── nestedObject.swift │ ├── realm-nestedArrayOfDoubles.swift │ ├── unbox-uint.swift │ ├── nsobject-uint.swift │ ├── class-int-string.swift │ ├── jsonjoy-bool.swift │ ├── jsonjoy-int.swift │ ├── jsonjoy-double.swift │ ├── jsonjoy-string.swift │ ├── jsonjoy-uint.swift │ ├── nsobject-unbox-uint.swift │ ├── realm-nestedObject.swift │ ├── realm-nestedArray.swift │ ├── realm-nestedArrayOfCustomObjects.swift │ ├── argo-arrayOfUIntegers.swift │ ├── argo-uint.swift │ ├── argo-arrayOfStrings.swift │ ├── argo-optional.swift │ ├── unbox-nested.swift │ ├── jsonjoy-nestedArrayOfBools.swift │ ├── argo-int-string.swift │ ├── jsonjoy-nestedArrayOfInts.swift │ ├── jsonjoy-nestedObject.swift │ ├── jsonjoy-nestedArrayOfUInts.swift │ ├── jsonjoy-nestedArrayOfDoubles.swift │ ├── jsonjoy-nestedArrayOfStrings.swift │ ├── nsobject-unbox-nested.swift │ └── jsonjoy-nestedArray.swift ├── testUtils.js ├── nsObjectWriterTest.js ├── unboxWriterTest.js ├── classWriterTest.js ├── argoWriterTest.js ├── realmWriterTest.js ├── mergedWritersTest.js ├── jsonJoyWriterTest.js └── baseWriterTest.js ├── _config.yml ├── .travis.yml ├── .eslintrc.json ├── LICENSE ├── package.json ├── CONTRIBUTING.md ├── README.md └── Gulpfile.js /src/assets/CNAME: -------------------------------------------------------------------------------- 1 | json2swift.org -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | presets: ['es2015'] 3 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | build/ 3 | _site/ 4 | coverage 5 | -------------------------------------------------------------------------------- /test/data/bool.swift: -------------------------------------------------------------------------------- 1 | struct Root { 2 | let boolean : Bool 3 | } 4 | -------------------------------------------------------------------------------- /test/data/int.swift: -------------------------------------------------------------------------------- 1 | struct Root { 2 | let integer : Int 3 | } 4 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | source: './build/public/' 2 | destination: './_site/' 3 | -------------------------------------------------------------------------------- /test/data/double.swift: -------------------------------------------------------------------------------- 1 | struct Root { 2 | let double : Double 3 | } 4 | -------------------------------------------------------------------------------- /test/data/optional.swift: -------------------------------------------------------------------------------- 1 | struct Root { 2 | let optional : Any? 3 | } 4 | -------------------------------------------------------------------------------- /test/data/string.swift: -------------------------------------------------------------------------------- 1 | struct Root { 2 | let string : String 3 | } 4 | -------------------------------------------------------------------------------- /test/data/uint.swift: -------------------------------------------------------------------------------- 1 | struct Root { 2 | let uinteger : UInt 3 | } 4 | -------------------------------------------------------------------------------- /test/data/arrayOfBools.swift: -------------------------------------------------------------------------------- 1 | struct Root { 2 | let array : [Bool] 3 | } 4 | -------------------------------------------------------------------------------- /test/data/arrayOfStrings.swift: -------------------------------------------------------------------------------- 1 | struct Root { 2 | let array : [String] 3 | } 4 | -------------------------------------------------------------------------------- /test/data/arrayOfUIntegers.swift: -------------------------------------------------------------------------------- 1 | struct Root { 2 | let array : [UInt] 3 | } 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "4.2.4" 4 | after_success: 5 | - "npm run cover" -------------------------------------------------------------------------------- /test/data/multipleKeys.swift: -------------------------------------------------------------------------------- 1 | struct Root { 2 | let array : [String] 3 | let uinteger : UInt 4 | } 5 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "standard", 3 | "plugins": [ 4 | "standard" 5 | ] 6 | } -------------------------------------------------------------------------------- /test/data/realm-uint.swift: -------------------------------------------------------------------------------- 1 | import RealmSwift 2 | 3 | class Root : Object { 4 | dynamic var uinteger : Int = 0 5 | } 6 | -------------------------------------------------------------------------------- /test/data/realm-bool.swift: -------------------------------------------------------------------------------- 1 | import RealmSwift 2 | 3 | class Root : Object { 4 | dynamic var boolean : Bool = false 5 | } 6 | -------------------------------------------------------------------------------- /test/data/realm-double.swift: -------------------------------------------------------------------------------- 1 | import RealmSwift 2 | 3 | class Root : Object { 4 | dynamic var double : Double = 0 5 | } 6 | -------------------------------------------------------------------------------- /test/data/realm-string.swift: -------------------------------------------------------------------------------- 1 | import RealmSwift 2 | 3 | class Root : Object { 4 | dynamic var string : String = "" 5 | } 6 | -------------------------------------------------------------------------------- /src/assets/images/xebia-fr-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/viteinfinite/json2swift/HEAD/src/assets/images/xebia-fr-logo.png -------------------------------------------------------------------------------- /test/data/class-uint.swift: -------------------------------------------------------------------------------- 1 | class Root { 2 | let uinteger : UInt 3 | 4 | init(uinteger: UInt) { 5 | self.uinteger = uinteger 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /test/data/class-arrayOfStrings.swift: -------------------------------------------------------------------------------- 1 | class Root { 2 | let array : [String] 3 | 4 | init(array: [String]) { 5 | self.array = array 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /test/data/nestedObject.swift: -------------------------------------------------------------------------------- 1 | struct NestedObject { 2 | let array : [String] 3 | } 4 | 5 | struct Root { 6 | let nestedObject : NestedObject 7 | } 8 | -------------------------------------------------------------------------------- /test/data/realm-nestedArrayOfDoubles.swift: -------------------------------------------------------------------------------- 1 | import RealmSwift 2 | 3 | class Root : Object { 4 | let nested : List = List() 5 | } 6 | -------------------------------------------------------------------------------- /src/javascript/exports.js: -------------------------------------------------------------------------------- 1 | if (typeof window !== 'undefined') { 2 | window.json2swift = require('./main.js') 3 | window.json2swift.writers = require('./writers') 4 | } 5 | -------------------------------------------------------------------------------- /test/data/unbox-uint.swift: -------------------------------------------------------------------------------- 1 | import Unbox 2 | 3 | struct Root : Unboxable { 4 | let uinteger : UInt 5 | 6 | init(unboxer: Unboxer) { 7 | self.uinteger = unboxer.unbox("uinteger") 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/data/nsobject-uint.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class Root : NSObject { 4 | let uinteger : UInt 5 | 6 | init(uinteger: UInt) { 7 | self.uinteger = uinteger 8 | super.init() 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /test/data/class-int-string.swift: -------------------------------------------------------------------------------- 1 | class Root { 2 | let integer : Int 3 | let string : String 4 | 5 | init(integer: Int, string: String) { 6 | self.integer = integer 7 | self.string = string 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/data/jsonjoy-bool.swift: -------------------------------------------------------------------------------- 1 | import JSONJoy 2 | 3 | struct Root : JSONJoy { 4 | var boolean : Bool 5 | 6 | init(_ decoder: JSONDecoder) throws { 7 | self.boolean = try decoder["boolean"].bool 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/data/jsonjoy-int.swift: -------------------------------------------------------------------------------- 1 | import JSONJoy 2 | 3 | struct Root : JSONJoy { 4 | var integer : Int 5 | 6 | init(_ decoder: JSONDecoder) throws { 7 | self.integer = try decoder["integer"].getInt() 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/data/jsonjoy-double.swift: -------------------------------------------------------------------------------- 1 | import JSONJoy 2 | 3 | struct Root : JSONJoy { 4 | var double : Double 5 | 6 | init(_ decoder: JSONDecoder) throws { 7 | self.double = try decoder["double"].getDouble() 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/data/jsonjoy-string.swift: -------------------------------------------------------------------------------- 1 | import JSONJoy 2 | 3 | struct Root : JSONJoy { 4 | var string : String 5 | 6 | init(_ decoder: JSONDecoder) throws { 7 | self.string = try decoder["string"].getString() 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/data/jsonjoy-uint.swift: -------------------------------------------------------------------------------- 1 | import JSONJoy 2 | 3 | struct Root : JSONJoy { 4 | var uinteger : UInt 5 | 6 | init(_ decoder: JSONDecoder) throws { 7 | self.uinteger = try decoder["uinteger"].getUnsigned() 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/data/nsobject-unbox-uint.swift: -------------------------------------------------------------------------------- 1 | import Unbox 2 | 3 | class Root : NSObject, Unboxable { 4 | let uinteger : UInt 5 | 6 | init(unboxer: Unboxer) { 7 | self.uinteger = unboxer.unbox("uinteger") 8 | super.init() 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /test/data/realm-nestedObject.swift: -------------------------------------------------------------------------------- 1 | import RealmSwift 2 | 3 | class Nested : Object { 4 | dynamic var uinteger : Int = 0 5 | } 6 | 7 | import RealmSwift 8 | 9 | class Root : Object { 10 | dynamic var nested : Nested? = nil 11 | } 12 | -------------------------------------------------------------------------------- /test/data/realm-nestedArray.swift: -------------------------------------------------------------------------------- 1 | import RealmSwift 2 | 3 | class Nested : Object { 4 | dynamic var uinteger : Int = 0 5 | } 6 | 7 | import RealmSwift 8 | 9 | class Root : Object { 10 | let nested : List = List() 11 | } 12 | -------------------------------------------------------------------------------- /test/data/realm-nestedArrayOfCustomObjects.swift: -------------------------------------------------------------------------------- 1 | import RealmSwift 2 | 3 | class Nested : Object { 4 | dynamic var key : String = "" 5 | } 6 | 7 | import RealmSwift 8 | 9 | class Root : Object { 10 | let nested : List = List() 11 | } 12 | -------------------------------------------------------------------------------- /test/testUtils.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs') 2 | 3 | var testUtils = { 4 | join: function (entities) { 5 | return entities.map((e) => e.code).join('\n') 6 | }, 7 | 8 | readFixture: function (name) { 9 | return fs.readFileSync('test/data/' + name + '.swift', 'utf8') 10 | } 11 | } 12 | 13 | module.exports = testUtils 14 | -------------------------------------------------------------------------------- /test/data/argo-arrayOfUIntegers.swift: -------------------------------------------------------------------------------- 1 | import Argo 2 | 3 | struct Root { 4 | let array : [Int] 5 | } 6 | 7 | extension Root : Decodable { 8 | static func create(array: [Int]) -> Root { 9 | return Root(array: array) 10 | } 11 | 12 | static func decode(j: JSON) -> Decoded { 13 | return self.create 14 | <^> j <|| "array" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /test/data/argo-uint.swift: -------------------------------------------------------------------------------- 1 | import Argo 2 | 3 | struct Root { 4 | let uinteger : Int 5 | } 6 | 7 | extension Root : Decodable { 8 | static func create(uinteger: Int) -> Root { 9 | return Root(uinteger: uinteger) 10 | } 11 | 12 | static func decode(j: JSON) -> Decoded { 13 | return self.create 14 | <^> j <| "uinteger" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /test/data/argo-arrayOfStrings.swift: -------------------------------------------------------------------------------- 1 | import Argo 2 | 3 | struct Root { 4 | let array : [String] 5 | } 6 | 7 | extension Root : Decodable { 8 | static func create(array: [String]) -> Root { 9 | return Root(array: array) 10 | } 11 | 12 | static func decode(j: JSON) -> Decoded { 13 | return self.create 14 | <^> j <|| "array" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /test/data/argo-optional.swift: -------------------------------------------------------------------------------- 1 | import Argo 2 | 3 | struct Root { 4 | let optional : Any? 5 | } 6 | 7 | extension Root : Decodable { 8 | static func create(optional: Any?) -> Root { 9 | return Root(optional: optional) 10 | } 11 | 12 | static func decode(j: JSON) -> Decoded { 13 | return self.create 14 | <^> j <|? "optional" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /test/data/unbox-nested.swift: -------------------------------------------------------------------------------- 1 | import Unbox 2 | 3 | struct Nested : Unboxable { 4 | let uinteger : UInt 5 | 6 | init(unboxer: Unboxer) { 7 | self.uinteger = unboxer.unbox("uinteger") 8 | } 9 | } 10 | 11 | import Unbox 12 | 13 | struct Root : Unboxable { 14 | let nested : Nested 15 | 16 | init(unboxer: Unboxer) { 17 | self.nested = unboxer.unbox("nested") 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/javascript/writers/nsObject.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 3 | superClasses: ['NSObject'], 4 | 5 | entityHeader: function () { 6 | return 'import Foundation\n\n' 7 | }, 8 | 9 | openImplementation: function (entity) { 10 | return 'class ' + entity.name.capitalizeFirstLetter() 11 | }, 12 | 13 | initAfterBody: function (entity) { 14 | return '\t\tsuper.init()\n' 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /test/data/jsonjoy-nestedArrayOfBools.swift: -------------------------------------------------------------------------------- 1 | import JSONJoy 2 | 3 | struct Root : JSONJoy { 4 | var nested : [Bool] 5 | 6 | init(_ decoder: JSONDecoder) throws { 7 | var nestedArray = [Bool]() 8 | guard let nestedDecoders = decoder["nested"].array else { throw JSONError.WrongType } 9 | for decoder in nestedDecoders { 10 | nestedArray.append(decoder.bool) 11 | } 12 | self.nested = nestedArray 13 | 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /test/data/argo-int-string.swift: -------------------------------------------------------------------------------- 1 | import Argo 2 | 3 | struct Root { 4 | let integer : Int 5 | let string : String 6 | } 7 | 8 | extension Root : Decodable { 9 | static func create(integer: Int)(string: String) -> Root { 10 | return Root(integer: integer, string: string) 11 | } 12 | 13 | static func decode(j: JSON) -> Decoded { 14 | return self.create 15 | <^> j <| "integer" 16 | <*> j <| "string" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /test/data/jsonjoy-nestedArrayOfInts.swift: -------------------------------------------------------------------------------- 1 | import JSONJoy 2 | 3 | struct Root : JSONJoy { 4 | var nested : [Int] 5 | 6 | init(_ decoder: JSONDecoder) throws { 7 | var nestedArray = [Int]() 8 | guard let nestedDecoders = decoder["nested"].array else { throw JSONError.WrongType } 9 | for decoder in nestedDecoders { 10 | nestedArray.append(try decoder.getInt()) 11 | } 12 | self.nested = nestedArray 13 | 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /test/data/jsonjoy-nestedObject.swift: -------------------------------------------------------------------------------- 1 | import JSONJoy 2 | 3 | struct Nested : JSONJoy { 4 | var uinteger : UInt 5 | 6 | init(_ decoder: JSONDecoder) throws { 7 | self.uinteger = try decoder["uinteger"].getUnsigned() 8 | } 9 | } 10 | 11 | import JSONJoy 12 | 13 | struct Root : JSONJoy { 14 | var nested : Nested 15 | 16 | init(_ decoder: JSONDecoder) throws { 17 | self.nested = try Nested(decoder["nested"]) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/data/jsonjoy-nestedArrayOfUInts.swift: -------------------------------------------------------------------------------- 1 | import JSONJoy 2 | 3 | struct Root : JSONJoy { 4 | var nested : [UInt] 5 | 6 | init(_ decoder: JSONDecoder) throws { 7 | var nestedArray = [UInt]() 8 | guard let nestedDecoders = decoder["nested"].array else { throw JSONError.WrongType } 9 | for decoder in nestedDecoders { 10 | nestedArray.append(try decoder.getUnsigned()) 11 | } 12 | self.nested = nestedArray 13 | 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /test/data/jsonjoy-nestedArrayOfDoubles.swift: -------------------------------------------------------------------------------- 1 | import JSONJoy 2 | 3 | struct Root : JSONJoy { 4 | var nested : [Double] 5 | 6 | init(_ decoder: JSONDecoder) throws { 7 | var nestedArray = [Double]() 8 | guard let nestedDecoders = decoder["nested"].array else { throw JSONError.WrongType } 9 | for decoder in nestedDecoders { 10 | nestedArray.append(try decoder.getDouble()) 11 | } 12 | self.nested = nestedArray 13 | 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /test/data/jsonjoy-nestedArrayOfStrings.swift: -------------------------------------------------------------------------------- 1 | import JSONJoy 2 | 3 | struct Root : JSONJoy { 4 | var nested : [String] 5 | 6 | init(_ decoder: JSONDecoder) throws { 7 | var nestedArray = [String]() 8 | guard let nestedDecoders = decoder["nested"].array else { throw JSONError.WrongType } 9 | for decoder in nestedDecoders { 10 | nestedArray.append(try decoder.getString()) 11 | } 12 | self.nested = nestedArray 13 | 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /test/data/nsobject-unbox-nested.swift: -------------------------------------------------------------------------------- 1 | import Unbox 2 | 3 | class Nested : NSObject, Unboxable { 4 | let uinteger : UInt 5 | 6 | init(unboxer: Unboxer) { 7 | self.uinteger = unboxer.unbox("uinteger") 8 | super.init() 9 | } 10 | } 11 | 12 | import Unbox 13 | 14 | class Root : NSObject, Unboxable { 15 | let nested : Nested 16 | 17 | init(unboxer: Unboxer) { 18 | self.nested = unboxer.unbox("nested") 19 | super.init() 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/javascript/writers/unbox.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 3 | protocols: ['Unboxable'], 4 | 5 | entityHeader: function () { 6 | return 'import Unbox\n\n' 7 | }, 8 | 9 | openInit: function (entity) { 10 | return '\n\tinit(unboxer: Unboxer) {\n' 11 | }, 12 | 13 | closeInit: function (entity) { 14 | return '\t}\n' 15 | }, 16 | 17 | initBody: function (entity) { 18 | return entity.properties.map((p) => 19 | '\t\tself.' + p.name + ' = unboxer.unbox(\"' + p.name + '\")' 20 | ).join('\n') + '\n' 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /test/data/jsonjoy-nestedArray.swift: -------------------------------------------------------------------------------- 1 | import JSONJoy 2 | 3 | struct Nested : JSONJoy { 4 | var uinteger : UInt 5 | 6 | init(_ decoder: JSONDecoder) throws { 7 | self.uinteger = try decoder["uinteger"].getUnsigned() 8 | } 9 | } 10 | 11 | import JSONJoy 12 | 13 | struct Root : JSONJoy { 14 | var nested : [Nested] 15 | 16 | init(_ decoder: JSONDecoder) throws { 17 | var nestedArray = [Nested]() 18 | guard let nestedDecoders = decoder["nested"].array else { throw JSONError.WrongType } 19 | for decoder in nestedDecoders { 20 | nestedArray.append(try Nested(decoder)) 21 | } 22 | self.nested = nestedArray 23 | 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/assets/css/style.css: -------------------------------------------------------------------------------- 1 | .logo { 2 | width: 33%; 3 | } 4 | 5 | .source { 6 | color: #666; 7 | font-family: 'PT Mono', monospace; 8 | font-size: 90%; 9 | height: 40vh; 10 | width: 100%; 11 | } 12 | 13 | code { 14 | font-family: 'PT Mono', monospace; 15 | } 16 | 17 | footer { 18 | font-size: .8rem; 19 | text-align: center; 20 | } 21 | 22 | .xebia-logo { 23 | width: 20%; 24 | } 25 | 26 | pre { 27 | position: relative; 28 | } 29 | 30 | .action-container { 31 | position: absolute; 32 | right: 1rem; 33 | top: 1rem; 34 | } 35 | 36 | .action-button { 37 | float: right; 38 | font-size: 2.5rem; 39 | margin-left: 1rem; 40 | padding: 0; 41 | width: 4rem; 42 | } 43 | -------------------------------------------------------------------------------- /src/javascript/writers/class.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 3 | openImplementation: function (entity) { 4 | return 'class ' + entity.name.capitalizeFirstLetter() 5 | }, 6 | 7 | openInit: function (entity) { 8 | return '\n\tinit(' + 9 | entity.properties.map((p) => 10 | this.parameter(p) 11 | ).join(', ') + ') {\n' 12 | }, 13 | 14 | initBody: function (entity) { 15 | return entity.properties.map((p) => 16 | '\t\tself.' + p.name + ' = ' + p.name 17 | ).join('\n') + '\n' 18 | }, 19 | 20 | closeInit: function (entity) { 21 | return '\t}\n' 22 | }, 23 | 24 | parameter: function (property) { 25 | return property.name + ': ' + this.propertyType(property) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /test/nsObjectWriterTest.js: -------------------------------------------------------------------------------- 1 | var assert = require('chai').assert 2 | var expect = require('chai').expect 3 | var should = require('chai').should() 4 | var u = require('./testUtils.js') 5 | var json2swift = require('../main.js') 6 | var allWriters = require('../writers') 7 | 8 | describe ('The NSObject writer', function () { 9 | 10 | var writers = [allWriters.base, allWriters.class, allWriters.nsObject] 11 | 12 | context ('given a parsed JSON', function () { 13 | 14 | it ('should convert a JSON containing an unsigned integer', function () { 15 | var sourceJSON = {'uinteger': 3} 16 | var result = u.join(json2swift.parseDocument(sourceJSON, writers)) 17 | result.should.equal(u.readFixture('nsobject-uint')) 18 | }) 19 | }) 20 | }) 21 | 22 | -------------------------------------------------------------------------------- /src/javascript/entity.js: -------------------------------------------------------------------------------- 1 | export default class Entity { 2 | constructor (name, properties) { 3 | this.name = name 4 | this.properties = properties 5 | } 6 | 7 | write (writer) { 8 | var result = writer.entityHeader(this) 9 | result += writer.openImplementation(this) 10 | result += writer.interfaces() 11 | result += ' {\n' 12 | result += this.properties.map((p) => 13 | writer.property(p) 14 | ).join('\n') 15 | result += '\n' 16 | result += writer.openInit(this) 17 | result += writer.initBeforeBody(this) 18 | result += writer.initBody(this) 19 | result += writer.initAfterBody(this) 20 | result += writer.closeInit(this) 21 | result += '}\n' 22 | result += writer.entityFooter(this) 23 | result += writer.spacer() 24 | return result 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/unboxWriterTest.js: -------------------------------------------------------------------------------- 1 | var assert = require('chai').assert 2 | var expect = require('chai').expect 3 | var should = require('chai').should() 4 | var u = require('./testUtils.js') 5 | var json2swift = require('../main.js') 6 | var allWriters = require('../writers') 7 | 8 | describe ('The unbox writer', function () { 9 | 10 | var writers = [allWriters.base, allWriters.unbox] 11 | 12 | context ('given a parsed JSON', function () { 13 | 14 | it ('should convert a JSON containing an unsigned integer', function () { 15 | var sourceJSON = {'uinteger': 3} 16 | var result = u.join(json2swift.parseDocument(sourceJSON, writers)) 17 | result.should.equal(u.readFixture('unbox-uint')) 18 | }) 19 | 20 | it ('should convert a JSON containing a nested object', function () { 21 | var sourceJSON = {'nested': {'uinteger': 3}} 22 | var result = u.join(json2swift.parseDocument(sourceJSON, writers)) 23 | result.should.equal(u.readFixture('unbox-nested')) 24 | }) 25 | }) 26 | }) 27 | 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Simone Civetta 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /test/classWriterTest.js: -------------------------------------------------------------------------------- 1 | var assert = require('chai').assert 2 | var expect = require('chai').expect 3 | var should = require('chai').should() 4 | var u = require('./testUtils.js') 5 | var json2swift = require('../main.js') 6 | var allWriters = require('../writers') 7 | 8 | describe ('The class writer', function () { 9 | 10 | var writers = [allWriters.base, allWriters.class] 11 | 12 | context ('given a parsed JSON', function () { 13 | 14 | it ('should convert a JSON containing an unsigned integer', function () { 15 | var sourceJSON = {'uinteger': 3} 16 | var result = u.join(json2swift.parseDocument(sourceJSON, writers)) 17 | result.should.equal(u.readFixture('class-uint')) 18 | }) 19 | 20 | it ('should convert a JSON containing an integer and a string', function () { 21 | var sourceJSON = {'integer': -3, 'string': 'aString'} 22 | var result = u.join(json2swift.parseDocument(sourceJSON, writers)) 23 | result.should.equal(u.readFixture('class-int-string')) 24 | }) 25 | 26 | it ('should convert a JSON containing an array of strings', function () { 27 | var sourceJSON = {'array': ['a', 'b', 'c']} 28 | var result = u.join(json2swift.parseDocument(sourceJSON, writers)) 29 | result.should.equal(u.readFixture('class-arrayOfStrings')) 30 | }) 31 | }) 32 | }) 33 | 34 | -------------------------------------------------------------------------------- /src/javascript/writers/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 3 | mergeWriters: function (writers) { 4 | var mergedWriter = { 5 | superClasses: [], 6 | protocols: [], 7 | interfaces: function () { 8 | var interfaces = this.superClasses.concat(this.protocols) 9 | if (interfaces.length === 0) { 10 | return '' 11 | } 12 | return ' : ' + interfaces.join(', ') 13 | } 14 | } 15 | 16 | writers.forEach(function (writer) { 17 | for (var fn in writer) { 18 | if (typeof writer[fn] !== 'function') { 19 | continue 20 | } 21 | mergedWriter[fn] = writer[fn] 22 | } 23 | 24 | if (Array.isArray(writer.superClasses)) { 25 | mergedWriter.superClasses = mergedWriter.superClasses.concat(writer.superClasses) 26 | } 27 | 28 | if (Array.isArray(writer.protocols)) { 29 | mergedWriter.protocols = mergedWriter.protocols.concat(writer.protocols) 30 | } 31 | }) 32 | return mergedWriter 33 | } 34 | } 35 | 36 | module.exports.base = require('./base.js') 37 | module.exports.class = require('./class.js') 38 | module.exports.nsObject = require('./nsObject.js') 39 | module.exports.argo = require('./argo.js') 40 | module.exports.unbox = require('./unbox.js') 41 | module.exports.realm = require('./realm.js') 42 | module.exports.jsonJoy = require('./jsonJoy.js') 43 | 44 | -------------------------------------------------------------------------------- /src/javascript/writers/base.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 3 | basePropertyType: function (property) { 4 | return property.type 5 | }, 6 | 7 | propertyType: function (property) { 8 | var result = '' 9 | if (property.isArray) { 10 | result += '[' + this.basePropertyType(property) + ']' 11 | } else { 12 | result += this.basePropertyType(property) 13 | } 14 | if (property.isOptional) { 15 | result += '?' 16 | } 17 | return result 18 | }, 19 | 20 | entityHeader: function (entity) { return '' }, 21 | 22 | openImplementation: function (entity) { 23 | return 'struct ' + entity.name.capitalizeFirstLetter() 24 | }, 25 | 26 | property: function (property) { 27 | return '\tlet ' + property.name + ' : ' + this.propertyType(property) 28 | }, 29 | 30 | statement: function (property) { 31 | return 'self.' + property.name + ' = ' + property.name 32 | }, 33 | 34 | parameter: function (property) { 35 | return property.name + ': ' + this.propertyType(property) 36 | }, 37 | 38 | openInit: function (entity) { return '' }, 39 | 40 | initBeforeBody: function (entity) { return '' }, 41 | 42 | initBody: function (entity) { return '' }, 43 | 44 | initAfterBody: function (entity) { return '' }, 45 | 46 | closeInit: function (entity) { return '' }, 47 | 48 | entityFooter: function (entity) { return '' }, 49 | 50 | spacer: function () { return '' } 51 | } 52 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "Simone Civetta", 3 | "dependencies": {}, 4 | "description": "Convert JSON to Swift entities", 5 | "devDependencies": { 6 | "babel": "^6.5.2", 7 | "babel-preset-es2015": "^6.5.0", 8 | "browserify": "^13.0.0", 9 | "chai": "^3.5.0", 10 | "coveralls": "^2.11.6", 11 | "eslint": "^2.2.0", 12 | "eslint-config-standard": "^5.1.0", 13 | "eslint-plugin-promise": "^1.0.8", 14 | "eslint-plugin-standard": "^1.3.2", 15 | "gulp": "^3.9.1", 16 | "gulp-babel": "^6.1.2", 17 | "gulp-browserify": "^0.5.1", 18 | "gulp-eslint": "^2.0.0", 19 | "gulp-gh-pages": "^0.5.4", 20 | "gulp-mocha": "^2.2.0", 21 | "gulp-rimraf": "^0.2.0", 22 | "istanbul": "^0.4.2", 23 | "mocha": "^2.4.5", 24 | "mocha-lcov-reporter": "^1.2.0", 25 | "run-sequence": "^1.1.5" 26 | }, 27 | "keywords": [ 28 | "swift", 29 | "json" 30 | ], 31 | "license": "MIT", 32 | "main": "js2swift.js", 33 | "name": "json2swift", 34 | "repository": { 35 | "type": "git", 36 | "url": "https://github.com/viteinfinite/json2swift.git" 37 | }, 38 | "scripts": { 39 | "test": "./node_modules/gulp/bin/gulp.js launch-tests", 40 | "cover": "./node_modules/istanbul/lib/cli.js cover ./node_modules/mocha/bin/_mocha --report lcovonly -- -R spec build/test/ && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js && rm -rf ./coverage" 41 | }, 42 | "version": "1.0.0" 43 | } 44 | -------------------------------------------------------------------------------- /src/javascript/main.js: -------------------------------------------------------------------------------- 1 | import Property from './property.js' 2 | import Entity from './entity.js' 3 | import writers from './writers' 4 | 5 | // Parsing 6 | 7 | var parser = { 8 | 9 | parseNode: function (node, name, visitableNodeNames, entities) { 10 | if (visitableNodeNames.indexOf(name) !== -1) { 11 | return 12 | } 13 | 14 | while (Array.isArray(node)) { 15 | node = node[0] 16 | } 17 | 18 | if (node === null || typeof node !== 'object') { 19 | return 20 | } 21 | 22 | visitableNodeNames.push(name) 23 | var properties = [] 24 | 25 | const keys = Object.keys(node) 26 | 27 | for (let key of keys) { 28 | const keyName = String(key) 29 | const value = node[key] 30 | properties.push(new Property(keyName, value)) 31 | if (typeof value === 'object') { 32 | parser.parseNode(value, keyName, visitableNodeNames, entities) 33 | } 34 | } 35 | 36 | const entityName = name || 'Root' 37 | entities.push(new Entity(entityName, properties)) 38 | }, 39 | 40 | parseDocument: function (document, appliedWriters) { 41 | var visitableNodeNames = [] 42 | var entities = [] 43 | 44 | parser.parseNode(document, null, visitableNodeNames, entities) 45 | 46 | var writer = writers.mergeWriters(appliedWriters) 47 | return entities.map((e) => 48 | ({'name': e.name, 'code': e.write(writer)}) 49 | ) 50 | } 51 | } 52 | 53 | module.exports = parser 54 | -------------------------------------------------------------------------------- /src/javascript/writers/argo.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 3 | basePropertyType: function (property) { 4 | return property.isUInt() ? 'Int' : property.type 5 | }, 6 | 7 | propertyRune: function (index, property) { 8 | var rune = index === 0 ? '^' : '*' 9 | var runeArrow = property.isArray ? '<||' : '<|' 10 | runeArrow += property.isOptional ? '?' : '' 11 | return '<' + rune + '> j ' + runeArrow + ' \"' + property.name + '\"' 12 | }, 13 | 14 | entityHeader: function () { 15 | return 'import Argo\n\n' 16 | }, 17 | 18 | entityFooter: function (entity) { 19 | var result = '\n' 20 | result += 'extension ' + entity.name + ' : Decodable {\n' 21 | 22 | // Create 23 | result += '\tstatic func create' 24 | result += entity.properties.map((p) => '(' + p.name + ': ' + this.propertyType(p) + ')').join('') 25 | result += ' -> ' + entity.name + ' {\n' 26 | result += '\t\treturn ' + entity.name + '(' 27 | 28 | // Constructor call 29 | result += entity.properties.map((p) => p.name + ': ' + p.name).join(', ') 30 | result += ')\n' 31 | result += '\t}\n' 32 | result += '\n' 33 | 34 | // Decode 35 | result += '\tstatic func decode(j: JSON) -> Decoded<' + entity.name + '> {\n' 36 | result += '\t\treturn self.create\n' 37 | result += entity.properties.map((p, idx) => 38 | '\t\t\t' + this.propertyRune(idx, p) + '\n' 39 | ).join('') 40 | result += '\t}\n' 41 | result += '}\n' 42 | return result 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | This document contains information and guidelines about contributing to this project. 4 | Please read it before you start participating. 5 | 6 | **Topics** 7 | 8 | * [Asking Questions](#asking-questions) 9 | * [Reporting Issues](#reporting-issues) 10 | 11 | ## Asking Questions 12 | 13 | Please feel free to ask questions directly in the repository's issue page. 14 | 15 | ## Reporting Issues 16 | 17 | A great way to contribute to the project 18 | is to send a detailed issue when you encounter an problem. 19 | We always appreciate a well-written, thorough bug report. 20 | 21 | Check that the project issues database 22 | doesn't already include that problem or suggestion before submitting an issue. 23 | If you find a match, add a quick "+1" or "I have this problem too." 24 | Doing this helps prioritize the most common problems and requests. 25 | 26 | When reporting issues, please include the following: 27 | 28 | * The JSON payload you want to convert 29 | * The browser you are using, including the version 30 | * Your OS name and version 31 | * Any other details that would be useful in understanding the problem 32 | 33 | This information will help us review and fix your issue faster. 34 | 35 | --- 36 | 37 | *Some of the ideas and wording for the statements above were based on work by the [AlamoFire](https://github.com/Alamofire/Alamofire/blob/master/CONTRIBUTING.md) community, whose *Contributing* document is based upon the works of [Docker](https://github.com/docker/docker/blob/master/CONTRIBUTING.md) and [Linux](http://elinux.org/Developer_Certificate_Of_Origin). We commend them for their efforts to facilitate collaboration in their projects.* 38 | -------------------------------------------------------------------------------- /src/javascript/property.js: -------------------------------------------------------------------------------- 1 | // String prototypes 2 | 3 | String.prototype.capitalizeFirstLetter = function () { 4 | return this.charAt(0).toUpperCase() + this.slice(1) 5 | } 6 | 7 | // Property 8 | 9 | export default class Property { 10 | constructor (name, value) { 11 | this.name = name 12 | this.type = Property.resolveType(name, value) 13 | this.isArray = Array.isArray(value) 14 | this.isOptional = value == null 15 | } 16 | 17 | isInt () { 18 | return this.type === 'Int' 19 | } 20 | 21 | isUInt () { 22 | return this.type === 'UInt' 23 | } 24 | 25 | isDouble () { 26 | return this.type === 'Double' 27 | } 28 | 29 | isBool () { 30 | return this.type === 'Bool' 31 | } 32 | 33 | isNumber () { 34 | return this.isInt() || this.isUInt() || this.isDouble() 35 | } 36 | 37 | isString () { 38 | return this.type === 'String' 39 | } 40 | 41 | isCustomType () { 42 | return !this.isNumber() && !this.isString() && !this.isBool() 43 | } 44 | 45 | static resolveType (name, value) { 46 | if (value === null) { 47 | return 'Any' 48 | } else if (typeof value === 'string') { 49 | return 'String' 50 | } else if (typeof value === 'boolean') { 51 | return 'Bool' 52 | } else if (typeof value === 'number') { 53 | if (String(value).indexOf('.') !== -1) { 54 | return 'Double' 55 | } 56 | if (value < 0) { 57 | return 'Int' 58 | } 59 | return 'UInt' 60 | } else if (typeof value === 'object') { 61 | if (Array.isArray(value)) { 62 | if (value.length > 0) { 63 | return Property.resolveType(name, value[0]) 64 | } else { 65 | return name.capitalizeFirstLetter() 66 | } 67 | } else { 68 | return name.capitalizeFirstLetter() 69 | } 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /test/argoWriterTest.js: -------------------------------------------------------------------------------- 1 | var assert = require('chai').assert 2 | var expect = require('chai').expect 3 | var should = require('chai').should() 4 | var u = require('./testUtils.js') 5 | var json2swift = require('../main.js') 6 | var allWriters = require('../writers') 7 | 8 | describe ('The Argo writer', function () { 9 | 10 | var writers = [allWriters.base, allWriters.argo] 11 | 12 | context ('given a parsed JSON', function () { 13 | 14 | it ('should convert a JSON containing an unsigned integer', function () { 15 | var sourceJSON = {'uinteger': 3} 16 | var result = u.join(json2swift.parseDocument(sourceJSON, writers)) 17 | result.should.equal(u.readFixture('argo-uint')) 18 | }) 19 | 20 | it ('should convert a JSON containing an optional', function () { 21 | var sourceJSON = {'optional': null} 22 | var result = u.join(json2swift.parseDocument(sourceJSON, writers)) 23 | result.should.equal(u.readFixture('argo-optional')) 24 | }) 25 | 26 | it ('should convert a JSON containing an integer and a string', function () { 27 | var sourceJSON = {'integer': -3, 'string': 'aString'} 28 | var result = u.join(json2swift.parseDocument(sourceJSON, writers)) 29 | result.should.equal(u.readFixture('argo-int-string')) 30 | }) 31 | 32 | it ('should convert a JSON containing an array of strings', function () { 33 | var sourceJSON = {'array': ['a', 'b', 'c']} 34 | var result = u.join(json2swift.parseDocument(sourceJSON, writers)) 35 | result.should.equal(u.readFixture('argo-arrayOfStrings')) 36 | }) 37 | 38 | it ('should convert a JSON containing an array of unsigned integers', function () { 39 | var sourceJSON = {'array': [1, 2, 3]} 40 | var result = u.join(json2swift.parseDocument(sourceJSON, writers)) 41 | result.should.equal(u.readFixture('argo-arrayOfUIntegers')) 42 | }) 43 | }) 44 | }) 45 | 46 | -------------------------------------------------------------------------------- /src/javascript/writers/realm.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 3 | superClasses: ['Object'], 4 | 5 | basePropertyType: function (property) { 6 | return property.isUInt() ? 'Int' : property.type 7 | }, 8 | 9 | propertyType: function (property) { 10 | if (property.isArray) { 11 | return 'List<' + this.basePropertyType(property) + '>' 12 | } 13 | 14 | if (property.isNumber()) { 15 | if (property.isOptional) { 16 | return 'RealmOptional<' + this.basePropertyType(property) + '>' 17 | } 18 | return this.basePropertyType(property) 19 | } 20 | 21 | if (property.isOptional) { 22 | return this.basePropertyType(property) + '?' 23 | } 24 | 25 | return this.basePropertyType(property) 26 | }, 27 | 28 | defaultValue: function (property) { 29 | if (property.isOptional) { 30 | if (property.isNumber()) { 31 | return ' = RealmOptional<' + this.basePropertyType(property) + '>()' 32 | } 33 | 34 | if (property.isBool()) { 35 | return ' = RealmOptional()' 36 | } 37 | 38 | if (property.isCustomType()) { 39 | return '? = nil' 40 | } 41 | 42 | return ' = nil' 43 | } 44 | 45 | if (property.isArray) { 46 | return ' = List<' + this.basePropertyType(property) + '>()' 47 | } 48 | 49 | if (property.isNumber()) { 50 | return ' = 0' 51 | } 52 | 53 | if (property.isBool()) { 54 | return ' = false' 55 | } 56 | 57 | if (property.isString()) { 58 | return ' = ""' 59 | } 60 | 61 | if (property.isCustomType()) { 62 | return '? = nil' 63 | } 64 | 65 | return ' = nil' 66 | }, 67 | 68 | entityHeader: function () { 69 | return 'import RealmSwift\n\n' 70 | }, 71 | 72 | openImplementation: function (entity) { 73 | return 'class ' + entity.name.capitalizeFirstLetter() 74 | }, 75 | 76 | property: function (property) { 77 | if (property.isArray) { 78 | return '\tlet ' + property.name + ' : ' + this.propertyType(property) + this.defaultValue(property) 79 | } 80 | return '\tdynamic var ' + property.name + ' : ' + this.propertyType(property) + this.defaultValue(property) 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Logo](http://viteinfinite.github.io/json2swift/images/logo.svg)]()β 2 | 3 | [![Build Status](https://travis-ci.org/viteinfinite/json2swift.svg?branch=master)](https://travis-ci.org/viteinfinite/json2swift) 4 | [![Coverage Status](https://coveralls.io/repos/github/viteinfinite/json2swift/badge.svg?branch=master)](https://coveralls.io/github/viteinfinite/json2swift?branch=master) 5 | 6 | Automatically create Swift entities from [JSON](http://www.json.org). 7 | 8 | ## HTML interface 9 | 10 | The **most straightforward** way to use JSON2Swift is through the [JSON2Swift Web page](https://viteinfinite.github.io/json2swift), available at: 11 | 12 | [https://viteinfinite.github.io/json2swift](https://viteinfinite.github.io/json2swift) 13 | 14 | ## Usage 15 | 16 | Click and type and click the HTML interface. 17 | 18 | ### Build from sources 19 | 20 | You can also build from sources by performing 21 | 22 | ``` 23 | npm install 24 | node node_modules/gulp/bin/gulp.js build 25 | ``` 26 | 27 | You'll then be able to use the `parseDocument(JSON, [writers])` function against a JavaScript object and by providing a list of writers. 28 | 29 | ### Writers 30 | 31 | The writers, i.e. the output format, currently supported are currently: 32 | 33 | - `writers.base`, supporting `struct`s 34 | - `writers.class`, supporting `class`es 35 | - `writers.nsObject`, supporting `NSObject`s 36 | - `writers.argo`, supporting [Argo](https://github.com/thoughtbot/Argo) 37 | - `writers.unbox`, supporting [Unbox](https://github.com/JohnSundell/Unbox) 38 | - `writers.jsonJoy`, supporting [JSONJoy](https://github.com/daltoniam/JSONJoy-Swift) 39 | - `writers.realm`, supporting [Realm](https://realm.io) 40 | 41 | Writers can be mixed and matched. For instance, you could provide the `parseDocument` function with an array composed of `nsObject` and `argo` writers: 42 | 43 | ``` 44 | parseDocument({"key": "value"}, [writers.base, writers.nsObject, writers.argo]) 45 | ``` 46 | 47 | ## Credits 48 | 49 | - Simone Civetta ([@viteinfinite](https://twitter.com/viteinfinite)) - [Xebia France](http://xebia.fr) 50 | - _Thanks to_ [Paride Broggi](http://www.paridebroggi.com) for the precious feedback 51 | 52 | ### JSON2Swift is supported by 53 | 54 | 55 | 56 | ## Contributing 57 | 58 | You are encouraged to read [the contributing document](CONTRIBUTING.md) available in this repository. Thanks for your feedback! -------------------------------------------------------------------------------- /src/javascript/writers/jsonJoy.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 3 | protocols: ['JSONJoy'], 4 | 5 | entityHeader: function () { 6 | return 'import JSONJoy\n\n' 7 | }, 8 | 9 | property: function (property) { 10 | return '\tvar ' + property.name + ' : ' + this.propertyType(property) 11 | }, 12 | 13 | openInit: function (entity) { 14 | return '\n\tinit(_ decoder: JSONDecoder) throws {\n' 15 | }, 16 | 17 | closeInit: function (entity) { 18 | return '\t}\n' 19 | }, 20 | 21 | initBody: function (entity) { 22 | return entity.properties.map((p) => 23 | this.propertyInitializerBody(p) 24 | ).join('\n') + '\n' 25 | }, 26 | 27 | propertyInitializerBody (property) { 28 | if (property.isArray) { 29 | var propertyNameArray = property.name + 'Array' 30 | var propertyNameDecoders = property.name + 'Decoders' 31 | return '\t\tvar ' + propertyNameArray + ' = [' + property.type + ']()\n' + 32 | '\t\tguard let ' + propertyNameDecoders + ' = decoder["' + property.name + '"].array else { throw JSONError.WrongType }\n' + 33 | '\t\tfor decoder in ' + propertyNameDecoders + ' {\n' + 34 | '\t\t\t' + propertyNameArray + '.append(' + this.propertyInitializer(property) + ')\n' + 35 | '\t\t}\n' + 36 | '\t\tself.' + property.name + ' = ' + propertyNameArray + '\n' 37 | } 38 | 39 | if (property.isCustomType()) { 40 | return '\t\tself.' + property.name + ' = try ' + property.type + '(decoder[\"' + property.name + '\"])' 41 | } 42 | 43 | return '\t\tself.' + property.name + ' = try decoder[\"' + property.name + '\"].' + this.propertyConverter(property) 44 | }, 45 | 46 | propertyInitializer (property) { 47 | if (property.isCustomType()) { 48 | return 'try ' + property.type + '(decoder)' 49 | } 50 | 51 | if (property.isUInt()) { 52 | return 'try decoder.getUnsigned()' 53 | } 54 | 55 | if (property.isInt()) { 56 | return 'try decoder.getInt()' 57 | } 58 | 59 | if (property.isString()) { 60 | return 'try decoder.getString()' 61 | } 62 | 63 | if (property.isDouble()) { 64 | return 'try decoder.getDouble()' 65 | } 66 | 67 | if (property.isBool()) { 68 | return 'decoder.bool' 69 | } 70 | }, 71 | 72 | propertyConverter (property) { 73 | if (property.isUInt()) { 74 | return 'getUnsigned()' 75 | } 76 | 77 | if (property.isInt()) { 78 | return 'getInt()' 79 | } 80 | 81 | if (property.isString()) { 82 | return 'getString()' 83 | } 84 | 85 | if (property.isDouble()) { 86 | return 'getDouble()' 87 | } 88 | 89 | if (property.isBool()) { 90 | return 'bool' 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /test/realmWriterTest.js: -------------------------------------------------------------------------------- 1 | var assert = require('chai').assert 2 | var expect = require('chai').expect 3 | var should = require('chai').should() 4 | var u = require('./testUtils.js') 5 | var json2swift = require('../main.js') 6 | var allWriters = require('../writers') 7 | 8 | describe ('The Realm writer', function () { 9 | 10 | var writers = [allWriters.base, allWriters.realm] 11 | 12 | context ('given a parsed JSON', function () { 13 | 14 | it ('should convert a JSON containing an unsigned integer', function () { 15 | var sourceJSON = {'uinteger': 3} 16 | var result = u.join(json2swift.parseDocument(sourceJSON, writers)) 17 | result.should.equal(u.readFixture('realm-uint')) 18 | }) 19 | 20 | it ('should convert a JSON containing a boolean', function () { 21 | var sourceJSON = {'boolean': false} 22 | var result = u.join(json2swift.parseDocument(sourceJSON, writers)) 23 | result.should.equal(u.readFixture('realm-bool')) 24 | }) 25 | 26 | it ('should convert a JSON containing a nested array', function () { 27 | var sourceJSON = {'nested': [{'uinteger': 3}]} 28 | var result = u.join(json2swift.parseDocument(sourceJSON, writers)) 29 | result.should.equal(u.readFixture('realm-nestedArray')) 30 | }) 31 | 32 | it ('should convert a JSON containing a nested array of doubles', function () { 33 | var sourceJSON = {'nested': [0.5, 0.6]} 34 | var result = u.join(json2swift.parseDocument(sourceJSON, writers)) 35 | result.should.equal(u.readFixture('realm-nestedArrayOfDoubles')) 36 | }) 37 | 38 | it ('should convert a JSON containing a nested array of custom objects', function () { 39 | var sourceJSON = {'nested': [{'key': 'value'}]} 40 | var result = u.join(json2swift.parseDocument(sourceJSON, writers)) 41 | result.should.equal(u.readFixture('realm-nestedArrayOfCustomObjects')) 42 | }) 43 | 44 | it ('should convert a JSON containing a nested object', function () { 45 | var sourceJSON = {'nested': {'uinteger': 3}} 46 | var result = u.join(json2swift.parseDocument(sourceJSON, writers)) 47 | result.should.equal(u.readFixture('realm-nestedObject')) 48 | }) 49 | 50 | it ('should convert a JSON containing a string', function () { 51 | var sourceJSON = {'string': 'aString'} 52 | var result = u.join(json2swift.parseDocument(sourceJSON, writers)) 53 | result.should.equal(u.readFixture('realm-string')) 54 | }) 55 | 56 | it ('should convert a JSON containing a double', function () { 57 | var sourceJSON = {'double': 0.5} 58 | var result = u.join(json2swift.parseDocument(sourceJSON, writers)) 59 | result.should.equal(u.readFixture('realm-double')) 60 | }) 61 | }) 62 | }) 63 | 64 | -------------------------------------------------------------------------------- /test/mergedWritersTest.js: -------------------------------------------------------------------------------- 1 | var assert = require('chai').assert 2 | var expect = require('chai').expect 3 | var should = require('chai').should() 4 | var u = require('./testUtils.js') 5 | var json2swift = require('../main.js') 6 | var allWriters = require('../writers') 7 | 8 | describe ('Given the writer composition', function () { 9 | 10 | describe ('The mergeWriters function', function () { 11 | 12 | it ('should merge a single protocol', function () { 13 | var aWriter = {'protocols': ['a']} 14 | var merged = allWriters.mergeWriters([aWriter]) 15 | assert.include(merged.protocols, 'a') 16 | }) 17 | 18 | it ('should merge two protocols', function () { 19 | var aWriter = {'protocols': ['a']} 20 | var anotherWriter = {'protocols': ['b']} 21 | var merged = allWriters.mergeWriters([aWriter, anotherWriter]) 22 | assert.include(merged.protocols, 'a') 23 | assert.include(merged.protocols, 'b') 24 | }) 25 | 26 | it ('should merge two superClasses', function () { 27 | var aWriter = {'superClasses': ['a']} 28 | var anotherWriter = {'superClasses': ['b']} 29 | var merged = allWriters.mergeWriters([aWriter, anotherWriter]) 30 | assert.include(merged.superClasses, 'a') 31 | assert.include(merged.superClasses, 'b') 32 | }) 33 | 34 | it ('should write superClasses and protocols', function () { 35 | var aWriter = {'superClasses': ['a']} 36 | var anotherWriter = {'protocols': ['b']} 37 | var merged = allWriters.mergeWriters([aWriter, anotherWriter]) 38 | merged.interfaces().should.equal(' : a, b') 39 | }) 40 | 41 | it ('should write superClasses and protocols in order', function () { 42 | var aWriter = {'superClasses': ['a']} 43 | var anotherWriter = {'protocols': ['b']} 44 | var merged = allWriters.mergeWriters([anotherWriter, aWriter]) 45 | merged.interfaces().should.equal(' : a, b') 46 | }) 47 | }) 48 | 49 | describe ('The parseDocument function', function () { 50 | 51 | var writers 52 | 53 | context ('given a merged writer composed of NSObject and unbox', function () { 54 | 55 | beforeEach(function () { 56 | writers = [allWriters.base, allWriters.class, allWriters.nsObject, allWriters.unbox] 57 | }) 58 | 59 | it ('should convert a JSON containing an unsigned integer', function () { 60 | var sourceJSON = {'uinteger': 3} 61 | var result = u.join(json2swift.parseDocument(sourceJSON, writers)) 62 | result.should.equal(u.readFixture('nsobject-unbox-uint')) 63 | }) 64 | 65 | it ('should convert a JSON containing a nested object', function () { 66 | var sourceJSON = {'nested': {'uinteger': 3}} 67 | var result = u.join(json2swift.parseDocument(sourceJSON, writers)) 68 | result.should.equal(u.readFixture('nsobject-unbox-nested')) 69 | }) 70 | }) 71 | }) 72 | }) 73 | 74 | -------------------------------------------------------------------------------- /src/assets/js/index.js: -------------------------------------------------------------------------------- 1 | hljs.initHighlightingOnLoad(); 2 | 3 | // Actions 4 | window.onload = function (e) { 5 | var clipboard = new Clipboard('.copy-button', { 6 | target: function(trigger) { 7 | var entityName = trigger.getAttribute('data-entity-name'); 8 | return document.getElementById("entity-" + entityName); 9 | } 10 | }); 11 | } 12 | 13 | function save (trigger) { 14 | var entityName = trigger.getAttribute('data-entity-name'); 15 | var target = document.getElementById("entity-" + entityName); 16 | var blob = new Blob([target.textContent], {'type': 'text/x-swift;charset=utf-8'}); 17 | saveAs(blob, entityName + ".swift"); 18 | } 19 | 20 | // Utils 21 | function escapeHtml (text) { 22 | var map = { 23 | '&': '&', 24 | '<': '<', 25 | '>': '>', 26 | '"': '"', 27 | "'": ''' 28 | }; 29 | 30 | return text.replace(/[&<>"']/g, function(m) { return map[m]; }); 31 | } 32 | 33 | // Conversion 34 | function convert () { 35 | var sourceText = document 36 | .getElementById("source") 37 | .value 38 | .replace(new RegExp("\n", 'g'), " "); 39 | 40 | var destination = document.getElementById("destination"); 41 | 42 | try { 43 | var sourceJSON = JSON.parse(sourceText); 44 | } catch (e) { 45 | destination.innerText = e; 46 | return; 47 | } 48 | 49 | var writers = [json2swift.writers.base]; 50 | if (document.getElementById('radio-writer-class').checked) { 51 | writers.push(json2swift.writers.class); 52 | } 53 | 54 | if (document.getElementById('radio-writer-nsobject').checked) { 55 | writers.push(json2swift.writers.class); 56 | writers.push(json2swift.writers.nsObject); 57 | } 58 | 59 | if (document.getElementById('radio-writer-argo').checked) { 60 | writers.push(json2swift.writers.argo); 61 | } 62 | 63 | if (document.getElementById('radio-writer-unbox').checked) { 64 | writers.push(json2swift.writers.unbox); 65 | } 66 | 67 | if (document.getElementById('radio-writer-jsonjoy').checked) { 68 | writers.push(json2swift.writers.jsonJoy); 69 | } 70 | 71 | if (document.getElementById('radio-writer-realm').checked) { 72 | document.getElementById('radio-writer-none').checked = true; 73 | writers = [json2swift.writers.base, json2swift.writers.realm]; 74 | } 75 | 76 | var allEntities = json2swift.parseDocument(sourceJSON, writers); 77 | var mapped = allEntities.map(function (e) { 78 | return '
' +
79 |       '
' + 80 | '' + 81 | '' + 82 | '
' + 83 | '' + escapeHtml(e.code) + '' + 84 | '
'; 85 | }); 86 | 87 | destination.innerHTML = mapped.join('\n'); 88 | 89 | var codes = Array.prototype.slice.call(document.getElementsByTagName('code')); 90 | codes.forEach(function (c) { 91 | hljs.highlightBlock(c); 92 | }); 93 | } 94 | -------------------------------------------------------------------------------- /src/assets/images/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 10 | 19 | 24 | 25 | 27 | 30 | 32 | 34 | 36 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /test/jsonJoyWriterTest.js: -------------------------------------------------------------------------------- 1 | var assert = require('chai').assert 2 | var expect = require('chai').expect 3 | var should = require('chai').should() 4 | var u = require('./testUtils.js') 5 | var json2swift = require('../main.js') 6 | var allWriters = require('../writers') 7 | 8 | describe ('The JSONJoy writer', function () { 9 | 10 | var writers = [allWriters.base, allWriters.jsonJoy] 11 | 12 | context ('given a parsed JSON', function () { 13 | 14 | it ('should convert a JSON containing an unsigned integer', function () { 15 | var sourceJSON = {'uinteger': 3} 16 | var result = u.join(json2swift.parseDocument(sourceJSON, writers)) 17 | result.should.equal(u.readFixture('jsonjoy-uint')) 18 | }) 19 | 20 | it ('should convert a JSON containing a boolean', function () { 21 | var sourceJSON = {'boolean': false} 22 | var result = u.join(json2swift.parseDocument(sourceJSON, writers)) 23 | result.should.equal(u.readFixture('jsonjoy-bool')) 24 | }) 25 | 26 | it ('should convert a JSON containing a double', function () { 27 | var sourceJSON = {'double': 0.5} 28 | var result = u.join(json2swift.parseDocument(sourceJSON, writers)) 29 | result.should.equal(u.readFixture('jsonjoy-double')) 30 | }) 31 | 32 | it ('should convert a JSON containing a string', function () { 33 | var sourceJSON = {'string': 'aString'} 34 | var result = u.join(json2swift.parseDocument(sourceJSON, writers)) 35 | result.should.equal(u.readFixture('jsonjoy-string')) 36 | }) 37 | 38 | it ('should convert a JSON containing an integer', function () { 39 | var sourceJSON = {'integer': -1} 40 | var result = u.join(json2swift.parseDocument(sourceJSON, writers)) 41 | result.should.equal(u.readFixture('jsonjoy-int')) 42 | }) 43 | 44 | it ('should convert a JSON containing a nested array', function () { 45 | var sourceJSON = {'nested': [{'uinteger': 3}]} 46 | var result = u.join(json2swift.parseDocument(sourceJSON, writers)) 47 | result.should.equal(u.readFixture('jsonjoy-nestedArray')) 48 | }) 49 | 50 | it ('should convert a JSON containing a nested array of doubles', function () { 51 | var sourceJSON = {'nested': [0.5, 0.6]} 52 | var result = u.join(json2swift.parseDocument(sourceJSON, writers)) 53 | result.should.equal(u.readFixture('jsonjoy-nestedArrayOfDoubles')) 54 | }) 55 | 56 | it ('should convert a JSON containing a nested array of strings', function () { 57 | var sourceJSON = {'nested': ['aString']} 58 | var result = u.join(json2swift.parseDocument(sourceJSON, writers)) 59 | result.should.equal(u.readFixture('jsonjoy-nestedArrayOfStrings')) 60 | }) 61 | 62 | it ('should convert a JSON containing a nested array of bools', function () { 63 | var sourceJSON = {'nested': [true]} 64 | var result = u.join(json2swift.parseDocument(sourceJSON, writers)) 65 | result.should.equal(u.readFixture('jsonjoy-nestedArrayOfBools')) 66 | }) 67 | 68 | it ('should convert a JSON containing a nested array of unsigned integers', function () { 69 | var sourceJSON = {'nested': [3]} 70 | var result = u.join(json2swift.parseDocument(sourceJSON, writers)) 71 | result.should.equal(u.readFixture('jsonjoy-nestedArrayOfUInts')) 72 | }) 73 | 74 | it ('should convert a JSON containing a nested array of integers', function () { 75 | var sourceJSON = {'nested': [-3]} 76 | var result = u.join(json2swift.parseDocument(sourceJSON, writers)) 77 | result.should.equal(u.readFixture('jsonjoy-nestedArrayOfInts')) 78 | }) 79 | 80 | it ('should convert a JSON containing a nested object', function () { 81 | var sourceJSON = {'nested': {'uinteger': 3}} 82 | var result = u.join(json2swift.parseDocument(sourceJSON, writers)) 83 | result.should.equal(u.readFixture('jsonjoy-nestedObject')) 84 | }) 85 | }) 86 | }) 87 | 88 | -------------------------------------------------------------------------------- /src/assets/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | JSON2Swift | Generate boilerplate code for your Swift structs or classes 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | Fork me on GitHub 25 | 26 |
27 |
28 |

29 |
30 | 31 |
32 |
Paste your JSON and generate Swift entities using the configuration below.
33 |
34 | 35 |
36 |
37 |
38 |
Choose a representation...
39 | Struct
40 | Class
41 | NSObject
42 | Realm 43 | 44 |
45 |
46 |
...and a flavor
47 | None
48 | Argo
49 | Unbox
50 | JSONJoy 51 | 52 |
53 |
54 |
55 | 56 |
57 | 65 |
66 | 67 |
68 | 69 |
70 | 71 |
72 | 73 |
74 | 75 | 87 |
88 | 89 | 90 | -------------------------------------------------------------------------------- /test/baseWriterTest.js: -------------------------------------------------------------------------------- 1 | var assert = require('chai').assert 2 | var expect = require('chai').expect 3 | var should = require('chai').should() 4 | var u = require('./testUtils.js') 5 | var json2swift = require('../main.js') 6 | var allWriters = require('../writers') 7 | 8 | describe ('json2swift', function () { 9 | 10 | describe ('The parseDocument function', function () { 11 | 12 | var writers 13 | 14 | context ('given the base writer', function () { 15 | 16 | beforeEach (function () { 17 | writers = [allWriters.base] 18 | }) 19 | 20 | it ('should convert a JSON containing an unsigned integer', function () { 21 | var sourceJSON = {'uinteger': 3} 22 | var result = u.join(json2swift.parseDocument(sourceJSON, writers)) 23 | result.should.equal(u.readFixture('uint')) 24 | }) 25 | 26 | it ('should convert a JSON containing a negative integer', function () { 27 | var sourceJSON = {'integer': -3} 28 | var result = u.join(json2swift.parseDocument(sourceJSON, writers)) 29 | result.should.equal(u.readFixture('int')) 30 | }) 31 | 32 | it ('should convert a JSON containing an optional', function () { 33 | var sourceJSON = {'optional': null} 34 | var result = u.join(json2swift.parseDocument(sourceJSON, writers)) 35 | result.should.equal(u.readFixture('optional')) 36 | }) 37 | 38 | it ('should convert a JSON containing a double', function () { 39 | var sourceJSON = {'double': 0.3} 40 | var result = u.join(json2swift.parseDocument(sourceJSON, writers)) 41 | result.should.equal(u.readFixture('double')) 42 | }) 43 | 44 | it ('should convert a JSON containing a boolean', function () { 45 | var sourceJSON = {'boolean': true} 46 | var result = u.join(json2swift.parseDocument(sourceJSON, writers)) 47 | result.should.equal(u.readFixture('bool')) 48 | }) 49 | 50 | it ('should convert a JSON containing a string', function () { 51 | var sourceJSON = {'string': 'aString'} 52 | var result = u.join(json2swift.parseDocument(sourceJSON, writers)) 53 | result.should.equal(u.readFixture('string')) 54 | }) 55 | 56 | it ('should convert a JSON containing an array of booleans', function () { 57 | var sourceJSON = {'array': [false, true]} 58 | var result = u.join(json2swift.parseDocument(sourceJSON, writers)) 59 | result.should.equal(u.readFixture('arrayOfBools')) 60 | }) 61 | 62 | it ('should convert a JSON containing an array of integers', function () { 63 | var sourceJSON = {'array': [1, 2]} 64 | var result = u.join(json2swift.parseDocument(sourceJSON, writers)) 65 | result.should.equal(u.readFixture('arrayOfUIntegers')) 66 | }) 67 | 68 | it ('should convert a JSON containing an array of strings', function () { 69 | var sourceJSON = {'array': ['1', '2']} 70 | var result = u.join(json2swift.parseDocument(sourceJSON, writers)) 71 | result.should.equal(u.readFixture('arrayOfStrings')) 72 | }) 73 | 74 | it ('should convert a JSON containing a nested object', function () { 75 | var sourceJSON = {'nestedObject': {'array': ['1', '2']}} 76 | var result = u.join(json2swift.parseDocument(sourceJSON, writers)) 77 | result.should.equal(u.readFixture('nestedObject')) 78 | }) 79 | 80 | it ('should convert a JSON with multiple keys', function () { 81 | var sourceJSON = {'array': ['1', '2'], 'uinteger': 3} 82 | var result = u.join(json2swift.parseDocument(sourceJSON, writers)) 83 | result.should.equal(u.readFixture('multipleKeys')) 84 | }) 85 | 86 | it ('should convert a JSON array', function () { 87 | var sourceJSON = [{'uinteger': 1}] 88 | var result = u.join(json2swift.parseDocument(sourceJSON, writers)) 89 | result.should.equal(u.readFixture('uint')) 90 | }) 91 | 92 | it ('should convert a JSON array of arrays', function () { 93 | var sourceJSON = [[{'uinteger': 1}]] 94 | var result = u.join(json2swift.parseDocument(sourceJSON, writers)) 95 | result.should.equal(u.readFixture('uint')) 96 | }) 97 | 98 | it ('should convert an empty array of arrays with no error', function () { 99 | var sourceJSON = [[]] 100 | var result = u.join(json2swift.parseDocument(sourceJSON, writers)) 101 | result.should.equal('') 102 | }) 103 | }) 104 | }) 105 | }) 106 | -------------------------------------------------------------------------------- /Gulpfile.js: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////////// 2 | // Imports 3 | //////////////////////////////////////////////////////////////////////////////////// 4 | 'use strict'; 5 | 6 | var gulp = require('gulp'); 7 | var babel = require('gulp-babel'); 8 | var mocha = require('gulp-mocha'); 9 | var runSequence = require('run-sequence'); 10 | var rimraf = require('gulp-rimraf'); 11 | var eslint = require('gulp-eslint'); 12 | var spawn = require('child_process').spawn; 13 | var browserify = require('gulp-browserify'); 14 | var deploy = require('gulp-gh-pages'); 15 | var cp = require('child_process'); 16 | var jekyll = process.platform === 'win32' ? 'jekyll.bat' : 'jekyll'; 17 | 18 | var node; 19 | 20 | //////////////////////////////////////////////////////////////////////////////////// 21 | // Tasks 22 | //////////////////////////////////////////////////////////////////////////////////// 23 | 24 | gulp.task('build-js', function () { 25 | return gulp.src(['src/javascript/**/*.js', '!src/javascript/conf/config.js']) 26 | .pipe(babel()) 27 | .pipe(gulp.dest('build')); 28 | }); 29 | 30 | gulp.task('build-sources', function (callback) { 31 | runSequence('build-js', callback); 32 | }); 33 | 34 | gulp.task('copy-assets', function () { 35 | return gulp.src(['src/assets/**/*']) 36 | .pipe(gulp.dest('build/public/')); 37 | }); 38 | 39 | gulp.task('clean-build', function () { 40 | return gulp.src('build', {read: false}) 41 | .pipe(rimraf()); 42 | }); 43 | 44 | // Default gulp task 45 | gulp.task('default', function (callback) { 46 | runSequence('build', callback); 47 | }); 48 | 49 | gulp.task('eslint', function () { 50 | return gulp.src(['**/*.js', '!node_modules/**', '!build/**']) 51 | .pipe(eslint()) 52 | .pipe(eslint.format()) 53 | .pipe(eslint.failAfterError()); 54 | }); 55 | 56 | gulp.task('exec', function () { 57 | if (node) node.kill(); 58 | 59 | node = spawn('node', ['build/main.js'], {stdio: 'inherit'}) 60 | node.on('close', function (code) { 61 | if (code === 8) { 62 | gulp.log('Error detected, waiting for changes...'); 63 | } 64 | }); 65 | }); 66 | 67 | gulp.task('browserify', function () { 68 | return gulp.src(['build/exports.js']) 69 | .pipe(browserify({ 70 | insertGlobals: true, 71 | debug: !gulp.env.production 72 | })) 73 | .pipe(gulp.dest('./build/public/js/')) 74 | }); 75 | 76 | gulp.task('build', ['clean-build'], function (callback) { 77 | runSequence('build-sources', 'copy-assets', callback); 78 | }); 79 | 80 | gulp.task('build-for-web', function (callback) { 81 | runSequence('build', 'browserify', callback); 82 | }); 83 | 84 | /** 85 | * Tests 86 | */ 87 | 88 | gulp.task('copy-test-data', function () { 89 | return gulp.src('test/data/**/*') 90 | .pipe(gulp.dest('build/test/data')); 91 | }); 92 | 93 | gulp.task('build-tests', ['copy-test-data'], function () { 94 | return gulp.src('test/**/*.js') 95 | .pipe(babel()) 96 | .pipe(gulp.dest('build/test')); 97 | }); 98 | 99 | gulp.task('mocha-tests', ['build-tests'], function () { 100 | return gulp.src(['build/test/*Test.js']) 101 | .pipe(mocha({timeout: 5000})) 102 | .once('error', function (err) { 103 | console.log(err); 104 | process.exit(1); 105 | }) 106 | .once('end', function () { 107 | process.exit(0); 108 | }); 109 | }); 110 | 111 | gulp.task('launch-tests', function (callback) { 112 | runSequence('build', 'build-tests', 'mocha-tests', callback); 113 | }); 114 | 115 | /** 116 | * Watch 117 | */ 118 | 119 | gulp.task('watch', ['build'], function (callback) { 120 | runSequence('exec', callback); 121 | 122 | // Build my sources 123 | gulp.watch(['src/javascript/**/*.js'], ['build-sources']); 124 | 125 | // Note: try wrapping in a function if getting an error like `TypeError: Bad argument at TypeError (native) at 126 | // ChildProcess.spawn` 127 | gulp.watch('build/main.js', function () { 128 | runSequence('exec', callback); 129 | }); 130 | }); 131 | 132 | /** 133 | * Build the Jekyll Site 134 | */ 135 | 136 | gulp.task('jekyll-clean', function () { 137 | return gulp.src('_site', {read: false}) 138 | .pipe(rimraf()); 139 | }); 140 | 141 | gulp.task('jekyll-build', ['jekyll-clean', 'build-for-web'], function (done) { 142 | return cp.spawn(jekyll, ['build'], {stdio: 'inherit'}) 143 | .on('close', done); 144 | }); 145 | 146 | gulp.task('deploy', ['jekyll-build'], function () { 147 | return gulp.src('./build/public/**/*') 148 | .pipe(deploy()); 149 | }); 150 | --------------------------------------------------------------------------------