├── .gitignore ├── LICENSE ├── README.md ├── bin └── swift-json-gen ├── example ├── Blog+JsonGen.swift └── Blog.swift ├── lib ├── Extensions.js ├── Extensions.js.map ├── JsonGen.js ├── JsonGen.js.map ├── SwiftAst.js ├── SwiftAst.js.map ├── SwiftPrinter.js └── SwiftPrinter.js.map ├── package.json ├── src ├── Extensions.ts ├── JsonGen.ts ├── SwiftAst.ts ├── SwiftPrinter.ts └── node.d.ts ├── tests ├── Test01+Extensions.swift ├── Test01.swift ├── Test02.swift ├── Test03.swift ├── Test04.swift ├── Test05.swift ├── Test06a.swift ├── Test06b.swift ├── Test07.swift ├── Test08.swift ├── Test09.swift ├── Test10.swift ├── Test11_nested_enums.swift ├── Test12_empty_struct.swift ├── Test13_struct_in_extension.swift ├── Test14_generate_init.swift ├── Test15_keywords.swift └── Test16_inits.swift └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # Compiled binary addons (http://nodejs.org/api/addons.html) 20 | build/Release 21 | 22 | # Dependency directory 23 | # Commenting this out is preferred by some people, see 24 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- 25 | node_modules 26 | 27 | # Users Environment Variables 28 | .lock-wscript 29 | 30 | # tests generated files 31 | tests/*+JsonGen.swift 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Tom Lokhorst 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 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Swift JsonGen 2 |
3 | 4 | JsonGen generates source code files with decoders and encoders for parsing JSON into immutable Swift structs. 5 | 6 | Features 7 | -------- 8 | 9 | * Generates an extension with a `decodeJson` and `encodeJson` method for each struct 10 | * Works on individual `.swift` files or whole directories 11 | * Handles type aliases 12 | * Supports primitive types, nested types and custom generic types 13 | * Allow for custom encoders and decoders 14 | * Allow for part of the datastructure to remain untyped 15 | * Excelent error messages when JSON decoding fails: [Improving error messages](http://q42.com/blog/post/134258806788/improving-error-messages-from-generated-json) 16 | 17 | Here's an example of a nice, detailed error message: 18 | 19 | ```swift 20 | 2 errors in Blog struct 21 | - subTitle: Value is not of expected type String?: `42` 22 | ▿ posts: 2 errors in array 23 | ▿ [1] 1 error in Post struct 24 | - title: Field missing 25 | ▿ [2] 3 errors in Post struct 26 | - title: Value is not of expected type String: `1` 27 | - body: Value is not of expected type String: `42` 28 | ▿ author: 2 errors in Author struct 29 | - name: Field missing 30 | - email: Field missing 31 | ``` 32 | 33 | See also the blog post: 34 | [Swift + JSON with code generation](http://tomlokhorst.tumblr.com/post/119966903324/json-swift-with-code-generation) 35 | 36 | 37 | CocoaHeadsNL presentation 38 | ------------------------- 39 | 40 | Tom Lokhorst presented at the January 2016 CocoaHeadsNL meetup. 41 | Comparing several Json decoding libraries for Swift and talking about code generation with JsonGen. 42 | 43 | 44 | 45 | 46 | Installation 47 | ------------ 48 | 49 | Install the latest release from NPM: 50 | 51 | > npm install -g swift-json-gen 52 | 53 | Include the [Statham](https://github.com/tomlokhorst/Statham) swift library in your own project. 54 | This library contains some encoders and decoders for default Swift and Foundation types. 55 | 56 | With CocoaPods, this can be done with: 57 | 58 | pod 'Statham' 59 | 60 | 61 | Example 62 | ------- 63 | 64 | Assuming you have a file `example/Blog.swift` containing one or more structs: 65 | 66 | ```swift 67 | struct Blog { 68 | let id: Int 69 | let name: String 70 | let author: String? 71 | let needsPassword: Bool 72 | let url: URL 73 | } 74 | ``` 75 | 76 | To generate Json decoders based a file of structs run: 77 | 78 | > swift-json-gen example/Blog.swift 79 | 80 | 81 | This will generate the file 82 | [`example/Blog+JsonGen.swift`](https://raw.githubusercontent.com/tomlokhorst/swift-json-gen/develop/example/Blog+JsonGen.swift) 83 | with the following (truncated) content: 84 | 85 | ```swift 86 | extension Blog { 87 | static func decodeJson(json: Any) throws -> Blog { 88 | let decoder = try JsonDecoder(json: json) 89 | 90 | let _id = try decoder.decode("id", decoder: Int.decodeJson) 91 | let _name = try decoder.decode("name", decoder: String.decodeJson) 92 | let _author = try decoder.decode("author", decoder: Optional.decodeJson(String.decodeJson)) 93 | let _needsPassword = try decoder.decode("needsPassword", decoder: Bool.decodeJson) 94 | let _url = try decoder.decode("url", decoder: URL.decodeJson) 95 | 96 | guard 97 | let id = _id, 98 | let name = _name, 99 | let author = _author, 100 | let needsPassword = _needsPassword, 101 | let url = _url 102 | else { 103 | throw JsonDecodeError.structErrors(type: "Blog", errors: decoder.errors) 104 | } 105 | 106 | return Blog(id: id, name: name, author: author, needsPassword: needsPassword, url: url) 107 | } 108 | 109 | func encodeJson() -> [String: Any] { 110 | var dict: [String: Any] = [:] 111 | 112 | dict["id"] = id.encodeJson() 113 | dict["name"] = name.encodeJson() 114 | dict["author"] = author.encodeJson({ $0.encodeJson() }) 115 | dict["needsPassword"] = needsPassword.encodeJson() 116 | dict["url"] = url.encodeJson() 117 | 118 | return dict 119 | } 120 | } 121 | ``` 122 | 123 | 124 | Usage 125 | ----- 126 | 127 | Include the generated `YourFile+JsonGen.swift` file into your project. Make sure you've also included the [Statham](https://github.com/tomlokhorst/Statham) library. 128 | 129 | The generated encoder and decoder can be used in conjunction with NSJSONSerialization like so: 130 | 131 | ```swift 132 | let inputStr = "{ \"title\": \"Hello, World!\", \"published\": true, \"author\": { \"first\": \"Tom\", \"last\": \"Lokhorst\" } }" 133 | let inputData = inputStr.data(using: .utf8)! 134 | let inputObj = try! JSONSerialization.jsonObject(with: inputData, options: []) 135 | 136 | let blog = try! Blog.decodeJson(inputObj) 137 | 138 | let outputObj = blog.encodeJson() 139 | let outputData = try! JSONSerialization.data(withJSONObject: outputObj, options: .prettyPrinted) 140 | let outputStr = String(data: outputData, encoding: .utf8)! 141 | ``` 142 | 143 | 144 | Customization 145 | ------------- 146 | 147 | If you want to differ from the default generated code you can provide your own 148 | `decodeJson` or `encodeJson` functions. If these already exist, no new 149 | function will be generated. 150 | 151 | You also need to provide your own functions for kinds that are not supported, 152 | like enums and classes. 153 | 154 | 155 | How it works 156 | ------------ 157 | 158 | This program calls the Swift compiler and dumps the parsed AST. 159 | (Using the command `xcrun swiftc -dump-ast SomeFile.swift`) 160 | 161 | This AST is traversed to look for struct definitions, for each struct 162 | `decodeJson` and `encodeJson` functions is generated: 163 | 164 | ```swift 165 | extension SomeStruct { 166 | static func decodeJson(_ json: Any) throws -> SomeStruct { 167 | ... 168 | } 169 | 170 | func encodeJson() -> Any { 171 | ... 172 | } 173 | } 174 | ``` 175 | 176 | 177 | Compiling 178 | --------- 179 | 180 | This package is written in TypeScript. To make changes to the code of JsonGen, first install TypeScript: 181 | 182 | > npm install -g typescript 183 | 184 | Edit the `.ts` files and compile the code as follows: 185 | 186 | > tsc 187 | 188 | 189 | Releases 190 | -------- 191 | 192 | - 1.2.0 - 2017-03-09 - Swift 3.1 support 193 | - 1.1.0 - 2017-03-07 - Add `--accessLevel` flag 194 | - **1.0.0** - 2016-09-30 - Swift 3 support 195 | - 0.8.0 - 2016-09-29 - Swift 2.3 support 196 | - 0.7.0 - 2016-04-07 - Generate missing `init` 197 | - 0.6.0 - 2016-03-03 - Move JsonGen.swift to separate library [Statham](https://github.com/tomlokhorst/Statham) 198 | - 0.5.0 - 2016-02-29 - Adds `--output` option for providing an output directory 199 | - 0.4.0 - 2016-02-21 - Generate code based on JsonDecodable class 200 | - 0.3.0 - 2015-11-19 - Decoders with `throws`, instead of returning an optional 201 | - 0.2.2 - 2015-09-22 - Bugfix, show correct error on missing field 202 | - 0.2.1 - 2015-09-14 - Bugfix, now works with released Xcode 203 | - **0.2.0** - 2015-09-11 - Update to Swift 2 204 | - 0.1.3 - 2015-07-22 - Show all Swift compiler errors 205 | - 0.1.2 - 2015-06-01 - Support for computed properties 206 | - 0.1.1 - 2015-05-28 - Don't generate empty files 207 | - **0.1.0** - 2015-05-25 - Initial public release 208 | - 0.0.0 - 2014-10-11 - Initial private version for project at [Q42](http://q42.com) 209 | 210 | 211 | Licence & Credits 212 | ----------------- 213 | 214 | JsonGen is written by [Tom Lokhorst](https://twitter.com/tomlokhorst) of [Q42](http://q42.com) 215 | and available under the [MIT license](https://github.com/tomlokhorst/swift-json-gen/blob/develop/LICENSE), 216 | so feel free to use it in commercial and non-commercial projects. 217 | -------------------------------------------------------------------------------- /bin/swift-json-gen: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | "use strict"; 4 | var path = require('path'); 5 | var fs = require('fs'); 6 | var lib = path.join(path.dirname(fs.realpathSync(__filename)), '../lib'); 7 | 8 | require(lib+'/JsonGen.js').generate(); 9 | 10 | -------------------------------------------------------------------------------- /example/Blog+JsonGen.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Blog+JsonGen.swift 3 | // 4 | // Auto generated by swift-json-gen on Fri, 30 Sep 2016 06:38:45 GMT 5 | // See for details: https://github.com/tomlokhorst/swift-json-gen 6 | // 7 | 8 | import Foundation 9 | import Statham 10 | 11 | extension Blog { 12 | static func decodeJson(_ json: Any) throws -> Blog { 13 | let decoder = try JsonDecoder(json: json) 14 | 15 | let _id = try decoder.decode("id", decoder: Int.decodeJson) 16 | let _name = try decoder.decode("name", decoder: String.decodeJson) 17 | let _author = try decoder.decode("author", decoder: Optional.decodeJson(String.decodeJson)) 18 | let _needsPassword = try decoder.decode("needsPassword", decoder: Bool.decodeJson) 19 | let _url = try decoder.decode("url", decoder: URL.decodeJson) 20 | 21 | guard 22 | let id = _id, 23 | let name = _name, 24 | let author = _author, 25 | let needsPassword = _needsPassword, 26 | let url = _url 27 | else { 28 | throw JsonDecodeError.structErrors(type: "Blog", errors: decoder.errors) 29 | } 30 | 31 | return Blog(id: id, name: name, author: author, needsPassword: needsPassword, url: url) 32 | } 33 | 34 | func encodeJson() -> [String: Any] { 35 | var dict: [String: Any] = [:] 36 | 37 | dict["id"] = id.encodeJson() 38 | dict["name"] = name.encodeJson() 39 | dict["author"] = author.encodeJson({ $0.encodeJson() }) 40 | dict["needsPassword"] = needsPassword.encodeJson() 41 | dict["url"] = url.encodeJson() 42 | 43 | return dict 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /example/Blog.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | struct Blog { 4 | let id: Int 5 | let name: String 6 | let author: String? 7 | let needsPassword: Bool 8 | let url: URL 9 | } 10 | 11 | -------------------------------------------------------------------------------- /lib/Extensions.js: -------------------------------------------------------------------------------- 1 | // 2 | // A parse function for parsing the AST dump from the swift compiler. 3 | // 4 | // Also extents the Array prototype with a bunch of useful functions for 5 | // inspecting the parsed AST. 6 | // 7 | Array.prototype.name = function () { 8 | return this[0]; 9 | }; 10 | Array.prototype.fields = function () { 11 | var fields = this.slice(1) 12 | .filter(not(isArray)); 13 | return fields; 14 | }; 15 | Array.prototype.contains = function (elem) { 16 | return this.indexOf(elem) > -1; 17 | }; 18 | Array.prototype.unique = function () { 19 | var unique = []; 20 | for (var i = 0; i < this.length; i++) { 21 | if (unique.indexOf(this[i]) == -1) { 22 | unique.push(this[i]); 23 | } 24 | } 25 | return unique; 26 | }; 27 | Array.prototype.keys = function () { 28 | return this.fields() 29 | .filter(not(isAttr)) 30 | .map(function (s) { 31 | if (typeof (s) != 'string') 32 | return s; 33 | var val = s.replace(/'/g, '"'); 34 | if (val.length && val[0] == '"') 35 | val = val.replace(/"/g, ''); 36 | return val; 37 | }); 38 | }; 39 | Array.prototype.key = function (ix) { 40 | var keys = this.keys(); 41 | if (!keys.length) 42 | throw 'index ' + ix + ' out of bounds for: ' + this; 43 | return keys[0]; 44 | }; 45 | Array.prototype.attrs = function () { 46 | return this.fields() 47 | .filter(isAttr) 48 | .map(function (s) { 49 | var ix = s.indexOf('='); 50 | var key = s.slice(0, ix); 51 | var val = s.slice(ix + 1); 52 | if (val.length > 2 && val.startsWith("'") && val.endsWith("'")) { 53 | try { 54 | val = JSON.parse('"' + val.substring(1, val.length - 1) + '"'); 55 | } 56 | catch (_) { 57 | } 58 | } 59 | return [key, val]; 60 | }); 61 | }; 62 | Array.prototype.attr = function (key) { 63 | var attrs = this.attrs() 64 | .filter(function (arr) { 65 | return arr[0] == key; 66 | }); 67 | if (!attrs.length) 68 | throw 'key "' + key + '" not in: ' + this; 69 | return attrs[0][1]; 70 | }; 71 | Array.prototype.children = function (name) { 72 | var arrays = this.filter(isArray); 73 | if (name) { 74 | arrays = arrays.filter(function (arr) { 75 | return isArray(name) ? name.contains(arr.name()) : arr.name() == name; 76 | }); 77 | } 78 | return arrays; 79 | }; 80 | Array.prototype.flatMap = function (f) { 81 | var nested = this.map(f); 82 | var merged = []; 83 | return merged.concat.apply(merged, nested); 84 | }; 85 | Array.prototype.any = function (predicate) { 86 | for (var i = 0; i < this.length; i++) { 87 | if (predicate(this[i])) { 88 | return true; 89 | } 90 | } 91 | return false; 92 | }; 93 | String.prototype.unquote = function () { 94 | return this.replace(/"(.*)"/g, '$1'); 95 | }; 96 | if (!String.prototype.startsWith) { 97 | Object.defineProperty(String.prototype, 'startsWith', { 98 | enumerable: false, 99 | configurable: false, 100 | writable: false, 101 | value: function (searchString, position) { 102 | position = position || 0; 103 | return this.lastIndexOf(searchString, position) === position; 104 | } 105 | }); 106 | } 107 | if (!String.prototype.endsWith) { 108 | Object.defineProperty(String.prototype, 'endsWith', { 109 | value: function (searchString, position) { 110 | var subjectString = this.toString(); 111 | if (position === undefined || position > subjectString.length) { 112 | position = subjectString.length; 113 | } 114 | position -= searchString.length; 115 | var lastIndex = subjectString.indexOf(searchString, position); 116 | return lastIndex !== -1 && lastIndex === position; 117 | } 118 | }); 119 | } 120 | if (!String.prototype.contains) { 121 | String.prototype.contains = function () { 122 | 'use strict'; 123 | return String.prototype.indexOf.apply(this, arguments) !== -1; 124 | }; 125 | } 126 | function not(f) { 127 | return function (x) { return !f(x); }; 128 | } 129 | function isAttr(s) { 130 | return s.indexOf('=') > 0; 131 | } 132 | function isArray(obj) { 133 | return obj === [] || typeof (obj) == 'object' && obj.length; 134 | } 135 | -------------------------------------------------------------------------------- /lib/Extensions.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"Extensions.js","sourceRoot":"","sources":["Extensions.ts"],"names":["not","isAttr","isArray"],"mappings":"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"} -------------------------------------------------------------------------------- /lib/JsonGen.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 3 | return new (P || (P = Promise))(function (resolve, reject) { 4 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 5 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 6 | function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } 7 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 8 | }); 9 | }; 10 | const bluebird = require('bluebird'); 11 | const exec = bluebird.promisify(require('child_process').exec, { multiArgs: true }); 12 | const fs = bluebird.promisifyAll(require('fs')); 13 | const mkdirp = bluebird.promisify(require('mkdirp')); 14 | const tmp = bluebird.promisify(require('tmp').dir); 15 | const path = require('path'); 16 | require('./Extensions'); 17 | var ast = require('./SwiftAst'); 18 | var printer = require('./SwiftPrinter'); 19 | var headerLength = 9; 20 | var swiftc = 'swiftc'; 21 | var sdk = '$(xcrun --show-sdk-path)'; 22 | // var swiftc = '/Applications/Xcode-9.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swiftc' 23 | // var sdk = '/Applications/Xcode-9.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk' 24 | function generate() { 25 | return __awaiter(this, void 0, void 0, function* () { 26 | var usage = 'USAGE: $0 [--accessLevel level] [-o output_directory] source_files...\n\n' 27 | + ' Generates +JsonGen.swift files for all swift files supplied,\n' 28 | + ' filenames ending with +Extensions.swift are excluded.'; 29 | var yargs = require('yargs') 30 | .usage(usage) 31 | .help() 32 | .alias('h', 'help') 33 | .alias('o', 'output') 34 | .alias('v', 'version') 35 | .describe('accessLevel', '"public" or "internal"') 36 | .describe('statham', 'Statham library directory') 37 | .describe('xcode', 'Path to Xcode.app') 38 | .describe('o', 'Output directory') 39 | .describe('v', 'Print version'); 40 | var argv = yargs.argv; 41 | if (argv.version) { 42 | var pjson = require('../package.json'); 43 | console.log(pjson.version); 44 | return; 45 | } 46 | const inputs = argv._; 47 | const outputDirectory = typeof (argv.output) == 'string' ? argv.output : null; 48 | const stathamDirectory = typeof (argv.statham) == 'string' ? argv.statham : null; 49 | const accessLevel = typeof (argv.accessLevel) == 'string' ? argv.accessLevel : null; 50 | const xcode = typeof (argv.xcode) == 'string' ? argv.xcode : null; 51 | // override swiftc and sdk paths 52 | if (xcode != null) { 53 | swiftc = xcode + '/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swiftc'; 54 | sdk = xcode + '/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk'; 55 | } 56 | if (accessLevel != null && accessLevel != 'public' && accessLevel != 'internal') { 57 | console.error('accessLevel must be "public" or "internal"'); 58 | return; 59 | } 60 | if (inputs.length == 0) { 61 | yargs.showHelp(); 62 | return; 63 | } 64 | yield checkSwiftVersion(); 65 | const stathamDir = yield compileStatham(); 66 | if (outputDirectory) { 67 | yield mkdirp(outputDirectory); 68 | } 69 | handleFiles(inputs, accessLevel, stathamDir, outputDirectory); 70 | function checkSwiftVersion() { 71 | return __awaiter(this, void 0, void 0, function* () { 72 | const supportedVersions = ['Apple Swift version 3.0', 'Apple Swift version 3.1']; 73 | const [stdout] = yield exec('"' + swiftc + '" --version'); 74 | const versions = supportedVersions.filter(version => stdout.startsWith(version)); 75 | if (versions.length == 0) { 76 | console.log('WARNING: Using untested swiftc version. swift-json-gen has been tested with:'); 77 | supportedVersions.forEach(function (version) { 78 | console.log(' - ' + version); 79 | }); 80 | } 81 | }); 82 | } 83 | function compileStatham() { 84 | return __awaiter(this, void 0, void 0, function* () { 85 | if (!stathamDirectory) { 86 | return null; 87 | } 88 | const stathamTempDir = yield tmp(); 89 | // From: http://stackoverflow.com/a/27047477/2597 90 | const cmd = 'xcrun "' + swiftc + '" -sdk "' + sdk + '"' 91 | + ' -module-name Statham' 92 | + ' -emit-module-path ' + stathamTempDir 93 | + ' -emit-module ' + stathamDirectory + '/Sources/*.swift'; 94 | yield exec(cmd); 95 | return stathamTempDir; 96 | }); 97 | } 98 | }); 99 | } 100 | function fullFilenames(input) { 101 | return __awaiter(this, void 0, void 0, function* () { 102 | const stat = yield fs.statAsync(input); 103 | if (stat.isDirectory()) { 104 | const inputFiles = yield fs.readdirAsync(input); 105 | const filenamePromises = inputFiles.map(fn => fullFilenames(path.join(input, fn))); 106 | const filenamesArray = yield bluebird.all(filenamePromises); 107 | return filenamesArray.flatMap(x => x); 108 | } 109 | else if (stat.isFile()) { 110 | return [input]; 111 | } 112 | throw new Error("input is neither a file nor a directory"); 113 | }); 114 | } 115 | function fileDescription(filename, allFilenames, outputDirectory) { 116 | var dirname = path.dirname(filename); 117 | var basename = path.basename(filename); 118 | var outbase = basename.replace('.swift', '+JsonGen.swift'); 119 | var outfile = outputDirectory ? path.join(outputDirectory, outbase) : path.join(dirname, outbase); 120 | return { 121 | filename: basename, 122 | fullname: path.join(dirname, basename), 123 | outbase: outbase, 124 | outfile: outfile, 125 | }; 126 | } 127 | function containsPodError(s) { 128 | return s.contains('error: use of undeclared type \'AnyJson\'') 129 | || s.contains('error: use of undeclared type \'JsonObject\'') 130 | || s.contains('error: use of undeclared type \'JsonArray\'') 131 | || s.contains('error: no such module \'Statham\''); 132 | } 133 | function handleFiles(inputs, accessLevel, stathamTempDir, outputDirectory) { 134 | return __awaiter(this, void 0, void 0, function* () { 135 | var inputFilenames = yield bluebird.all(inputs.map(fullFilenames)); 136 | var filenames = inputFilenames.flatMap(x => x); 137 | var files = filenames 138 | .map(fn => fileDescription(fn, filenames, outputDirectory)) 139 | .filter(function (f) { 140 | var isExtensions = f.filename.indexOf('+Extensions.swift') > 0; 141 | var isJsonGen = f.filename.indexOf('+JsonGen.swift') > 0; 142 | var isSwift = f.filename.indexOf('.swift') > 0; 143 | return isSwift && !isJsonGen && !isExtensions; 144 | }); 145 | var filenamesString = files.map(f => '"' + f.fullname + '"').join(' '); 146 | var statham = ''; 147 | if (stathamTempDir) { 148 | statham = ' -I ' + stathamTempDir + ' -L ' + stathamTempDir + ' -lStatham -module-link-name Statham'; 149 | } 150 | var cmd = 'xcrun "' + swiftc + '"' + statham + ' -sdk "' + sdk + '" -dump-ast ' + filenamesString; 151 | var opts = { 152 | maxBuffer: 200 * 1024 * 1024 153 | }; 154 | const [stdout, stderr] = yield exec(cmd, opts); 155 | var parseResult = parseXcOutput(stderr); 156 | var xcoutputs = parseResult.outputs; 157 | var errors = parseResult.errors; 158 | // If an actual error (not a `(source_file`), print and stop 159 | if (errors.length) { 160 | errors.forEach(error => { 161 | console.error(error); 162 | }); 163 | if (errors.any(containsPodError) && !stathamTempDir) { 164 | console.error(''); 165 | console.error('When using Statham library include argument: --statham=Pods/Statham'); 166 | } 167 | return; 168 | } 169 | if (xcoutputs.length != files.length) { 170 | console.error('INTERNAL ERROR - swift-json-gen'); 171 | console.error('inconsistency; xcoutputs not equal in length to files'); 172 | console.error('xcoutputs.length: ' + xcoutputs.length + ', files: ' + files.length); 173 | console.error(); 174 | console.error('Please report this at: https://github.com/tomlokhorst/swift-json-gen/issues'); 175 | return; 176 | } 177 | var fileAsts = xcoutputs.map(ast.parse); 178 | var mergedFileAsts = [].concat.apply([], fileAsts); 179 | var globalAttrs = ast.globalAttrs(mergedFileAsts); 180 | for (var i = 0; i < files.length; i++) { 181 | const file = files[i]; 182 | const fileAst = fileAsts[i]; 183 | if (file.filename == 'JsonGen.swift') 184 | continue; 185 | var lines = printer.makeFile(fileAst, accessLevel, globalAttrs, file.outbase); 186 | if (lines.length == 0) 187 | continue; 188 | var text = lines.join('\n'); 189 | yield printFile(text, file.outfile); 190 | } 191 | }); 192 | } 193 | function parseXcOutput(output) { 194 | // Separate outputs 195 | // Each non-error output starts with `(`, subsequent lines start with ` ` or `)` 196 | var lines = output.split(/\n/g); 197 | var xcoutputs = []; 198 | var errors = []; 199 | var current = []; 200 | for (var i = 0; i < lines.length; i++) { 201 | var line = lines[i]; 202 | if (line.length == 0 || line[0] == ' ' || line[0] == ')') { 203 | current.push(line); 204 | } 205 | else { 206 | var merged = current.join('\n'); 207 | if (current.length && merged.indexOf('(source_file') == 0) 208 | xcoutputs.push(merged); 209 | else if (current.length) 210 | errors.push(merged); 211 | current = [line]; 212 | } 213 | } 214 | var merged = current.join('\n'); 215 | if (current.length && merged.indexOf('(source_file') == 0) 216 | xcoutputs.push(merged); 217 | else if (current.length) 218 | errors.push(merged); 219 | return { errors: errors, outputs: xcoutputs }; 220 | } 221 | function printFile(text, outfile) { 222 | return __awaiter(this, void 0, void 0, function* () { 223 | // Ignore first 4? lines (containing only generated date) 224 | var outputBody = text.split('\n').slice(headerLength).join('\n'); 225 | try { 226 | const existing = yield fs.readFileAsync(outfile, 'utf8'); 227 | if (existing) { 228 | var existingBody = existing.split('\n').slice(headerLength).join('\n'); 229 | // No changes since existing 230 | if (outputBody == existingBody) 231 | return; 232 | } 233 | } 234 | catch (_) { 235 | // If no exising file and no output body 236 | if (outputBody == '') 237 | return; 238 | } 239 | yield fs.writeFileAsync(outfile, text, 'utf8'); 240 | }); 241 | } 242 | exports.generate = generate; 243 | -------------------------------------------------------------------------------- /lib/JsonGen.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"JsonGen.js","sourceRoot":"","sources":["JsonGen.ts"],"names":["fullFilenames","fileDescription","generate","parseXcOutput","printFile"],"mappings":"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"} -------------------------------------------------------------------------------- /lib/SwiftAst.js: -------------------------------------------------------------------------------- 1 | // 2 | // A parse function for parsing the AST dump from the swift compiler. 3 | // 4 | function globalAttrs(ast) { 5 | var tfns = typeFuncNames(ast); 6 | var decoders = tfns 7 | .filter(d => d.funcNames.contains('decodeJson')) 8 | .map(d => d.typeName); 9 | var encoders = tfns 10 | .filter(d => d.funcNames.contains('encodeJson')) 11 | .map(d => d.typeName); 12 | var constructors = {}; 13 | tfns.forEach(tfn => { 14 | var xs = constructors[tfn.typeName] || []; 15 | if (tfn.constructorParams.length) { 16 | constructors[tfn.typeName] = xs.concat(tfn.constructorParams); 17 | } 18 | }); 19 | return { 20 | typeAliases: typeAliases(ast), 21 | constructors: constructors, 22 | decoders: decoders, 23 | encoders: encoders, 24 | }; 25 | } 26 | exports.globalAttrs = globalAttrs; 27 | function typeFuncNames(ast) { 28 | var emptyAliases = {}; 29 | var ds1 = structs(ast, emptyAliases) 30 | .map(s => { 31 | return { 32 | typeName: s.baseName, 33 | constructorParams: s.constructorParams, 34 | funcNames: s.funcNames 35 | }; 36 | }); 37 | var ds2 = enums(ast, emptyAliases) 38 | .map(e => { 39 | return { 40 | typeName: e.baseName, 41 | constructorParams: e.constructorParams, 42 | funcNames: e.funcNames 43 | }; 44 | }); 45 | var ds3 = ast 46 | .children('extension_decl') 47 | .map(s => { 48 | return { 49 | typeName: extension(s).typeBaseName, 50 | constructorParams: constructorParams(s), 51 | funcNames: funcNames(s) 52 | }; 53 | }); 54 | return ds1.concat(ds2).concat(ds3); 55 | } 56 | function funcNames(ast) { 57 | return ast.children('func_decl').map(f => f.key(0) == 'implicit' ? f.key(1) : f.key(0)); 58 | } 59 | function constructorParams(ast) { 60 | return ast.children('constructor_decl') 61 | .filter(a => a.attr('access') != 'private' && a.attr('access') != 'fileprivate') 62 | .flatMap(constructorDeclParams); 63 | } 64 | function constructorDeclParams(constructorDecl) { 65 | const parts = constructorDecl 66 | .filter(obj => (typeof (obj) == 'object' && obj.length == 0) || (typeof (obj) == 'object' && obj.length == 1 && typeof (obj[0]) == 'string')) 67 | .map(a => a.length ? a[0] : ''); 68 | if (parts.length < 3) { 69 | return []; 70 | } 71 | const names = parts[0]; 72 | const types = parts[2]; 73 | return [names + '||' + types]; 74 | } 75 | function extension(ast) { 76 | var fullName = ast.key(0); 77 | var keys = ast.keys().slice(1); 78 | while (fullName.contains('<') && !fullName.contains('>') && keys.length > 0) { 79 | fullName += keys.splice(0, 1)[0]; 80 | } 81 | var baseName = fullName.replace(/<([^>]*)>/g, ''); 82 | return { typeBaseName: baseName }; 83 | } 84 | function typeAliases(ast) { 85 | var aliases = {}; 86 | ast.children('typealias') 87 | .forEach(function (t) { 88 | var name = t.fields().name().unquote(); 89 | var type = t.attrs().filter(attr => attr[0] == 'type')[1][1]; 90 | if (!type.startsWith("'") && type.endsWith("'")) { 91 | type = type.substring(0, type.length - 1); 92 | } 93 | aliases[name] = type; 94 | }); 95 | return aliases; 96 | } 97 | function getBaseName(ast, prefix) { 98 | prefix = prefix ? prefix + '.' : ''; 99 | var fullName = ast.key(0); 100 | return prefix + fullName.replace(/<([^>]*)>/g, ''); 101 | } 102 | function structs(ast, aliases, prefix) { 103 | var structs1 = ast.children('struct_decl') 104 | .map(a => struct(a, aliases, prefix)); 105 | var structs2 = ast.children(['struct_decl', 'enum_decl']) 106 | .flatMap(a => structs(a, aliases, getBaseName(a, prefix))); 107 | return structs1.concat(structs2); 108 | } 109 | exports.structs = structs; 110 | function struct(ast, aliases, prefix) { 111 | var baseName = getBaseName(ast, prefix); 112 | var fullName = ast.key(0); 113 | var typeArgs = genericArguments(ast); 114 | var varDecls = ast.children('var_decl') 115 | .filter(a => a.attr('storage_kind') == 'stored_with_trivial_accessors') 116 | .map(a => varDecl(a, aliases)); 117 | var r = { 118 | baseName: baseName, 119 | typeArguments: typeArgs, 120 | varDecls: varDecls, 121 | constructorParams: constructorParams(ast), 122 | funcNames: funcNames(ast) 123 | }; 124 | return r; 125 | } 126 | function enums(ast, aliases, prefix) { 127 | var enums1 = ast 128 | .children('enum_decl') 129 | .filter(a => { 130 | var keys = a.keys(); 131 | var ix = keys.indexOf('inherits:'); 132 | return ix > 0 && keys.length > ix + 1; 133 | }) 134 | .map(a => enum_(a, aliases, prefix)); 135 | var enums2 = ast.children(['struct_decl', 'enum_decl']) 136 | .flatMap(a => enums(a, aliases, getBaseName(a, prefix))); 137 | return enums1.concat(enums2); 138 | } 139 | exports.enums = enums; 140 | function enum_(ast, aliases, prefix) { 141 | var baseName = getBaseName(ast, prefix); 142 | var fullName = ast.key(0); 143 | var keys = ast.keys(); 144 | var ix = keys.indexOf('inherits:'); 145 | var rawTypeName = keys[ix + 1]; 146 | var r = { 147 | baseName: baseName, 148 | rawTypeName: rawTypeName, 149 | constructorParams: constructorParams(ast), 150 | funcNames: funcNames(ast) 151 | }; 152 | return r; 153 | } 154 | function genericArguments(ast) { 155 | // Swift 3.0 has generic arguments as part of fullName 156 | // Swift 3.1 has generic arguments as separate parts, after fullName 157 | var generics = ast.key(0); 158 | const keys = ast.keys(); 159 | for (var ix = 1; ix < keys.length; ix++) { 160 | const key = keys[ix]; 161 | if (key == 'interface') { 162 | break; 163 | } 164 | if (key == '@_fixed_layout') { 165 | break; 166 | } 167 | generics += key; 168 | } 169 | var matches = generics.match(/<([^>]*)>/); 170 | if (matches && matches.length == 2) 171 | return matches[1].split(',').map(s => s.trim()); 172 | return []; 173 | } 174 | function varDecl(ast, aliases) { 175 | return { name: ast.key(0), type: type(ast.attr('type'), aliases) }; 176 | } 177 | function type(typeString, aliases) { 178 | if (aliases[typeString]) { 179 | var resolved = type(aliases[typeString], aliases); 180 | resolved.alias = typeString; 181 | return resolved; 182 | } 183 | var isBracketed = typeString.startsWith('[') && typeString.endsWith(']'); 184 | var isGeneric = typeString.match(/\<(.*)>/); 185 | var isDictionary = isBracketed && typeString.contains(':'); 186 | var isArray = isBracketed && !typeString.contains(':'); 187 | var isOptional = typeString.endsWith('?'); 188 | if (isOptional) { 189 | var inner = typeString.substring(0, typeString.length - 1).trim(); 190 | return { baseName: 'Optional', genericArguments: [type(inner, aliases)] }; 191 | } 192 | if (isArray) { 193 | var inner = typeString.substring(1, typeString.length - 1).trim(); 194 | return { baseName: 'Array', genericArguments: [type(inner, aliases)] }; 195 | } 196 | if (isDictionary) { 197 | var matches = typeString.match(/\[(.*):(.*)\]/); 198 | if (matches.length != 3) 199 | throw new Error('"' + typeString + '" appears to be a Dictionary, but isn\'t'); 200 | var keyType = type(matches[1].trim(), aliases); 201 | var valueType = type(matches[2].trim(), aliases); 202 | return { baseName: 'Dictionary', genericArguments: [keyType, valueType] }; 203 | } 204 | if (isDictionary) { 205 | var matches = typeString.match(/\[(.*):(.*)\]/); 206 | if (matches.length != 3) 207 | throw new Error('"' + typeString + '" appears to be a Dictionary, but isn\'t'); 208 | var keyType = type(matches[1].trim(), aliases); 209 | var valueType = type(matches[2].trim(), aliases); 210 | return { baseName: 'Dictionary', genericArguments: [keyType, valueType] }; 211 | } 212 | if (isGeneric) { 213 | var baseName = typeString.replace(/<([^>]*)>/g, ''); 214 | var matches = typeString.match(/\<(.*)>/); 215 | if (matches.length != 2) 216 | throw new Error('"' + typeString + '" appears to be a generic type, but isn\'t'); 217 | var types = matches[1] 218 | .split(',') 219 | .map(t => t.trim()) 220 | .map(mkType); 221 | return { baseName: baseName, genericArguments: types }; 222 | } 223 | return { baseName: typeString, genericArguments: [] }; 224 | } 225 | function mkType(name) { 226 | return { baseName: name, genericArguments: [] }; 227 | } 228 | // Based on: https://github.com/arian/LISP.js 229 | function parse(text) { 230 | var results = []; 231 | text = text.trim(); 232 | // text = text.replace(/=\[([^\]]*)\]'/g, function (n) { return n.replace(/ /g, 'JSON_GEN_SPACE') } ) // Workaround for swiftc 2.0 233 | text = text.replace(/='([^']*)'/g, function (n) { return n.replace(/ /g, 'JSON_GEN_SPACE'); }); 234 | text = text.replace(/"<([^>]*)>/g, function (n) { return n.replace(/ /g, 'JSON_GEN_SPACE'); }); 235 | if (text.charAt(0) != '(') 236 | return text; 237 | var stack = []; 238 | var token; 239 | var tokens = ''; 240 | var inString = false; 241 | var i = 0; 242 | var current; 243 | while (i < text.length) { 244 | token = text.charAt(i++); 245 | var isOpen = token == '('; 246 | var isClose = token == ')'; 247 | var isSpace = token == ' ' && !inString; 248 | if (isOpen || isClose || isSpace) { 249 | if (current && tokens.length) { 250 | var n = +tokens; 251 | var tokens_ = tokens.replace(/JSON_GEN_SPACE/g, ' '); 252 | current.push(isNaN(n) ? tokens_ : n); 253 | } 254 | tokens = ''; 255 | } 256 | else { 257 | if (token == '"') 258 | inString = !inString; 259 | if (!/\s/.test(token) || inString) 260 | tokens += token; 261 | } 262 | if (isOpen) { 263 | var previous = current; 264 | current = []; 265 | if (previous) { 266 | stack.push(previous); 267 | previous.push(current); 268 | } 269 | } 270 | else if (isClose) { 271 | var pop = stack.pop(); 272 | if (!pop) { 273 | return current; 274 | } 275 | current = pop; 276 | } 277 | } 278 | var msg = 'INTERNAL ERROR:\n' 279 | + 'Likely due to errornous output from Swift compiler on some language construct (like a switch or array ializer).\n' 280 | + 'Workaround: Change all methods from SomeFile.swift into extensions methods in SomeFile+Extensions.swift, which is ignored by JsonGen.\n\n' 281 | + 'For details, please create an issue (including the failing Swift sources):\nhttps://github.com/tomlokhorst/swift-json-gen/issues'; 282 | console.error(msg); 283 | throw 'unbalanced parentheses'; 284 | } 285 | ; 286 | exports.parse = parse; 287 | -------------------------------------------------------------------------------- /lib/SwiftAst.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"SwiftAst.js","sourceRoot":"","sources":["SwiftAst.ts"],"names":["globalAttrs","typeFuncNames","funcNames","extension","typeAliases","getBaseName","structs","struct","enums","enum_","genericArguments","varDecl","type","mkType","parse"],"mappings":"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"} -------------------------------------------------------------------------------- /lib/SwiftPrinter.js: -------------------------------------------------------------------------------- 1 | // 2 | // Several functions for generating Swift code based on the parsed AST. 3 | // 4 | var ast = require('./SwiftAst'); 5 | function makeFile(file, accessLevel, globalAttrs, filename) { 6 | const accessLevelPrefix = accessLevel == null ? '' : accessLevel + ' '; 7 | function constructorExists(struct) { 8 | const paramNames = struct.varDecls.map(vd => vd.name + ':'); 9 | const paramTypes = struct.varDecls.map(vd => typeString(vd.type)); 10 | const paramsString = paramNames.join('') + '||' + paramTypes.join(', '); 11 | const constructors = globalAttrs.constructors[struct.baseName] || []; 12 | return constructors.contains(paramsString); 13 | } 14 | function decoderExists(typeName) { 15 | return globalAttrs.decoders.contains(typeName); 16 | } 17 | function encoderExists(typeName) { 18 | return globalAttrs.encoders.contains(typeName); 19 | } 20 | var structs = ast.structs(file, globalAttrs.typeAliases) 21 | .filter(s => !constructorExists(s) || !decoderExists(s.baseName) || !encoderExists(s.baseName)); 22 | var enums = ast.enums(file, globalAttrs.typeAliases) 23 | .filter(e => !decoderExists(e.baseName) || !encoderExists(e.baseName)); 24 | var lines = []; 25 | lines.push('//'); 26 | lines.push('// ' + filename); 27 | lines.push('//'); 28 | lines.push('// Auto generated by swift-json-gen on ' + new Date().toUTCString()); 29 | lines.push('// See for details: https://github.com/tomlokhorst/swift-json-gen'); 30 | lines.push('//'); 31 | lines.push(''); 32 | lines.push('import Foundation'); 33 | lines.push('import Statham'); 34 | lines.push(''); 35 | enums.forEach(function (s) { 36 | var createDecoder = !decoderExists(s.baseName); 37 | var createEncoder = !encoderExists(s.baseName); 38 | lines.push('extension ' + escaped(s.baseName) + ' {'); 39 | if (createDecoder) { 40 | lines = lines.concat(makeEnumDecoder(s, accessLevelPrefix)); 41 | } 42 | if (createDecoder && createEncoder) { 43 | lines.push(''); 44 | } 45 | if (createEncoder) { 46 | lines = lines.concat(makeEnumEncoder(s, accessLevelPrefix)); 47 | } 48 | lines.push('}'); 49 | lines.push(''); 50 | }); 51 | structs.forEach(function (s) { 52 | var createConstructor = !constructorExists(s); 53 | var createDecoder = !decoderExists(s.baseName); 54 | var createEncoder = !encoderExists(s.baseName); 55 | lines.push('extension ' + escaped(s.baseName) + ' {'); 56 | if (createDecoder) { 57 | lines = lines.concat(makeStructDecoder(s, accessLevelPrefix)); 58 | } 59 | if (createDecoder && (createConstructor || createEncoder)) { 60 | lines.push(''); 61 | } 62 | if (createConstructor) { 63 | lines = lines.concat(makeStructConstructor(s, accessLevelPrefix)); 64 | } 65 | if (createConstructor && createEncoder) { 66 | lines.push(''); 67 | } 68 | if (createEncoder) { 69 | lines = lines.concat(makeStructEncoder(s, enums, accessLevelPrefix)); 70 | } 71 | lines.push('}'); 72 | lines.push(''); 73 | }); 74 | return lines; 75 | } 76 | exports.makeFile = makeFile; 77 | function makeEnumDecoder(en, accessLevelPrefix) { 78 | var lines = []; 79 | lines.push(' ' + accessLevelPrefix + 'static func decodeJson(_ json: Any) throws -> ' + escaped(en.baseName) + ' {'); 80 | lines.push(' guard let rawValue = json as? ' + escaped(en.rawTypeName) + ' else {'); 81 | lines.push(' throw JsonDecodeError.wrongType(rawValue: json, expectedType: "' + en.rawTypeName + '")'); 82 | lines.push(' }'); 83 | lines.push(' guard let value = ' + escaped(en.baseName) + '(rawValue: rawValue) else {'); 84 | lines.push(' throw JsonDecodeError.wrongEnumRawValue(rawValue: rawValue, enumType: "' + en.baseName + '")'); 85 | lines.push(' }'); 86 | lines.push(''); 87 | lines.push(' return value'); 88 | lines.push(' }'); 89 | return lines.join('\n'); 90 | } 91 | function makeEnumEncoder(en, accessLevelPrefix) { 92 | var lines = []; 93 | lines.push(' ' + accessLevelPrefix + 'func encodeJson() -> ' + escaped(en.rawTypeName) + ' {'); 94 | lines.push(' return rawValue'); 95 | lines.push(' }'); 96 | return lines.join('\n'); 97 | } 98 | function makeStructConstructor(struct, accessLevelPrefix) { 99 | var lines = []; 100 | const paramsStrings = struct.varDecls.map(vd => vd.name + ': ' + typeString(vd.type)); 101 | lines.push('fileprivate init(' + paramsStrings.join(', ') + ') {'); 102 | struct.varDecls.forEach(varDecl => { 103 | lines.push(' self.' + varDecl.name + ' = ' + escaped(varDecl.name)); 104 | }); 105 | lines.push('}'); 106 | return lines.map(indent(2)).join('\n'); 107 | } 108 | function makeStructDecoder(struct, accessLevelPrefix) { 109 | var lines = []; 110 | var curried = struct.typeArguments.length > 0; 111 | if (curried) { 112 | lines.push(' ' + accessLevelPrefix + 'static func decodeJson' + decodeArguments(struct) + ' -> (Any) throws -> ' + escaped(struct.baseName) + ' {'); 113 | lines.push(' return { json in'); 114 | } 115 | else { 116 | lines.push(' ' + accessLevelPrefix + 'static func decodeJson(_ json: Any) throws -> ' + escaped(struct.baseName) + ' {'); 117 | } 118 | var body = makeStructDecoderBody(struct).map(indent(curried ? 6 : 4)); 119 | lines = lines.concat(body); 120 | if (curried) { 121 | lines.push(' }'); 122 | } 123 | lines.push(' }'); 124 | return lines.join('\n'); 125 | } 126 | function decodeArguments(struct) { 127 | var parts = struct.typeArguments 128 | .map(typeVar => '_ decode' + typeVar + ': @escaping (Any) throws -> ' + escaped(typeVar)); 129 | return '(' + parts.join(', ') + ')'; 130 | } 131 | function makeStructDecoderBody(struct) { 132 | if (struct.varDecls.length == 0) { 133 | return ['return ' + struct.baseName + '()']; 134 | } 135 | var lines = []; 136 | lines.push('let decoder = try JsonDecoder(json: json)'); 137 | lines.push(''); 138 | struct.varDecls.forEach(function (field, ix) { 139 | var decoder = decodeFunction(field.type, struct.typeArguments); 140 | var line = 'let _' + field.name + ' = ' 141 | + 'try decoder.decode("' + field.name + '", decoder: ' + decoder + ')'; 142 | lines.push(line); 143 | }); 144 | lines.push(''); 145 | var fieldDecodes = struct.varDecls.map(function (field, ix) { 146 | var isLast = struct.varDecls.length == ix + 1; 147 | var commaOrBrace = isLast ? '' : ','; 148 | var line = 'let ' + escaped(field.name) + ' = _' + field.name + commaOrBrace; 149 | return line; 150 | }); 151 | if (fieldDecodes.length == 1) { 152 | lines.push('guard ' + fieldDecodes[0] + ' else {'); 153 | } 154 | else { 155 | lines.push('guard'); 156 | lines = lines.concat(fieldDecodes.map(indent(2))); 157 | lines.push('else {'); 158 | } 159 | var params = struct.varDecls.map(decl => decl.name + ': ' + escaped(decl.name)); 160 | lines.push(' throw JsonDecodeError.structErrors(type: "' + struct.baseName + '", errors: decoder.errors)'); 161 | lines.push('}'); 162 | lines.push(''); 163 | lines.push('return ' + escaped(struct.baseName) + '(' + params.join(', ') + ')'); 164 | return lines; 165 | } 166 | function typeString(type) { 167 | var args = type.genericArguments 168 | .map(typeString); 169 | var argList = args.length ? '<' + args.join(', ') + '>' : ''; 170 | var typeName = type.alias || type.baseName; 171 | if (typeName == 'Optional' && args.length == 1) { 172 | return args[0] + '?'; 173 | } 174 | if (typeName == 'Array' && args.length == 1) { 175 | return '[' + args[0] + ']'; 176 | } 177 | if (typeName == 'Dictionary' && args.length == 2) { 178 | return '[' + args[0] + ' : ' + args[1] + ']'; 179 | } 180 | if (type.alias) { 181 | return type.alias; 182 | } 183 | return typeName + argList; 184 | } 185 | function decodeFunction(type, genericDecoders) { 186 | if (isKnownType(type)) 187 | return '{ $0 }'; 188 | var args = type.genericArguments 189 | .map(a => decodeFunction(a, genericDecoders)) 190 | .join(', '); 191 | var argList = args.length ? '(' + args + ')' : ''; 192 | var typeName = type.alias || type.baseName; 193 | if (genericDecoders.contains(typeName)) 194 | return 'decode' + typeName + argList; 195 | return typeName + '.decodeJson' + argList; 196 | } 197 | function makeStructEncoder(struct, enums, accessLevelPrefix) { 198 | var lines = []; 199 | lines.push(' ' + accessLevelPrefix + 'func encodeJson' + encodeArguments(struct) + ' -> [String: Any] {'); 200 | var body = makeStructEncoderBody(struct, enums).map(indent(4)); 201 | lines = lines.concat(body); 202 | lines.push(' }'); 203 | return lines.join('\n'); 204 | } 205 | function encodeArguments(struct) { 206 | var parts = struct.typeArguments 207 | .map(typeVar => '_ encode' + typeVar + ': (' + escaped(typeVar) + ') -> Any'); 208 | return '(' + parts.join(', ') + ')'; 209 | } 210 | function makeStructEncoderBody(struct, enums) { 211 | if (struct.varDecls.length == 0) { 212 | return ['return [:]']; 213 | } 214 | var lines = []; 215 | lines.push('var dict: [String: Any] = [:]'); 216 | lines.push(''); 217 | struct.varDecls.forEach(function (d) { 218 | var subs = makeFieldEncode(d, struct.typeArguments, enums); 219 | lines = lines.concat(subs); 220 | }); 221 | lines.push(''); 222 | lines.push('return dict'); 223 | return lines; 224 | } 225 | function encodeFunction(name, type, genericEncoders) { 226 | if (isKnownType(type)) 227 | return name; 228 | if (genericEncoders.contains(type.baseName)) 229 | return 'encode' + type.baseName + '(' + name + ')'; 230 | var args = type.genericArguments 231 | .map(t => '{ ' + encodeFunction('$0', t, genericEncoders) + ' }') 232 | .join(', '); 233 | return escaped(name) + '.encodeJson(' + args + ')'; 234 | } 235 | function makeFieldEncode(field, structTypeArguments, enums) { 236 | var lines = []; 237 | var name = field.name; 238 | var type = field.type; 239 | var prefix = ''; 240 | if (type.baseName == 'Dictionary' && type.genericArguments.length == 2) { 241 | var keyType = type.genericArguments[0].baseName; 242 | var enum_ = enums.filter(e => e.baseName == keyType)[0]; 243 | if (keyType != 'String' && enum_.rawTypeName != 'String') { 244 | lines.push('/* WARNING: Json only supports Strings as keys in dictionaries */'); 245 | } 246 | } 247 | lines.push('dict["' + name + '"] = ' + encodeFunction(name, type, structTypeArguments)); 248 | return lines; 249 | } 250 | function indent(nr) { 251 | return function (s) { 252 | return s == '' ? s : Array(nr + 1).join(' ') + s; 253 | }; 254 | } 255 | function isKnownType(type) { 256 | var types = ['Any', 'AnyObject', 'AnyJson']; 257 | return types.contains(type.alias) || types.contains(type.baseName); 258 | } 259 | // Copied from R.swift: 260 | // Based on https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/doc/uid/TP40014097-CH30-ID413 261 | let swiftKeywords = [ 262 | // Keywords used in declarations 263 | "associatedtype", "class", "deinit", "enum", "extension", "func", "import", "init", "inout", "internal", "let", "operator", "private", "protocol", "public", "static", "struct", "subscript", "typealias", "var", 264 | // Keywords used in statements 265 | "break", "case", "continue", "default", "defer", "do", "else", "fallthrough", "for", "guard", "if", "in", "repeat", "return", "switch", "where", "while", 266 | // Keywords used in expressions and types 267 | "as", "catch", "dynamicType", "false", "is", "nil", "rethrows", "super", "self", "Self", "throw", "throws", "true", "try", "__COLUMN__", "__FILE__", "__FUNCTION__", "__LINE__", 268 | ]; 269 | function escaped(name) { 270 | if (swiftKeywords.contains(name)) { 271 | return '`' + name + '`'; 272 | } 273 | else { 274 | return name; 275 | } 276 | } 277 | -------------------------------------------------------------------------------- /lib/SwiftPrinter.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"SwiftPrinter.js","sourceRoot":"","sources":["SwiftPrinter.ts"],"names":["makeFile","makeFile.decoderExists","makeFile.encoderExists","makeEnumDecoder","makeEnumEncoder","makeStructDecoder","makeStructEncoder","decodeArguments","encodeArguments","indent","isKnownType","isCastType","encodeFunction","makeFieldEncode","decodeFunction","decodeFunctionArgument","typeToString","makeFieldDecode","makeReturn"],"mappings":"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"} -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "swift-json-gen", 3 | "version": "1.2.0", 4 | "description": "Generate Swift Json encoders and decoders based on Swift structs.", 5 | "main": "lib/JsonGen", 6 | "bin": { 7 | "swift-json-gen": "./bin/swift-json-gen" 8 | }, 9 | "repository": "tomlokhorst/swift-json-gen", 10 | "homepage": "https://github.com/tomlokhorst/swift-json-gen", 11 | "author": "Tom Lokhorst", 12 | "license": "MIT", 13 | "dependencies": 14 | { 15 | "yargs": "~4.2", 16 | "mkdirp": "~0.5", 17 | "tmp": "~0.0.28", 18 | "bluebird": "~3.5.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Extensions.ts: -------------------------------------------------------------------------------- 1 | // 2 | // A parse function for parsing the AST dump from the swift compiler. 3 | // 4 | // Also extents the Array prototype with a bunch of useful functions for 5 | // inspecting the parsed AST. 6 | // 7 | 8 | interface Array { 9 | name(): string; 10 | fields(): Array; 11 | contains(elem: T): boolean; 12 | unique(): Array; 13 | 14 | keys(): Array; 15 | key(ix: Number): string; 16 | 17 | attrs(): Array; 18 | attr(key: string): string; 19 | 20 | children(name: string): Array; 21 | children(names: string[]): Array; 22 | 23 | flatMap(f: (arg: T) => Array): Array; 24 | 25 | any(predicate: (arg: T) => boolean): boolean; 26 | } 27 | 28 | interface String { 29 | unquote(): string; 30 | 31 | startsWith(searchString: string, position?: Number): boolean; 32 | endsWith(searchString: string, position?: Number): boolean; 33 | contains(searchString: string, position?: Number): boolean; 34 | } 35 | 36 | Array.prototype.name = function () { 37 | return this[0]; 38 | } 39 | 40 | Array.prototype.fields = function () { 41 | var fields = this.slice(1) 42 | .filter(not(isArray)) 43 | 44 | return fields; 45 | } 46 | 47 | Array.prototype.contains = function (elem) { 48 | return this.indexOf(elem) > -1; 49 | } 50 | 51 | Array.prototype.unique = function() { 52 | var unique = []; 53 | for (var i = 0; i < this.length; i++) { 54 | if (unique.indexOf(this[i]) == -1) { 55 | unique.push(this[i]); 56 | } 57 | } 58 | 59 | return unique; 60 | } 61 | 62 | Array.prototype.keys = function () { 63 | return this.fields() 64 | .filter(not(isAttr)) 65 | .map(function (s) { 66 | if (typeof(s) != 'string') return s; 67 | 68 | var val = s.replace(/'/g, '"'); 69 | 70 | if (val.length && val[0] == '"') 71 | val = val.replace(/"/g, ''); 72 | 73 | return val; 74 | }) 75 | } 76 | 77 | Array.prototype.key = function (ix) { 78 | var keys = this.keys(); 79 | 80 | if (!keys.length) 81 | throw 'index ' + ix + ' out of bounds for: ' + this; 82 | 83 | return keys[0]; 84 | } 85 | 86 | Array.prototype.attrs = function () { 87 | return this.fields() 88 | .filter(isAttr) 89 | .map(function (s) { 90 | var ix = s.indexOf('='); 91 | var key = s.slice(0, ix); 92 | var val = s.slice(ix + 1); 93 | 94 | if (val.length > 2 && val.startsWith("'") && val.endsWith("'")) { 95 | try { 96 | val = JSON.parse('"' + val.substring(1, val.length - 1) + '"'); 97 | } 98 | catch (_) { 99 | } 100 | } 101 | 102 | return [key, val]; 103 | }); 104 | } 105 | 106 | Array.prototype.attr = function (key) { 107 | var attrs = this.attrs() 108 | .filter(function (arr) { 109 | return arr[0] == key; 110 | }); 111 | 112 | if (!attrs.length) 113 | throw 'key "' + key + '" not in: ' + this; 114 | 115 | return attrs[0][1]; 116 | } 117 | 118 | Array.prototype.children = function (name) { 119 | var arrays = this.filter(isArray); 120 | 121 | if (name) { 122 | arrays = arrays.filter(function (arr) { 123 | return isArray(name) ? name.contains(arr.name()) : arr.name() == name; 124 | }); 125 | } 126 | 127 | return arrays; 128 | } 129 | 130 | Array.prototype.flatMap = function (f) { 131 | var nested = this.map(f); 132 | 133 | var merged = []; 134 | return merged.concat.apply(merged, nested); 135 | } 136 | 137 | Array.prototype.any = function (predicate) { 138 | for (var i = 0; i < this.length; i++) { 139 | if (predicate(this[i])) { 140 | return true; 141 | } 142 | } 143 | 144 | return false 145 | } 146 | 147 | String.prototype.unquote = function () { 148 | return this.replace(/"(.*)"/g, '$1'); 149 | } 150 | 151 | if (!String.prototype.startsWith) { 152 | Object.defineProperty(String.prototype, 'startsWith', { 153 | enumerable: false, 154 | configurable: false, 155 | writable: false, 156 | value: function (searchString, position) { 157 | position = position || 0; 158 | return this.lastIndexOf(searchString, position) === position; 159 | } 160 | }); 161 | } 162 | 163 | if (!String.prototype.endsWith) { 164 | Object.defineProperty(String.prototype, 'endsWith', { 165 | value: function (searchString, position) { 166 | var subjectString = this.toString(); 167 | if (position === undefined || position > subjectString.length) { 168 | position = subjectString.length; 169 | } 170 | position -= searchString.length; 171 | var lastIndex = subjectString.indexOf(searchString, position); 172 | return lastIndex !== -1 && lastIndex === position; 173 | } 174 | }); 175 | } 176 | 177 | if (!String.prototype.contains) { 178 | String.prototype.contains = function() {'use strict'; 179 | return String.prototype.indexOf.apply(this, arguments) !== -1; 180 | }; 181 | } 182 | 183 | function not(f) { 184 | return function (x) { return !f(x); } 185 | } 186 | 187 | function isAttr(s) { 188 | return s.indexOf('=') > 0; 189 | } 190 | 191 | function isArray(obj) { 192 | return obj === [] || typeof(obj) == 'object' && obj.length; 193 | } 194 | 195 | -------------------------------------------------------------------------------- /src/JsonGen.ts: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const bluebird = require('bluebird') 4 | const exec = bluebird.promisify(require('child_process').exec, { multiArgs: true }) 5 | const fs = bluebird.promisifyAll(require('fs')) 6 | const mkdirp = bluebird.promisify(require('mkdirp')) 7 | const tmp = bluebird.promisify(require('tmp').dir) 8 | const path = require('path') 9 | 10 | require('./Extensions') 11 | var ast = require('./SwiftAst') 12 | var printer = require('./SwiftPrinter') 13 | 14 | var headerLength = 9 15 | 16 | interface FileDesc { 17 | filename: string; 18 | fullname: string; 19 | outfile: string; 20 | outbase: string; 21 | } 22 | 23 | var swiftc = 'swiftc' 24 | var sdk = '$(xcrun --show-sdk-path)' 25 | // var swiftc = '/Applications/Xcode-9.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swiftc' 26 | // var sdk = '/Applications/Xcode-9.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk' 27 | 28 | async function generate() { 29 | 30 | var usage = 'USAGE: $0 [--accessLevel level] [-o output_directory] source_files...\n\n' 31 | + ' Generates +JsonGen.swift files for all swift files supplied,\n' 32 | + ' filenames ending with +Extensions.swift are excluded.' 33 | 34 | var yargs = require('yargs') 35 | .usage(usage) 36 | .help() 37 | .alias('h', 'help') 38 | .alias('o', 'output') 39 | .alias('v', 'version') 40 | .describe('accessLevel', '"public" or "internal"') 41 | .describe('statham', 'Statham library directory') 42 | .describe('xcode', 'Path to Xcode.app') 43 | .describe('o', 'Output directory') 44 | .describe('v', 'Print version') 45 | 46 | var argv = yargs.argv 47 | 48 | if (argv.version) { 49 | var pjson = require('../package.json'); 50 | console.log(pjson.version); 51 | return 52 | } 53 | 54 | const inputs = argv._ 55 | const outputDirectory = typeof(argv.output) == 'string' ? argv.output : null 56 | const stathamDirectory = typeof(argv.statham) == 'string' ? argv.statham : null 57 | const accessLevel = typeof(argv.accessLevel) == 'string' ? argv.accessLevel : null 58 | const xcode = typeof(argv.xcode) == 'string' ? argv.xcode : null 59 | 60 | // override swiftc and sdk paths 61 | if (xcode != null) { 62 | swiftc = xcode + '/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swiftc' 63 | sdk = xcode + '/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk' 64 | } 65 | 66 | if (accessLevel != null && accessLevel != 'public' && accessLevel != 'internal') { 67 | console.error('accessLevel must be "public" or "internal"') 68 | return 69 | } 70 | 71 | if (inputs.length == 0) { 72 | yargs.showHelp() 73 | return 74 | } 75 | 76 | await checkSwiftVersion() 77 | const stathamDir = await compileStatham() 78 | if (outputDirectory) { 79 | await mkdirp(outputDirectory) 80 | } 81 | handleFiles(inputs, accessLevel, stathamDir, outputDirectory) 82 | 83 | async function checkSwiftVersion() { 84 | const supportedVersions = ['Apple Swift version 3.0', 'Apple Swift version 3.1']; 85 | const [stdout] = await exec('"' + swiftc + '" --version') 86 | const versions = supportedVersions.filter(version => stdout.startsWith(version)) 87 | 88 | if (versions.length == 0) { 89 | console.log('WARNING: Using untested swiftc version. swift-json-gen has been tested with:') 90 | supportedVersions.forEach(function (version) { 91 | console.log(' - ' + version); 92 | }); 93 | } 94 | } 95 | 96 | async function compileStatham() { 97 | if (!stathamDirectory) { return null } 98 | 99 | const stathamTempDir = await tmp() 100 | 101 | // From: http://stackoverflow.com/a/27047477/2597 102 | const cmd = 'xcrun "' + swiftc + '" -sdk "' + sdk + '"' 103 | + ' -module-name Statham' 104 | // + ' -emit-library' 105 | + ' -emit-module-path ' + stathamTempDir 106 | + ' -emit-module ' + stathamDirectory + '/Sources/*.swift' 107 | 108 | await exec(cmd) 109 | 110 | return stathamTempDir 111 | } 112 | } 113 | 114 | async function fullFilenames(input: string) : Promise { 115 | 116 | const stat = await fs.statAsync(input) 117 | 118 | if (stat.isDirectory()) { 119 | const inputFiles = await fs.readdirAsync(input) 120 | const filenamePromises = inputFiles.map(fn => fullFilenames(path.join(input, fn))) 121 | const filenamesArray = await bluebird.all(filenamePromises) 122 | 123 | return filenamesArray.flatMap(x => x) 124 | } 125 | else if (stat.isFile()) { 126 | return [input] 127 | } 128 | 129 | throw new Error("input is neither a file nor a directory"); 130 | } 131 | 132 | function fileDescription(filename: string, allFilenames: string[], outputDirectory: string) : FileDesc { 133 | 134 | var dirname = path.dirname(filename) 135 | var basename = path.basename(filename) 136 | var outbase = basename.replace('.swift', '+JsonGen.swift') 137 | var outfile = outputDirectory ? path.join(outputDirectory, outbase) : path.join(dirname, outbase) 138 | 139 | return { 140 | filename: basename, 141 | fullname: path.join(dirname, basename), 142 | outbase: outbase, 143 | outfile: outfile, 144 | } 145 | } 146 | 147 | function containsPodError(s: string): boolean { 148 | return s.contains('error: use of undeclared type \'AnyJson\'') 149 | || s.contains('error: use of undeclared type \'JsonObject\'') 150 | || s.contains('error: use of undeclared type \'JsonArray\'') 151 | || s.contains('error: no such module \'Statham\''); 152 | } 153 | 154 | async function handleFiles(inputs: string[], accessLevel: string, stathamTempDir: string, outputDirectory: string) { 155 | var inputFilenames: string[][] = await bluebird.all(inputs.map(fullFilenames)) 156 | var filenames: string[] = inputFilenames.flatMap(x => x) 157 | 158 | var files = filenames 159 | .map(fn => fileDescription(fn, filenames, outputDirectory)) 160 | .filter(function (f) { 161 | var isExtensions = f.filename.indexOf('+Extensions.swift') > 0; 162 | var isJsonGen = f.filename.indexOf('+JsonGen.swift') > 0; 163 | var isSwift = f.filename.indexOf('.swift') > 0; 164 | 165 | return isSwift && !isJsonGen && !isExtensions; 166 | }); 167 | 168 | var filenamesString = files.map(f => '"' + f.fullname + '"').join(' '); 169 | 170 | var statham = '' 171 | if (stathamTempDir) { 172 | statham = ' -I ' + stathamTempDir + ' -L ' + stathamTempDir + ' -lStatham -module-link-name Statham' 173 | } 174 | 175 | var cmd = 'xcrun "' + swiftc + '"' + statham + ' -sdk "' +sdk + '" -dump-ast ' + filenamesString 176 | 177 | var opts = { 178 | maxBuffer: 200*1024*1024 179 | } 180 | 181 | const [stdout, stderr] = await exec(cmd, opts) 182 | 183 | var parseResult = parseXcOutput(stderr) 184 | var xcoutputs = parseResult.outputs 185 | var errors = parseResult.errors 186 | 187 | // If an actual error (not a `(source_file`), print and stop 188 | if (errors.length) { 189 | errors.forEach(error => { 190 | console.error(error) 191 | }) 192 | 193 | if (errors.any(containsPodError) && !stathamTempDir) { 194 | console.error('') 195 | console.error('When using Statham library include argument: --statham=Pods/Statham') 196 | } 197 | return; 198 | } 199 | 200 | if (xcoutputs.length != files.length) { 201 | console.error('INTERNAL ERROR - swift-json-gen'); 202 | console.error('inconsistency; xcoutputs not equal in length to files'); 203 | console.error('xcoutputs.length: ' + xcoutputs.length + ', files: ' + files.length); 204 | console.error(); 205 | console.error('Please report this at: https://github.com/tomlokhorst/swift-json-gen/issues'); 206 | return 207 | } 208 | 209 | var fileAsts = xcoutputs.map(ast.parse); 210 | var mergedFileAsts = [].concat.apply([], fileAsts); 211 | var globalAttrs = ast.globalAttrs(mergedFileAsts); 212 | 213 | for (var i = 0; i < files.length; i++) { 214 | const file = files[i] 215 | const fileAst = fileAsts[i] 216 | if (file.filename == 'JsonGen.swift') continue; 217 | 218 | var lines = printer.makeFile(fileAst, accessLevel, globalAttrs, file.outbase) 219 | if (lines.length == 0) continue; 220 | 221 | var text = lines.join('\n'); 222 | 223 | await printFile(text, file.outfile); 224 | } 225 | } 226 | 227 | function parseXcOutput(output: String) : { errors: String[], outputs: String[] } { 228 | // Separate outputs 229 | // Each non-error output starts with `(`, subsequent lines start with ` ` or `)` 230 | var lines = output.split(/\n/g); 231 | 232 | var xcoutputs = []; 233 | var errors = []; 234 | var current = []; 235 | for (var i = 0; i < lines.length; i++) { 236 | var line = lines[i]; 237 | if (line.length == 0 || line[0] == ' ' || line[0] == ')') { 238 | current.push(line); 239 | } 240 | else { 241 | var merged = current.join('\n'); 242 | if (current.length && merged.indexOf('(source_file') == 0) 243 | xcoutputs.push(merged); 244 | else if (current.length) 245 | errors.push(merged); 246 | 247 | current = [line]; 248 | } 249 | } 250 | 251 | var merged = current.join('\n'); 252 | if (current.length && merged.indexOf('(source_file') == 0) 253 | xcoutputs.push(merged); 254 | else if (current.length) 255 | errors.push(merged); 256 | 257 | return { errors: errors, outputs: xcoutputs } 258 | } 259 | 260 | async function printFile(text, outfile) { 261 | 262 | // Ignore first 4? lines (containing only generated date) 263 | var outputBody = text.split('\n').slice(headerLength).join('\n'); 264 | 265 | try { 266 | const existing = await fs.readFileAsync(outfile, 'utf8') 267 | 268 | if (existing) { 269 | var existingBody = existing.split('\n').slice(headerLength).join('\n') 270 | 271 | // No changes since existing 272 | if (outputBody == existingBody) return; 273 | } 274 | } 275 | catch(_) { 276 | // If no exising file and no output body 277 | if (outputBody == '') return; 278 | } 279 | 280 | await fs.writeFileAsync(outfile, text, 'utf8') 281 | } 282 | 283 | exports.generate = generate; 284 | 285 | -------------------------------------------------------------------------------- /src/SwiftAst.ts: -------------------------------------------------------------------------------- 1 | // 2 | // A parse function for parsing the AST dump from the swift compiler. 3 | // 4 | 5 | interface GlobalAttrs { 6 | typeAliases: { [ix: string]: string }; 7 | constructors: { [typeName: string]: string[] }; 8 | decoders: string[]; 9 | encoders: string[]; 10 | } 11 | 12 | interface TypeFuncNames { 13 | typeName: string; 14 | constructorParams: string[]; 15 | funcNames: string[]; 16 | } 17 | 18 | interface TypeAliases { 19 | [ix: string]: string; 20 | } 21 | 22 | interface Struct { 23 | baseName: string; 24 | typeArguments: string[]; 25 | varDecls: VarDecl[]; 26 | constructorParams: string[]; 27 | funcNames: string[]; 28 | } 29 | 30 | interface Enum { 31 | baseName: string; 32 | rawTypeName: string; 33 | constructorParams: string[]; 34 | funcNames: string[]; 35 | } 36 | 37 | interface Extension { 38 | typeBaseName: string; 39 | } 40 | 41 | interface VarDecl { 42 | name: string; 43 | type: Type; 44 | } 45 | 46 | interface Type { 47 | alias?: string; 48 | baseName: string; 49 | genericArguments: Type[]; 50 | } 51 | 52 | function globalAttrs(ast: any[]) : GlobalAttrs { 53 | var tfns = typeFuncNames(ast); 54 | var decoders = tfns 55 | .filter(d => d.funcNames.contains('decodeJson')) 56 | .map(d => d.typeName); 57 | var encoders = tfns 58 | .filter(d => d.funcNames.contains('encodeJson')) 59 | .map(d => d.typeName); 60 | 61 | var constructors: { [typeName: string]: string[] } = {} 62 | tfns.forEach(tfn => { 63 | var xs = constructors[tfn.typeName] || [] 64 | if (tfn.constructorParams.length) { 65 | constructors[tfn.typeName] = xs.concat(tfn.constructorParams) 66 | } 67 | }) 68 | 69 | return { 70 | typeAliases: typeAliases(ast), 71 | constructors: constructors, 72 | decoders: decoders, 73 | encoders: encoders, 74 | } 75 | } 76 | 77 | exports.globalAttrs = globalAttrs; 78 | 79 | function typeFuncNames(ast: any[]) : TypeFuncNames[] { 80 | var emptyAliases: TypeAliases = {}; 81 | var ds1 = structs(ast, emptyAliases) 82 | .map(s => { 83 | return { 84 | typeName: s.baseName, 85 | constructorParams: s.constructorParams, 86 | funcNames: s.funcNames 87 | } 88 | }); 89 | var ds2 = enums(ast, emptyAliases) 90 | .map(e => { 91 | return { 92 | typeName: e.baseName, 93 | constructorParams: e.constructorParams, 94 | funcNames: e.funcNames 95 | } 96 | }); 97 | var ds3 = ast 98 | .children('extension_decl') 99 | .map(s => { 100 | return { 101 | typeName: extension(s).typeBaseName, 102 | constructorParams: constructorParams(s), 103 | funcNames: funcNames(s) 104 | } 105 | }); 106 | 107 | return ds1.concat(ds2).concat(ds3); 108 | } 109 | 110 | function funcNames(ast: any[]) : string[] { 111 | return ast.children('func_decl').map(f => f.key(0) == 'implicit' ? f.key(1) : f.key(0)) 112 | } 113 | 114 | function constructorParams(ast: any[]) : string[] { 115 | return ast.children('constructor_decl') 116 | .filter(a => a.attr('access') != 'private' && a.attr('access') != 'fileprivate') 117 | .flatMap(constructorDeclParams) 118 | } 119 | 120 | function constructorDeclParams(constructorDecl: any[]) : string[] { 121 | const parts = constructorDecl 122 | .filter(obj => (typeof(obj) == 'object' && obj.length == 0) || (typeof(obj) == 'object' && obj.length == 1 && typeof(obj[0]) == 'string')) 123 | .map(a => a.length ? a[0] : '') 124 | 125 | if (parts.length < 3) { return [] } 126 | 127 | const names = parts[0] 128 | const types = parts[2] 129 | 130 | return [names + '||' + types] 131 | } 132 | 133 | function extension(ast: any[]) : Extension { 134 | var fullName = ast.key(0); 135 | var keys = ast.keys().slice(1); 136 | 137 | while (fullName.contains('<') && !fullName.contains('>') && keys.length > 0) { 138 | fullName += keys.splice(0, 1)[0] 139 | } 140 | 141 | var baseName = fullName.replace(/<([^>]*)>/g, ''); 142 | 143 | return { typeBaseName: baseName }; 144 | } 145 | 146 | function typeAliases(ast: any[]) : TypeAliases { 147 | var aliases: TypeAliases = {}; 148 | 149 | ast.children('typealias') 150 | .forEach(function (t) { 151 | var name = t.fields().name().unquote() 152 | var type = t.attrs().filter(attr => attr[0] == 'type' )[1][1] 153 | 154 | if (!type.startsWith("'") && type.endsWith("'")) { 155 | type = type.substring(0, type.length - 1) 156 | } 157 | 158 | aliases[name] = type; 159 | }); 160 | 161 | return aliases; 162 | } 163 | 164 | function getBaseName(ast: any[], prefix?: string) : string { 165 | prefix = prefix ? prefix + '.' : ''; 166 | 167 | var fullName = ast.key(0); 168 | return prefix + fullName.replace(/<([^>]*)>/g, ''); 169 | } 170 | 171 | function structs(ast: any[], aliases: TypeAliases, prefix?: string) : Struct[] { 172 | var structs1 = ast.children('struct_decl') 173 | .map(a => struct(a, aliases, prefix)); 174 | 175 | var structs2 = ast.children(['struct_decl', 'enum_decl']) 176 | .flatMap(a => structs(a, aliases, getBaseName(a, prefix))); 177 | 178 | return structs1.concat(structs2) 179 | } 180 | 181 | exports.structs = structs; 182 | 183 | function struct(ast: any[], aliases: TypeAliases, prefix?: string) : Struct { 184 | 185 | var baseName = getBaseName(ast, prefix) 186 | var fullName = ast.key(0) 187 | var typeArgs = genericArguments(ast) 188 | var varDecls = ast.children('var_decl') 189 | .filter(a => a.attr('storage_kind') == 'stored_with_trivial_accessors') 190 | .map(a => varDecl(a, aliases)) 191 | 192 | var r = { 193 | baseName: baseName, 194 | typeArguments: typeArgs, 195 | varDecls: varDecls, 196 | constructorParams: constructorParams(ast), 197 | funcNames: funcNames(ast) 198 | }; 199 | 200 | return r; 201 | } 202 | 203 | function enums(ast: any[], aliases: TypeAliases, prefix?: string) : Enum[] { 204 | var enums1 = ast 205 | .children('enum_decl') 206 | .filter(a => { 207 | var keys = a.keys() 208 | var ix = keys.indexOf('inherits:') 209 | return ix > 0 && keys.length > ix + 1 210 | }) 211 | .map(a => enum_(a, aliases, prefix)); 212 | 213 | var enums2 = ast.children(['struct_decl', 'enum_decl']) 214 | .flatMap(a => enums(a, aliases, getBaseName(a, prefix))); 215 | 216 | return enums1.concat(enums2); 217 | } 218 | 219 | exports.enums = enums; 220 | 221 | function enum_(ast: any[], aliases: TypeAliases, prefix?: string) : Enum { 222 | 223 | var baseName = getBaseName(ast, prefix); 224 | var fullName = ast.key(0); 225 | 226 | var keys = ast.keys() 227 | var ix = keys.indexOf('inherits:') 228 | var rawTypeName = keys[ix + 1] 229 | 230 | var r = { 231 | baseName: baseName, 232 | rawTypeName: rawTypeName, 233 | constructorParams: constructorParams(ast), 234 | funcNames: funcNames(ast) 235 | }; 236 | 237 | return r; 238 | } 239 | 240 | function genericArguments(ast: any[]) : string[] { 241 | 242 | // Swift 3.0 has generic arguments as part of fullName 243 | // Swift 3.1 has generic arguments as separate parts, after fullName 244 | var generics = ast.key(0) 245 | const keys = ast.keys() 246 | for (var ix = 1; ix < keys.length; ix++) { 247 | const key = keys[ix] 248 | if (key == 'interface') { break } 249 | if (key == '@_fixed_layout') { break } 250 | generics += key 251 | } 252 | 253 | var matches = generics.match(/<([^>]*)>/); 254 | if (matches && matches.length == 2) 255 | return matches[1].split(',').map(s => s.trim()); 256 | 257 | return [] 258 | } 259 | 260 | function varDecl(ast: any, aliases: TypeAliases) : VarDecl { 261 | return { name: ast.key(0), type: type(ast.attr('type'), aliases) }; 262 | } 263 | 264 | function type(typeString: string, aliases: TypeAliases) : Type { 265 | 266 | if (aliases[typeString]) { 267 | var resolved = type(aliases[typeString], aliases); 268 | resolved.alias = typeString 269 | return resolved; 270 | } 271 | 272 | var isBracketed = typeString.startsWith('[') && typeString.endsWith(']'); 273 | 274 | var isGeneric = typeString.match(/\<(.*)>/); 275 | var isDictionary = isBracketed && typeString.contains(':'); 276 | var isArray = isBracketed && !typeString.contains(':'); 277 | var isOptional = typeString.endsWith('?'); 278 | 279 | if (isOptional) { 280 | var inner = typeString.substring(0, typeString.length - 1).trim(); 281 | return { baseName: 'Optional', genericArguments: [ type(inner, aliases) ] }; 282 | } 283 | 284 | if (isArray) { 285 | var inner = typeString.substring(1, typeString.length - 1).trim(); 286 | return { baseName: 'Array', genericArguments: [ type(inner, aliases) ] }; 287 | } 288 | 289 | if (isDictionary) { 290 | var matches = typeString.match(/\[(.*):(.*)\]/); 291 | 292 | if (matches.length != 3) 293 | throw new Error('"' + typeString + '" appears to be a Dictionary, but isn\'t'); 294 | 295 | var keyType = type(matches[1].trim(), aliases); 296 | var valueType = type(matches[2].trim(), aliases); 297 | return { baseName: 'Dictionary', genericArguments: [ keyType, valueType ] }; 298 | } 299 | 300 | if (isDictionary) { 301 | var matches = typeString.match(/\[(.*):(.*)\]/); 302 | 303 | if (matches.length != 3) 304 | throw new Error('"' + typeString + '" appears to be a Dictionary, but isn\'t'); 305 | 306 | var keyType = type(matches[1].trim(), aliases); 307 | var valueType = type(matches[2].trim(), aliases); 308 | return { baseName: 'Dictionary', genericArguments: [ keyType, valueType ] }; 309 | } 310 | 311 | if (isGeneric) { 312 | var baseName = typeString.replace(/<([^>]*)>/g, ''); 313 | var matches = typeString.match(/\<(.*)>/); 314 | 315 | if (matches.length != 2) 316 | throw new Error('"' + typeString + '" appears to be a generic type, but isn\'t'); 317 | 318 | var types = matches[1] 319 | .split(',') 320 | .map(t => t.trim()) 321 | .map(mkType); 322 | 323 | return { baseName: baseName, genericArguments: types }; 324 | } 325 | 326 | return { baseName: typeString, genericArguments: [] }; 327 | } 328 | 329 | function mkType(name: string) : Type { 330 | return { baseName: name, genericArguments: [] }; 331 | } 332 | 333 | // Based on: https://github.com/arian/LISP.js 334 | function parse(text) { 335 | 336 | var results = [] 337 | 338 | text = text.trim(); 339 | // text = text.replace(/=\[([^\]]*)\]'/g, function (n) { return n.replace(/ /g, 'JSON_GEN_SPACE') } ) // Workaround for swiftc 2.0 340 | text = text.replace(/='([^']*)'/g, function (n) { return n.replace(/ /g, 'JSON_GEN_SPACE') } ) 341 | text = text.replace(/"<([^>]*)>/g, function (n) { return n.replace(/ /g, 'JSON_GEN_SPACE') } ) 342 | 343 | if (text.charAt(0) != '(') return text; 344 | 345 | var stack = []; 346 | var token; 347 | var tokens = ''; 348 | var inString = false; 349 | var i = 0; 350 | var current; 351 | 352 | while (i < text.length) { 353 | token = text.charAt(i++); 354 | 355 | var isOpen = token == '('; 356 | var isClose = token == ')'; 357 | var isSpace = token == ' ' && !inString; 358 | 359 | if (isOpen || isClose || isSpace) { 360 | if (current && tokens.length) { 361 | var n = +tokens; 362 | var tokens_ = tokens.replace(/JSON_GEN_SPACE/g, ' ') 363 | current.push(isNaN(n) ? tokens_ : n); 364 | } 365 | tokens = ''; 366 | } else { 367 | if (token == '"') inString = !inString; 368 | if (!/\s/.test(token) || inString) tokens += token; 369 | } 370 | 371 | if (isOpen) { 372 | 373 | var previous = current; 374 | current = []; 375 | 376 | if (previous){ 377 | stack.push(previous); 378 | previous.push(current); 379 | } 380 | 381 | } else if (isClose) { 382 | 383 | var pop = stack.pop(); 384 | if (!pop) { 385 | return current; 386 | } 387 | 388 | current = pop; 389 | } 390 | } 391 | 392 | var msg = 'INTERNAL ERROR:\n' 393 | + 'Likely due to errornous output from Swift compiler on some language construct (like a switch or array ializer).\n' 394 | + 'Workaround: Change all methods from SomeFile.swift into extensions methods in SomeFile+Extensions.swift, which is ignored by JsonGen.\n\n' 395 | + 'For details, please create an issue (including the failing Swift sources):\nhttps://github.com/tomlokhorst/swift-json-gen/issues'; 396 | console.error(msg) 397 | 398 | throw 'unbalanced parentheses' 399 | }; 400 | 401 | exports.parse = parse; 402 | -------------------------------------------------------------------------------- /src/SwiftPrinter.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Several functions for generating Swift code based on the parsed AST. 3 | // 4 | 5 | var ast = require('./SwiftAst') 6 | 7 | function makeFile(file: any[], accessLevel: string, globalAttrs: GlobalAttrs, filename: string): string[] { 8 | 9 | const accessLevelPrefix = accessLevel == null ? '' : accessLevel + ' ' 10 | 11 | function constructorExists(struct: Struct) : boolean { 12 | const paramNames = struct.varDecls.map(vd => vd.name + ':') 13 | const paramTypes = struct.varDecls.map(vd => typeString(vd.type)) 14 | const paramsString = paramNames.join('') + '||' + paramTypes.join(', ') 15 | const constructors = globalAttrs.constructors[struct.baseName] || [] 16 | 17 | return constructors.contains(paramsString); 18 | } 19 | 20 | function decoderExists(typeName: string) : boolean { 21 | return globalAttrs.decoders.contains(typeName); 22 | } 23 | 24 | function encoderExists(typeName: string) : boolean { 25 | return globalAttrs.encoders.contains(typeName); 26 | } 27 | 28 | var structs = ast.structs(file, globalAttrs.typeAliases) 29 | .filter(s => !constructorExists(s) || !decoderExists(s.baseName) || !encoderExists(s.baseName)); 30 | 31 | var enums = ast.enums(file, globalAttrs.typeAliases) 32 | .filter(e => !decoderExists(e.baseName) || !encoderExists(e.baseName)); 33 | 34 | var lines = []; 35 | 36 | lines.push('//'); 37 | lines.push('// ' + filename); 38 | lines.push('//'); 39 | lines.push('// Auto generated by swift-json-gen on ' + new Date().toUTCString()); 40 | lines.push('// See for details: https://github.com/tomlokhorst/swift-json-gen') 41 | lines.push('//'); 42 | lines.push(''); 43 | lines.push('import Foundation'); 44 | lines.push('import Statham'); 45 | lines.push(''); 46 | 47 | enums.forEach(function (s) { 48 | 49 | var createDecoder = !decoderExists(s.baseName); 50 | var createEncoder = !encoderExists(s.baseName); 51 | 52 | lines.push('extension ' + escaped(s.baseName) + ' {') 53 | 54 | if (createDecoder) { 55 | lines = lines.concat(makeEnumDecoder(s, accessLevelPrefix)); 56 | } 57 | 58 | if (createDecoder && createEncoder) { 59 | lines.push(''); 60 | } 61 | 62 | if (createEncoder) { 63 | lines = lines.concat(makeEnumEncoder(s, accessLevelPrefix)); 64 | } 65 | 66 | lines.push('}'); 67 | lines.push(''); 68 | }); 69 | 70 | structs.forEach(function (s) { 71 | 72 | var createConstructor = !constructorExists(s); 73 | var createDecoder = !decoderExists(s.baseName); 74 | var createEncoder = !encoderExists(s.baseName); 75 | 76 | lines.push('extension ' + escaped(s.baseName) + ' {') 77 | 78 | if (createDecoder) { 79 | lines = lines.concat(makeStructDecoder(s, accessLevelPrefix)); 80 | } 81 | 82 | if (createDecoder && (createConstructor || createEncoder)) { 83 | lines.push(''); 84 | } 85 | 86 | if (createConstructor) { 87 | lines = lines.concat(makeStructConstructor(s, accessLevelPrefix)); 88 | } 89 | 90 | if (createConstructor && createEncoder) { 91 | lines.push(''); 92 | } 93 | 94 | if (createEncoder) { 95 | lines = lines.concat(makeStructEncoder(s, enums, accessLevelPrefix)); 96 | } 97 | 98 | lines.push('}'); 99 | lines.push(''); 100 | }); 101 | 102 | return lines; 103 | } 104 | 105 | exports.makeFile = makeFile; 106 | 107 | function makeEnumDecoder(en: Enum, accessLevelPrefix: string) : string { 108 | var lines = []; 109 | 110 | lines.push(' ' + accessLevelPrefix + 'static func decodeJson(_ json: Any) throws -> ' + escaped(en.baseName) + ' {'); 111 | lines.push(' guard let rawValue = json as? ' + escaped(en.rawTypeName) + ' else {'); 112 | lines.push(' throw JsonDecodeError.wrongType(rawValue: json, expectedType: "' + en.rawTypeName + '")'); 113 | lines.push(' }'); 114 | lines.push(' guard let value = ' + escaped(en.baseName) + '(rawValue: rawValue) else {'); 115 | lines.push(' throw JsonDecodeError.wrongEnumRawValue(rawValue: rawValue, enumType: "' + en.baseName + '")'); 116 | lines.push(' }'); 117 | lines.push(''); 118 | lines.push(' return value'); 119 | lines.push(' }'); 120 | 121 | return lines.join('\n'); 122 | } 123 | 124 | function makeEnumEncoder(en: Enum, accessLevelPrefix: string) : string { 125 | var lines = []; 126 | 127 | lines.push(' ' + accessLevelPrefix + 'func encodeJson() -> ' + escaped(en.rawTypeName) + ' {'); 128 | lines.push(' return rawValue'); 129 | lines.push(' }'); 130 | 131 | return lines.join('\n'); 132 | } 133 | 134 | function makeStructConstructor(struct: Struct, accessLevelPrefix: string) : string { 135 | var lines = []; 136 | const paramsStrings = struct.varDecls.map(vd => vd.name + ': ' + typeString(vd.type)) 137 | 138 | lines.push('fileprivate init(' + paramsStrings.join(', ') + ') {'); 139 | 140 | struct.varDecls.forEach(varDecl => { 141 | lines.push(' self.' + varDecl.name + ' = ' + escaped(varDecl.name)) 142 | }) 143 | 144 | lines.push('}'); 145 | 146 | return lines.map(indent(2)).join('\n'); 147 | } 148 | 149 | function makeStructDecoder(struct: Struct, accessLevelPrefix: string) : string { 150 | var lines = []; 151 | 152 | var curried = struct.typeArguments.length > 0; 153 | 154 | if (curried) { 155 | lines.push(' ' + accessLevelPrefix + 'static func decodeJson' + decodeArguments(struct) + ' -> (Any) throws -> ' + escaped(struct.baseName) + ' {'); 156 | lines.push(' return { json in'); 157 | } 158 | else { 159 | lines.push(' ' + accessLevelPrefix + 'static func decodeJson(_ json: Any) throws -> ' + escaped(struct.baseName) + ' {'); 160 | } 161 | 162 | var body = makeStructDecoderBody(struct).map(indent(curried ? 6 : 4)); 163 | lines = lines.concat(body); 164 | 165 | if (curried) { 166 | lines.push(' }'); 167 | } 168 | 169 | lines.push(' }'); 170 | 171 | return lines.join('\n'); 172 | } 173 | 174 | function decodeArguments(struct: Struct) : string { 175 | var parts = struct.typeArguments 176 | .map(typeVar => '_ decode' + typeVar + ': @escaping (Any) throws -> ' + escaped(typeVar)) 177 | 178 | return '(' + parts.join(', ') + ')'; 179 | } 180 | 181 | function makeStructDecoderBody(struct: Struct) : string[] { 182 | if (struct.varDecls.length == 0) { 183 | return ['return ' + struct.baseName + '()']; 184 | } 185 | 186 | var lines = []; 187 | 188 | lines.push('let decoder = try JsonDecoder(json: json)'); 189 | lines.push(''); 190 | 191 | struct.varDecls.forEach(function (field, ix) { 192 | var decoder = decodeFunction(field.type, struct.typeArguments) 193 | var line = 'let _' + field.name + ' = ' 194 | + 'try decoder.decode("' + field.name + '", decoder: ' + decoder + ')'; 195 | 196 | lines.push(line) 197 | }); 198 | 199 | lines.push(''); 200 | 201 | var fieldDecodes = struct.varDecls.map(function (field, ix) { 202 | var isLast = struct.varDecls.length == ix + 1 203 | var commaOrBrace = isLast ? '' : ',' 204 | 205 | var line = 'let ' + escaped(field.name) + ' = _' + field.name + commaOrBrace; 206 | 207 | return line 208 | }); 209 | 210 | if (fieldDecodes.length == 1) { 211 | lines.push('guard ' + fieldDecodes[0] + ' else {'); 212 | } 213 | else { 214 | lines.push('guard'); 215 | lines = lines.concat(fieldDecodes.map(indent(2))); 216 | lines.push('else {'); 217 | } 218 | 219 | var params = struct.varDecls.map(decl => decl.name + ': ' + escaped(decl.name)) 220 | lines.push(' throw JsonDecodeError.structErrors(type: "' + struct.baseName + '", errors: decoder.errors)') 221 | lines.push('}'); 222 | 223 | lines.push('') 224 | lines.push('return ' + escaped(struct.baseName) + '(' + params.join(', ') + ')') 225 | 226 | return lines 227 | } 228 | 229 | function typeString(type: Type) : string { 230 | 231 | var args = type.genericArguments 232 | .map(typeString) 233 | 234 | var argList = args.length ? '<' + args.join(', ') + '>' : ''; 235 | var typeName = type.alias || type.baseName; 236 | 237 | if (typeName == 'Optional' && args.length == 1) { 238 | return args[0] + '?' 239 | } 240 | 241 | if (typeName == 'Array' && args.length == 1) { 242 | return '[' + args[0] + ']' 243 | } 244 | 245 | if (typeName == 'Dictionary' && args.length == 2) { 246 | return '[' + args[0] + ' : ' + args[1] + ']' 247 | } 248 | 249 | if (type.alias) { 250 | return type.alias; 251 | } 252 | 253 | return typeName + argList; 254 | } 255 | 256 | function decodeFunction(type: Type, genericDecoders: string[]) : string { 257 | 258 | if (isKnownType(type)) 259 | return '{ $0 }'; 260 | 261 | var args = type.genericArguments 262 | .map(a => decodeFunction(a, genericDecoders)) 263 | .join(', '); 264 | 265 | var argList = args.length ? '(' + args + ')' : ''; 266 | var typeName = type.alias || type.baseName; 267 | 268 | if (genericDecoders.contains(typeName)) 269 | return 'decode' + typeName + argList; 270 | 271 | return typeName + '.decodeJson' + argList; 272 | } 273 | 274 | function makeStructEncoder(struct: Struct, enums: Enum[], accessLevelPrefix: string) : string { 275 | var lines = []; 276 | 277 | lines.push(' ' + accessLevelPrefix + 'func encodeJson' + encodeArguments(struct) + ' -> [String: Any] {'); 278 | 279 | var body = makeStructEncoderBody(struct, enums).map(indent(4)); 280 | lines = lines.concat(body); 281 | lines.push(' }'); 282 | 283 | return lines.join('\n'); 284 | } 285 | 286 | function encodeArguments(struct: Struct) : string { 287 | var parts = struct.typeArguments 288 | .map(typeVar => '_ encode' + typeVar + ': (' + escaped(typeVar) + ') -> Any') 289 | 290 | return '(' + parts.join(', ') + ')'; 291 | } 292 | 293 | function makeStructEncoderBody(struct: Struct, enums: Enum[]) : string[] { 294 | if (struct.varDecls.length == 0) { 295 | return ['return [:]']; 296 | } 297 | 298 | var lines = []; 299 | lines.push('var dict: [String: Any] = [:]'); 300 | lines.push(''); 301 | 302 | struct.varDecls.forEach(function (d) { 303 | var subs = makeFieldEncode(d, struct.typeArguments, enums); 304 | lines = lines.concat(subs); 305 | }); 306 | 307 | lines.push(''); 308 | lines.push('return dict'); 309 | 310 | return lines; 311 | } 312 | 313 | function encodeFunction(name: string, type: Type, genericEncoders: string[]) : string { 314 | 315 | if (isKnownType(type)) 316 | return name; 317 | 318 | if (genericEncoders.contains(type.baseName)) 319 | return 'encode' + type.baseName + '(' + name + ')'; 320 | 321 | var args = type.genericArguments 322 | .map(t => '{ ' + encodeFunction('$0', t, genericEncoders) + ' }') 323 | .join(', '); 324 | 325 | return escaped(name) + '.encodeJson(' + args + ')'; 326 | } 327 | 328 | function makeFieldEncode(field: VarDecl, structTypeArguments: string[], enums: Enum[]) { 329 | var lines = []; 330 | 331 | var name = field.name; 332 | var type = field.type; 333 | 334 | var prefix = '' 335 | 336 | if (type.baseName == 'Dictionary' && type.genericArguments.length == 2) { 337 | var keyType = type.genericArguments[0].baseName; 338 | var enum_ = enums.filter(e => e.baseName == keyType)[0]; 339 | if (keyType != 'String' && enum_.rawTypeName != 'String') { 340 | lines.push('/* WARNING: Json only supports Strings as keys in dictionaries */'); 341 | } 342 | } 343 | lines.push('dict["' + name + '"] = ' + encodeFunction(name, type, structTypeArguments)); 344 | 345 | return lines; 346 | } 347 | 348 | function indent(nr) { 349 | return function (s) { 350 | return s == '' ? s : Array(nr + 1).join(' ') + s; 351 | }; 352 | } 353 | 354 | function isKnownType(type: Type) : boolean { 355 | var types = [ 'Any', 'AnyObject', 'AnyJson' ]; 356 | return types.contains(type.alias) || types.contains(type.baseName); 357 | } 358 | 359 | // Copied from R.swift: 360 | // Based on https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/doc/uid/TP40014097-CH30-ID413 361 | let swiftKeywords = [ 362 | // Keywords used in declarations 363 | "associatedtype", "class", "deinit", "enum", "extension", "func", "import", "init", "inout", "internal", "let", "operator", "private", "protocol", "public", "static", "struct", "subscript", "typealias", "var", 364 | 365 | // Keywords used in statements 366 | "break", "case", "continue", "default", "defer", "do", "else", "fallthrough", "for", "guard", "if", "in", "repeat", "return", "switch", "where", "while", 367 | 368 | // Keywords used in expressions and types 369 | "as", "catch", "dynamicType", "false", "is", "nil", "rethrows", "super", "self", "Self", "throw", "throws", "true", "try", "__COLUMN__", "__FILE__", "__FUNCTION__", "__LINE__", 370 | ] 371 | 372 | function escaped(name: string) : string { 373 | if (swiftKeywords.contains(name)) { 374 | return '`' + name + '`' 375 | } 376 | else { 377 | return name 378 | } 379 | } 380 | -------------------------------------------------------------------------------- /src/node.d.ts: -------------------------------------------------------------------------------- 1 | /************************************************ 2 | * * 3 | * Node.js v0.8.8 API * 4 | * * 5 | ************************************************/ 6 | 7 | /************************************************ 8 | * * 9 | * GLOBAL * 10 | * * 11 | ************************************************/ 12 | declare var process: NodeProcess; 13 | declare var global: any; 14 | 15 | declare var __filename: string; 16 | declare var __dirname: string; 17 | 18 | declare function setTimeout(callback: (...args: any[]) => void, ms: number, ...args: any[]): Timer; 19 | declare function clearTimeout(timeoutId: Timer); 20 | declare function setInterval(callback: (...args: any[]) => void, ms: number, ...args: any[]): Timer; 21 | declare function clearInterval(intervalId: Timer); 22 | declare function setImmediate(callback: (...args: any[]) => void, ...args: any[]): any; 23 | declare function clearImmediate(immediateId: any); 24 | 25 | declare var require: { 26 | (id: string): any; 27 | resolve(): string; 28 | cache: any; 29 | extensions: any; 30 | } 31 | 32 | declare var module: { 33 | exports: any; 34 | require(id: string): any; 35 | id: string; 36 | filename: string; 37 | loaded: boolean; 38 | parent: any; 39 | children: any[]; 40 | } 41 | 42 | // Same as module.exports 43 | declare var exports: any; 44 | declare var SlowBuffer: { 45 | new (str: string, encoding?: string): NodeBuffer; 46 | new (size: number): NodeBuffer; 47 | new (array: any[]): NodeBuffer; 48 | prototype: NodeBuffer; 49 | isBuffer(obj: any): boolean; 50 | byteLength(string: string, encoding?: string): number; 51 | concat(list: NodeBuffer[], totalLength?: number): NodeBuffer; 52 | }; 53 | declare var Buffer: { 54 | new (str: string, encoding?: string): NodeBuffer; 55 | new (size: number): NodeBuffer; 56 | new (array: any[]): NodeBuffer; 57 | prototype: NodeBuffer; 58 | isBuffer(obj: any): boolean; 59 | byteLength(string: string, encoding?: string): number; 60 | concat(list: NodeBuffer[], totalLength?: number): NodeBuffer; 61 | } 62 | 63 | /************************************************ 64 | * * 65 | * INTERFACES * 66 | * * 67 | ************************************************/ 68 | 69 | declare class EventEmitter { 70 | addListener(event: string, listener: Function); 71 | on(event: string, listener: Function); 72 | once(event: string, listener: Function): void; 73 | removeListener(event: string, listener: Function): void; 74 | removeAllListeners(event: string): void; 75 | setMaxListeners(n: number): void; 76 | listeners(event: string): { Function; }[]; 77 | emit(event: string, ...args: any[]): void; 78 | } 79 | 80 | declare class WritableStream extends EventEmitter { 81 | writable: boolean; 82 | write(str: string, encoding?: string, fd?: string): boolean; 83 | write(buffer: NodeBuffer): boolean; 84 | end(): void; 85 | end(str: string, enconding: string): void; 86 | end(buffer: NodeBuffer): void; 87 | destroy(): void; 88 | destroySoon(): void; 89 | } 90 | 91 | declare class RENAME_TO_AVOID_TYPESCRIPT_CONFLICT_ReadableStream extends EventEmitter { 92 | readable: boolean; 93 | setEncoding(encoding: string): void; 94 | pause(): void; 95 | resume(): void; 96 | destroy(): void; 97 | pipe(destination: WritableStream, options?: { end?: boolean; }): void; 98 | } 99 | 100 | declare class NodeProcess extends EventEmitter { 101 | stdout: WritableStream; 102 | stderr: WritableStream; 103 | stdin: ReadableStream; 104 | argv: string[]; 105 | execPath: string; 106 | abort(): void; 107 | chdir(directory: string): void; 108 | cwd(): string; 109 | env: any; 110 | exit(code?: number): void; 111 | getgid(): number; 112 | setgid(id: number): void; 113 | getuid(): number; 114 | setuid(id: number): void; 115 | version: string; 116 | versions: { http_parser: string; node: string; v8: string; ares: string; uv: string; zlib: string; openssl: string; }; 117 | config: { 118 | target_defaults: { 119 | cflags: any[]; 120 | default_configuration: string; 121 | defines: string[]; 122 | include_dirs: string[]; 123 | libraries: string[]; 124 | }; 125 | variables: { 126 | clang: number; 127 | host_arch: string; 128 | node_install_npm: boolean; 129 | node_install_waf: boolean; 130 | node_prefix: string; 131 | node_shared_openssl: boolean; 132 | node_shared_v8: boolean; 133 | node_shared_zlib: boolean; 134 | node_use_dtrace: boolean; 135 | node_use_etw: boolean; 136 | node_use_openssl: boolean; 137 | target_arch: string; 138 | v8_no_strict_aliasing: number; 139 | v8_use_snapshot: boolean; 140 | visibility: string; 141 | }; 142 | }; 143 | kill(pid: number, signal?: string): void; 144 | pid: number; 145 | title: string; 146 | arch: string; 147 | platform: string; 148 | memoryUsage(): { rss: number; heapTotal; number; heapUsed: number; }; 149 | nextTick(callback: Function): void; 150 | umask(mask?: number): number; 151 | uptime(): number; 152 | hrtime(): number[]; 153 | hrtime(start: number[]): number[]; 154 | } 155 | 156 | interface Timer { 157 | ref(): void; 158 | unref(): void; 159 | } 160 | 161 | // Buffer class 162 | interface NodeBuffer { 163 | [index: number]: number; 164 | write(string: string, offset?: number, length?: number, encoding?: string): number; 165 | toString(encoding?: string, start?: number, end?: number): string; 166 | length: number; 167 | copy(targetBuffer: NodeBuffer, targetStart?: number, sourceStart?: number, sourceEnd?: number): void; 168 | slice(start?: number, end?: number): NodeBuffer; 169 | readUInt8(offset: number, noAsset?: boolean): number; 170 | readUInt16LE(offset: number, noAssert?: boolean): number; 171 | readUInt16BE(offset: number, noAssert?: boolean): number; 172 | readUInt32LE(offset: number, noAssert?: boolean): number; 173 | readUInt32BE(offset: number, noAssert?: boolean): number; 174 | readInt8(offset: number, noAssert?: boolean): number; 175 | readInt16LE(offset: number, noAssert?: boolean): number; 176 | readInt16BE(offset: number, noAssert?: boolean): number; 177 | readInt32LE(offset: number, noAssert?: boolean): number; 178 | readInt32BE(offset: number, noAssert?: boolean): number; 179 | readFloatLE(offset: number, noAssert?: boolean): number; 180 | readFloatBE(offset: number, noAssert?: boolean): number; 181 | readDoubleLE(offset: number, noAssert?: boolean): number; 182 | readDoubleBE(offset: number, noAssert?: boolean): number; 183 | writeUInt8(value: number, offset: number, noAssert?: boolean): void; 184 | writeUInt16LE(value: number, offset: number, noAssert?: boolean): void; 185 | writeUInt16BE(value: number, offset: number, noAssert?: boolean): void; 186 | writeUInt32LE(value: number, offset: number, noAssert?: boolean): void; 187 | writeUInt32BE(value: number, offset: number, noAssert?: boolean): void; 188 | writeInt8(value: number, offset: number, noAssert?: boolean): void; 189 | writeInt16LE(value: number, offset: number, noAssert?: boolean): void; 190 | writeInt16BE(value: number, offset: number, noAssert?: boolean): void; 191 | writeInt32LE(value: number, offset: number, noAssert?: boolean): void; 192 | writeInt32BE(value: number, offset: number, noAssert?: boolean): void; 193 | writeFloatLE(value: number, offset: number, noAssert?: boolean): void; 194 | writeFloatBE(value: number, offset: number, noAssert?: boolean): void; 195 | writeDoubleLE(value: number, offset: number, noAssert?: boolean): void; 196 | writeDoubleBE(value: number, offset: number, noAssert?: boolean): void; 197 | fill(value: any, offset?: number, end?: number): void; 198 | INSPECT_MAX_BYTES: number; 199 | } 200 | 201 | /************************************************ 202 | * * 203 | * MODULES * 204 | * * 205 | ************************************************/ 206 | declare module "querystring" { 207 | export function stringify(obj: any, sep?: string, eq?: string): string; 208 | export function parse(str: string, sep?: string, eq?: string, options?: { maxKeys?: number; }): any; 209 | export function escape(): any; 210 | export function unescape(): any; 211 | } 212 | 213 | declare module "events" { 214 | export class EventEmitter { 215 | addListener(event: string, listener: Function); 216 | on(event: string, listener: Function): any; 217 | once(event: string, listener: Function): void; 218 | removeListener(event: string, listener: Function): void; 219 | removeAllListener(event: string): void; 220 | setMaxListeners(n: number): void; 221 | listeners(event: string): { Function; }[]; 222 | emit(event: string, arg1?: any, arg2?: any): void; 223 | } 224 | } 225 | 226 | declare module "http" { 227 | import events = require("events"); 228 | import net = require("net"); 229 | import stream = require("stream"); 230 | 231 | export class Server extends events.EventEmitter { 232 | listen(port: number, hostname?: string, backlog?: number, callback?: Function): void; 233 | listen(port: number, hostname?: number, callback?: Function): void; 234 | listen(path: string, callback?: Function): void; 235 | listen(handle: any, listeningListener?: Function): void; 236 | close(cb?: any): void; 237 | maxHeadersCount: number; 238 | } 239 | export class ServerRequest extends stream.ReadableStream { 240 | method: string; 241 | url: string; 242 | headers: any; 243 | trailers: string; 244 | httpVersion: string; 245 | setEncoding(encoding?: string): void; 246 | pause(): void; 247 | resume(): void; 248 | connection: net.NodeSocket; 249 | } 250 | export class ServerResponse extends stream.WritableStream { 251 | // Extended base methods 252 | write(str: string, encoding?: string, fd?: string): boolean; 253 | write(buffer: NodeBuffer): boolean; 254 | 255 | writeContinue(): void; 256 | writeHead(statusCode: number, reasonPhrase?: string, headers?: any): void; 257 | writeHead(statusCode: number, headers?: any): void; 258 | statusCode: number; 259 | setHeader(name: string, value: string): void; 260 | sendDate: boolean; 261 | getHeader(name: string): string; 262 | removeHeader(name: string): void; 263 | write(chunk: any, encoding?: string): any; 264 | addTrailers(headers: any): void; 265 | end(data?: any, encoding?: string): void; 266 | } 267 | export class ClientRequest extends stream.WritableStream { 268 | // Extended base methods 269 | write(str: string, encoding?: string, fd?: string): boolean; 270 | write(buffer: NodeBuffer): boolean; 271 | 272 | write(chunk: any, encoding?: string): void; 273 | end(data?: any, encoding?: string): void; 274 | abort(): void; 275 | setTimeout(timeout: number, callback?: Function): void; 276 | setNoDelay(noDelay?: Function): void; 277 | setSocketKeepAlive(enable?: boolean, initialDelay?: number): void; 278 | } 279 | export class ClientResponse extends stream.ReadableStream { 280 | statusCode: number; 281 | httpVersion: string; 282 | headers: any; 283 | trailers: any; 284 | setEncoding(encoding?: string): void; 285 | pause(): void; 286 | resume(): void; 287 | } 288 | export interface Agent { maxSockets: number; sockets: any; requests: any; } 289 | 290 | export var STATUS_CODES; 291 | export function createServer(requestListener?: (request: ServerRequest, response: ServerResponse) =>void ): Server; 292 | export function createClient(port?: number, host?: string): any; 293 | export function request(options: any, callback?: (res: ClientResponse) => void): ClientRequest; 294 | export function get(options: any, callback?: (res: ClientResponse) => void): ClientRequest; 295 | export var globalAgent: Agent; 296 | } 297 | 298 | declare module "cluster" { 299 | import child_process = require("child_process"); 300 | 301 | export interface ClusterSettings { 302 | exec: string; 303 | args: string[]; 304 | silent: boolean; 305 | } 306 | export interface Worker { 307 | id: string; 308 | process: child_process.ChildProcess; 309 | suicide: boolean; 310 | send(message: any, sendHandle?: any): void; 311 | destroy(): void; 312 | disconnect(): void; 313 | } 314 | 315 | 316 | export var settings: ClusterSettings; 317 | export var isMaster: boolean; 318 | export var isWorker: boolean; 319 | export function setupMaster(settings?: ClusterSettings): void; 320 | export function fork(env?: any): Worker; 321 | export function disconnect(callback?: Function): void; 322 | export var workers: any; 323 | 324 | // Event emitter 325 | export function addListener(event: string, listener: Function): void; 326 | export function on(event: string, listener: Function): any; 327 | export function once(event: string, listener: Function): void; 328 | export function removeListener(event: string, listener: Function): void; 329 | export function removeAllListener(event: string): void; 330 | export function setMaxListeners(n: number): void; 331 | export function listeners(event: string): { Function; }[]; 332 | export function emit(event: string, arg1?: any, arg2?: any): void; 333 | } 334 | 335 | declare module "zlib" { 336 | import stream = require("stream"); 337 | export interface ZlibOptions { chunkSize?: number; windowBits?: number; level?: number; memLevel?: number; strategy?: number; dictionary?: any; } 338 | 339 | export class Gzip extends stream.ReadWriteStream { } 340 | export class Gunzip extends stream.ReadWriteStream { } 341 | export class Deflate extends stream.ReadWriteStream { } 342 | export class Inflate extends stream.ReadWriteStream { } 343 | export class DeflateRaw extends stream.ReadWriteStream { } 344 | export class InflateRaw extends stream.ReadWriteStream { } 345 | export class Unzip extends stream.ReadWriteStream { } 346 | 347 | export function createGzip(options: ZlibOptions): Gzip; 348 | export function createGunzip(options: ZlibOptions): Gunzip; 349 | export function createDeflate(options: ZlibOptions): Deflate; 350 | export function createInflate(options: ZlibOptions): Inflate; 351 | export function createDeflateRaw(options: ZlibOptions): DeflateRaw; 352 | export function createInflateRaw(options: ZlibOptions): InflateRaw; 353 | export function createUnzip(options: ZlibOptions): Unzip; 354 | 355 | export function deflate(buf: NodeBuffer, callback: (error: Error, result) =>void ): void; 356 | export function deflateRaw(buf: NodeBuffer, callback: (error: Error, result) =>void ): void; 357 | export function gzip(buf: NodeBuffer, callback: (error: Error, result) =>void ): void; 358 | export function gunzip(buf: NodeBuffer, callback: (error: Error, result) =>void ): void; 359 | export function inflate(buf: NodeBuffer, callback: (error: Error, result) =>void ): void; 360 | export function inflateRaw(buf: NodeBuffer, callback: (error: Error, result) =>void ): void; 361 | export function unzip(buf: NodeBuffer, callback: (error: Error, result) =>void ): void; 362 | 363 | // Constants 364 | export var Z_NO_FLUSH: number; 365 | export var Z_PARTIAL_FLUSH: number; 366 | export var Z_SYNC_FLUSH: number; 367 | export var Z_FULL_FLUSH: number; 368 | export var Z_FINISH: number; 369 | export var Z_BLOCK: number; 370 | export var Z_TREES: number; 371 | export var Z_OK: number; 372 | export var Z_STREAM_END: number; 373 | export var Z_NEED_DICT: number; 374 | export var Z_ERRNO: number; 375 | export var Z_STREAM_ERROR: number; 376 | export var Z_DATA_ERROR: number; 377 | export var Z_MEM_ERROR: number; 378 | export var Z_BUF_ERROR: number; 379 | export var Z_VERSION_ERROR: number; 380 | export var Z_NO_COMPRESSION: number; 381 | export var Z_BEST_SPEED: number; 382 | export var Z_BEST_COMPRESSION: number; 383 | export var Z_DEFAULT_COMPRESSION: number; 384 | export var Z_FILTERED: number; 385 | export var Z_HUFFMAN_ONLY: number; 386 | export var Z_RLE: number; 387 | export var Z_FIXED: number; 388 | export var Z_DEFAULT_STRATEGY: number; 389 | export var Z_BINARY: number; 390 | export var Z_TEXT: number; 391 | export var Z_ASCII: number; 392 | export var Z_UNKNOWN: number; 393 | export var Z_DEFLATED: number; 394 | export var Z_NULL: number; 395 | } 396 | 397 | declare module "os" { 398 | export function tmpDir(): string; 399 | export function hostname(): string; 400 | export function type(): string; 401 | export function platform(): string; 402 | export function arch(): string; 403 | export function release(): string; 404 | export function uptime(): number; 405 | export function loadavg(): number[]; 406 | export function totalmem(): number; 407 | export function freemem(): number; 408 | export function cpus(): { model: string; speed: number; times: { user: number; nice: number; sys: number; idle: number; irq: number; }; }[]; 409 | export function networkInterfaces(): any; 410 | export var EOL: string; 411 | } 412 | 413 | declare module "https" { 414 | import tls = require("tls"); 415 | import events = require("events"); 416 | import http = require("http"); 417 | 418 | export interface ServerOptions { 419 | pfx?: any; 420 | key?: any; 421 | passphrase?: string; 422 | cert?: any; 423 | ca?: any; 424 | crl?: any; 425 | ciphers?: string; 426 | honorCipherOrder?: boolean; 427 | requestCert?: boolean; 428 | rejectUnauthorized?: boolean; 429 | NPNProtocols?: any; 430 | SNICallback?: (servername: string) => any; 431 | } 432 | 433 | export interface RequestOptions { 434 | host?: string; 435 | hostname?: string; 436 | port?: number; 437 | path?: string; 438 | method?: string; 439 | headers?: any; 440 | auth?: string; 441 | agent?: any; 442 | pfx?: any; 443 | key?: any; 444 | passphrase?: string; 445 | cert?: any; 446 | ca?: any; 447 | ciphers?: string; 448 | rejectUnauthorized?: boolean; 449 | } 450 | 451 | export interface NodeAgent { 452 | maxSockets: number; 453 | sockets: any; 454 | requests: any; 455 | } 456 | export var Agent: { 457 | new (options?: RequestOptions): NodeAgent; 458 | }; 459 | export class Server extends tls.Server { } 460 | export function createServer(options: ServerOptions, requestListener?: Function): Server; 461 | export function request(options: RequestOptions, callback?: (res: events.EventEmitter) =>void ): http.ClientRequest; 462 | export function get(options: RequestOptions, callback?: (res: events.EventEmitter) =>void ): http.ClientRequest; 463 | export var globalAgent: NodeAgent; 464 | } 465 | 466 | declare module "punycode" { 467 | export function decode(string: string): string; 468 | export function encode(string: string): string; 469 | export function toUnicode(domain: string): string; 470 | export function toASCII(domain: string): string; 471 | export var ucs2: ucs2; 472 | export interface ucs2 { 473 | decode(string: string): string; 474 | encode(codePoints: number[]): string; 475 | } 476 | export var version; 477 | } 478 | 479 | declare module "repl" { 480 | import stream = require("stream"); 481 | import events = require("events"); 482 | 483 | export interface ReplOptions { 484 | prompt?: string; 485 | input?: stream.ReadableStream; 486 | output?: stream.WritableStream; 487 | terminal?: boolean; 488 | eval?: Function; 489 | useColors?: boolean; 490 | useGlobal?: boolean; 491 | ignoreUndefined?: boolean; 492 | writer?: Function; 493 | } 494 | export function start(options: ReplOptions): events.EventEmitter; 495 | } 496 | 497 | declare module "readline" { 498 | import events = require("events"); 499 | import stream = require("stream"); 500 | 501 | export class ReadLine extends events.EventEmitter { 502 | setPrompt(prompt: string, length: number): void; 503 | prompt(preserveCursor?: boolean): void; 504 | question(query: string, callback: Function): void; 505 | pause(): void; 506 | resume(): void; 507 | close(): void; 508 | write(data: any, key?: any): void; 509 | } 510 | export interface ReadLineOptions { 511 | input: stream.ReadableStream; 512 | output: stream.WritableStream; 513 | completer?: Function; 514 | terminal?: boolean; 515 | } 516 | export function createInterface(options: ReadLineOptions): ReadLine; 517 | } 518 | 519 | declare module "vm" { 520 | export interface Context { } 521 | export interface Script { 522 | runInThisContext(): void; 523 | runInNewContext(sandbox?: Context): void; 524 | } 525 | export function runInThisContext(code: string, filename?: string): void; 526 | export function runInNewContext(code: string, sandbox?: Context, filename?: string): void; 527 | export function runInContext(code: string, context: Context, filename?: string): void; 528 | export function createContext(initSandbox?: Context): Context; 529 | export function createScript(code: string, filename?: string): Script; 530 | } 531 | 532 | declare module "child_process" { 533 | import events = require("events"); 534 | import stream = require("stream"); 535 | 536 | export class ChildProcess extends events.EventEmitter { 537 | stdin: stream.WritableStream; 538 | stdout: stream.ReadableStream; 539 | stderr: stream.ReadableStream; 540 | pid: number; 541 | kill(signal?: string): void; 542 | send(message: any, sendHandle: any): void; 543 | disconnect(): void; 544 | } 545 | 546 | export function spawn(command: string, args?: string[], options?: { 547 | cwd?: string; 548 | stdio?: any; 549 | custom?: any; 550 | env?: any; 551 | detached?: boolean; 552 | }): ChildProcess; 553 | export function exec(command: string, options: { 554 | cwd?: string; 555 | stdio?: any; 556 | customFds?: any; 557 | env?: any; 558 | encoding?: string; 559 | timeout?: number; 560 | maxBuffer?: number; 561 | killSignal?: string; 562 | }, callback: (error: Error, stdout: NodeBuffer, stderr: NodeBuffer) =>void ): ChildProcess; 563 | export function exec(command: string, callback: (error: Error, stdout: NodeBuffer, stderr: NodeBuffer) =>void ): ChildProcess; 564 | export function execFile(file: string, args: string[], options: { 565 | cwd?: string; 566 | stdio?: any; 567 | customFds?: any; 568 | env?: any; 569 | encoding?: string; 570 | timeout?: number; 571 | maxBuffer?: string; 572 | killSignal?: string; 573 | }, callback: (error: Error, stdout: NodeBuffer, stderr: NodeBuffer) =>void ): ChildProcess; 574 | export function fork(modulePath: string, args?: string[], options?: { 575 | cwd?: string; 576 | env?: any; 577 | encoding?: string; 578 | }): ChildProcess; 579 | } 580 | 581 | declare module "url" { 582 | export interface Url { 583 | href?: string; 584 | protocol?: string; 585 | auth?: string; 586 | hostname?: string; 587 | port?: string; 588 | host?: string; 589 | pathname?: string; 590 | search?: string; 591 | query?: any; 592 | slashes?: boolean; 593 | hash?: string; 594 | } 595 | 596 | export function parse(urlStr: string, parseQueryString? , slashesDenoteHost? ): Url; 597 | export function format(url: Url): string; 598 | export function resolve(from: string, to: string): string; 599 | } 600 | 601 | declare module "dns" { 602 | export function lookup(domain: string, family: number, callback: (err: Error, address: string, family: number) =>void ): string; 603 | export function lookup(domain: string, callback: (err: Error, address: string, family: number) =>void ): string; 604 | export function resolve(domain: string, rrtype: string, callback: (err: Error, addresses: string[]) =>void ): string[]; 605 | export function resolve(domain: string, callback: (err: Error, addresses: string[]) =>void ): string[]; 606 | export function resolve4(domain: string, callback: (err: Error, addresses: string[]) =>void ): string[]; 607 | export function resolve6(domain: string, callback: (err: Error, addresses: string[]) =>void ): string[]; 608 | export function resolveMx(domain: string, callback: (err: Error, addresses: string[]) =>void ): string[]; 609 | export function resolveTxt(domain: string, callback: (err: Error, addresses: string[]) =>void ): string[]; 610 | export function resolveSrv(domain: string, callback: (err: Error, addresses: string[]) =>void ): string[]; 611 | export function resolveNs(domain: string, callback: (err: Error, addresses: string[]) =>void ): string[]; 612 | export function resolveCname(domain: string, callback: (err: Error, addresses: string[]) =>void ): string[]; 613 | export function reverse(ip: string, callback: (err: Error, domains: string[]) =>void ): string[]; 614 | } 615 | 616 | declare module "net" { 617 | import stream = require("stream"); 618 | 619 | export class NodeSocket extends stream.ReadWriteStream { 620 | // Extended base methods 621 | write(str: string, encoding?: string, fd?: string): boolean; 622 | write(buffer: NodeBuffer): boolean; 623 | 624 | connect(port: number, host?: string, connectionListener?: Function): void; 625 | connect(path: string, connectionListener?: Function): void; 626 | bufferSize: number; 627 | setEncoding(encoding?: string): void; 628 | write(data: any, encoding?: string, callback?: Function): void; 629 | end(data?: any, encoding?: string): void; 630 | destroy(): void; 631 | pause(): void; 632 | resume(): void; 633 | setTimeout(timeout: number, callback?: Function): void; 634 | setNoDelay(noDelay?: boolean): void; 635 | setKeepAlive(enable?: boolean, initialDelay?: number): void; 636 | address(): { port: number; family: string; address: string; }; 637 | remoteAddress: string; 638 | remotePort: number; 639 | bytesRead: number; 640 | bytesWritten: number; 641 | } 642 | 643 | export var Socket: { 644 | new (options?: { fd?: string; type?: string; allowHalfOpen?: boolean; }): NodeSocket; 645 | }; 646 | 647 | export class Server extends NodeSocket { 648 | listen(port: number, host?: string, backlog?: number, listeningListener?: Function): void; 649 | listen(path: string, listeningListener?: Function): void; 650 | listen(handle: any, listeningListener?: Function): void; 651 | close(callback?: Function): void; 652 | address(): { port: number; family: string; address: string; }; 653 | maxConnections: number; 654 | connections: number; 655 | } 656 | export function createServer(connectionListener?: (socket: NodeSocket) =>void ): Server; 657 | export function createServer(options?: { allowHalfOpen?: boolean; }, connectionListener?: (socket: NodeSocket) =>void ): Server; 658 | export function connect(options: { allowHalfOpen?: boolean; }, connectionListener?: Function): void; 659 | export function connect(port: number, host?: string, connectionListener?: Function): void; 660 | export function connect(path: string, connectionListener?: Function): void; 661 | export function createConnection(options: { allowHalfOpen?: boolean; }, connectionListener?: Function): void; 662 | export function createConnection(port: number, host?: string, connectionListener?: Function): void; 663 | export function createConnection(path: string, connectionListener?: Function): void; 664 | export function isIP(input: string): number; 665 | export function isIPv4(input: string): boolean; 666 | export function isIPv6(input: string): boolean; 667 | } 668 | 669 | declare module "dgram" { 670 | import events = require("events"); 671 | 672 | export function createSocket(type: string, callback?: Function): Socket; 673 | 674 | export class Socket extends events.EventEmitter { 675 | send(buf: NodeBuffer, offset: number, length: number, port: number, address: string, callback?: Function): void; 676 | bind(port: number, address?: string): void; 677 | close(): void; 678 | address: { address: string; family: string; port: number; }; 679 | setBroadcast(flag: boolean): void; 680 | setMulticastTTL(ttl: number): void; 681 | setMulticastLoopback(flag: boolean): void; 682 | addMembership(multicastAddress: string, multicastInterface?: string): void; 683 | dropMembership(multicastAddress: string, multicastInterface?: string): void; 684 | } 685 | } 686 | 687 | declare module "fs" { 688 | import stream = require("stream"); 689 | 690 | export interface Stats { 691 | isFile(): boolean; 692 | isDirectory(): boolean; 693 | isBlockDevice(): boolean; 694 | isCharacterDevice(): boolean; 695 | isSymbolicLink(): boolean; 696 | isFIFO(): boolean; 697 | isSocket(): boolean; 698 | dev: number; 699 | ino: number; 700 | mode: number; 701 | nlink: number; 702 | uid: number; 703 | gid: number; 704 | rdev: number; 705 | size: number; 706 | blksize: number; 707 | blocks: number; 708 | atime: Date; 709 | mtime: Date; 710 | ctime: Date; 711 | } 712 | 713 | export interface FSWatcher { 714 | close(): void; 715 | } 716 | 717 | export class ReadStream extends stream.ReadableStream { } 718 | export class WriteStream extends stream.WritableStream { } 719 | 720 | export function rename(oldPath: string, newPath: string, callback?: Function): void; 721 | export function renameSync(oldPath: string, newPath: string): void; 722 | export function truncate(fd: number, len: number, callback?: Function): void; 723 | export function truncateSync(fd: number, len: number): void; 724 | export function chown(path: string, uid: number, gid: number, callback?: Function): void; 725 | export function chownSync(path: string, uid: number, gid: number): void; 726 | export function fchown(fd: number, uid: number, gid: number, callback?: Function): void; 727 | export function fchownSync(fd: number, uid: number, gid: number): void; 728 | export function lchown(path: string, uid: number, gid: number, callback?: Function): void; 729 | export function lchownSync(path: string, uid: number, gid: number): void; 730 | export function chmod(path: string, mode: number, callback?: Function): void; 731 | export function chmod(path: string, mode: string, callback?: Function): void; 732 | export function chmodSync(path: string, mode: number): void; 733 | export function chmodSync(path: string, mode: string): void; 734 | export function fchmod(fd: number, mode: number, callback?: Function): void; 735 | export function fchmod(fd: number, mode: string, callback?: Function): void; 736 | export function fchmodSync(fd: number, mode: number): void; 737 | export function fchmodSync(fd: number, mode: string): void; 738 | export function lchmod(path: string, mode: string, callback?: Function): void; 739 | export function lchmod(path: string, mode: number, callback?: Function): void; 740 | export function lchmodSync(path: string, mode: number): void; 741 | export function lchmodSync(path: string, mode: string): void; 742 | export function stat(path: string, callback?: (err: Error, stats: Stats) =>any): Stats; 743 | export function lstat(path: string, callback?: (err: Error, stats: Stats) =>any): Stats; 744 | export function fstat(fd: number, callback?: (err: Error, stats: Stats) =>any): Stats; 745 | export function statSync(path: string): Stats; 746 | export function lstatSync(path: string): Stats; 747 | export function fstatSync(fd: number): Stats; 748 | export function link(srcpath: string, dstpath: string, callback?: Function): void; 749 | export function linkSync(srcpath: string, dstpath: string): void; 750 | export function symlink(srcpath: string, dstpath: string, type?: string, callback?: Function): void; 751 | export function symlinkSync(srcpath: string, dstpath: string, type?: string): void; 752 | export function readlink(path: string, callback?: (err: Error, linkString: string) =>any): void; 753 | export function realpath(path: string, callback?: (err: Error, resolvedPath: string) =>any): void; 754 | export function realpath(path: string, cache: string, callback: (err: Error, resolvedPath: string) =>any): void; 755 | export function realpathSync(path: string, cache?: boolean): string; 756 | export function unlink(path: string, callback?: Function): void; 757 | export function unlinkSync(path: string): void; 758 | export function rmdir(path: string, callback?: Function): void; 759 | export function rmdirSync(path: string): void; 760 | export function mkdir(path: string, mode?: number, callback?: Function): void; 761 | export function mkdir(path: string, mode?: string, callback?: Function): void; 762 | export function mkdirSync(path: string, mode?: number): void; 763 | export function mkdirSync(path: string, mode?: string): void; 764 | export function readdir(path: string, callback?: (err: Error, files: string[]) => void): void; 765 | export function readdirSync(path: string): string[]; 766 | export function close(fd: number, callback?: Function): void; 767 | export function closeSync(fd: number): void; 768 | export function open(path: string, flags: string, mode?: string, callback?: (err: Error, fd: number) =>any): void; 769 | export function openSync(path: string, flags: string, mode?: string): number; 770 | export function utimes(path: string, atime: number, mtime: number, callback?: Function): void; 771 | export function utimesSync(path: string, atime: number, mtime: number): void; 772 | export function futimes(fd: number, atime: number, mtime: number, callback?: Function): void; 773 | export function futimesSync(fd: number, atime: number, mtime: number): void; 774 | export function fsync(fd: number, callback?: Function): void; 775 | export function fsyncSync(fd: number): void; 776 | export function write(fd: number, buffer: NodeBuffer, offset: number, length: number, position: number, callback?: (err: Error, written: number, buffer: NodeBuffer) =>any): void; 777 | export function writeSync(fd: number, buffer: NodeBuffer, offset: number, length: number, position: number): number; 778 | export function read(fd: number, buffer: NodeBuffer, offset: number, length: number, position: number, callback?: (err: Error, bytesRead: number, buffer: NodeBuffer) => void): void; 779 | export function readSync(fd: number, buffer: NodeBuffer, offset: number, length: number, position: number): number; 780 | export function readFile(filename: string, encoding: string, callback: (err: Error, data: string) => void ): void; 781 | export function readFile(filename: string, callback: (err: Error, data: NodeBuffer) => void ): void; 782 | export function readFileSync(filename: string, options?: { flag?: string; }): NodeBuffer; 783 | export function readFileSync(filename: string, options: { encoding: string; flag?: string; }): string; 784 | export function writeFile(filename: string, data: any, options?: { encoding?: string; mode?: number; flag?: string; }, callback?: Function): void; 785 | export function writeFile(filename: string, data: any, callback: Function): void; 786 | export function writeFileSync(filename: string, data: any, options?: { encoding?: string; mode?: number; flag?: string; }): void; 787 | export function appendFile(filename: string, data: any, options?: { encoding?: string; mode?: number; flag?: string; }, callback?: Function): void; 788 | export function appendFile(filename: string, data: any, callback: Function): void; 789 | export function appendFileSync(filename: string, data: any, options?: { encoding?: string; mode?: number; flag?: string; }): void; 790 | export function watchFile(filename: string, listener: (curr: Stats, prev: Stats)=>void): void; 791 | export function watchFile(filename: string, options: { persistent?: boolean; interval?: number; }, listener: (curr: Stats, prev: Stats)=>void): void; 792 | export function unwatchFile(filename: string, listener?: (curr: Stats, prev: Stats)=>void): void; 793 | export function watch(filename: string, options?: { persistent?: boolean; }, listener?: (event: string, filename: string) =>any): FSWatcher; 794 | export function exists(path: string, callback?: (exists: boolean) =>void ): void; 795 | export function existsSync(path: string): boolean; 796 | export function createReadStream(path: string, options?: { 797 | flags?: string; 798 | encoding?: string; 799 | fd?: string; 800 | mode?: number; 801 | bufferSize?: number; 802 | }): ReadStream; 803 | export function createWriteStream(path: string, options?: { 804 | flags?: string; 805 | encoding?: string; 806 | string?: string; 807 | }): WriteStream; 808 | } 809 | 810 | declare module "path" { 811 | export function normalize(p: string): string; 812 | export function join(...paths: any[]): string; 813 | export function resolve(from: string, to: string): string; 814 | export function resolve(from: string, from2: string, to: string): string; 815 | export function resolve(from: string, from2: string, from3: string, to: string): string; 816 | export function resolve(from: string, from2: string, from3: string, from4: string, to: string): string; 817 | export function resolve(from: string, from2: string, from3: string, from4: string, from5: string, to: string): string; 818 | export function relative(from: string, to: string): string; 819 | export function dirname(p: string): string; 820 | export function basename(p: string, ext?: string): string; 821 | export function extname(p: string): string; 822 | export var sep: string; 823 | } 824 | 825 | declare module "string_decoder" { 826 | export interface NodeStringDecoder { 827 | write(buffer: NodeBuffer): string; 828 | detectIncompleteChar(buffer: NodeBuffer): number; 829 | } 830 | export var StringDecoder: { 831 | new (encoding: string): NodeStringDecoder; 832 | }; 833 | } 834 | 835 | declare module "tls" { 836 | import crypto = require("crypto"); 837 | import net = require("net"); 838 | import stream = require("stream"); 839 | 840 | export var CLIENT_RENEG_LIMIT: number; 841 | export var CLIENT_RENEG_WINDOW: number; 842 | 843 | export interface TlsOptions { 844 | pfx?: any; //string or buffer 845 | key?: any; //string or buffer 846 | passphrase?: string; 847 | cert?: any; 848 | ca?: any; //string or buffer 849 | crl?: any; //string or string array 850 | ciphers?: string; 851 | honorCipherOrder?: any; 852 | requestCert?: boolean; 853 | rejectUnauthorized?: boolean; 854 | NPNProtocols?: any; //array or Buffer; 855 | SNICallback?: (servername: string) => any; 856 | } 857 | 858 | export interface ConnectionOptions { 859 | host?: string; 860 | port?: number; 861 | socket?: net.NodeSocket; 862 | pfx?: any; //string | Buffer 863 | key?: any; //string | Buffer 864 | passphrase?: string; 865 | cert?: any; //string | Buffer 866 | ca?: any; //Array of string | Buffer 867 | rejectUnauthorized?: boolean; 868 | NPNProtocols?: any; //Array of string | Buffer 869 | servername?: string; 870 | } 871 | 872 | export class Server extends net.Server { 873 | // Extended base methods 874 | listen(port: number, host?: string, backlog?: number, listeningListener?: Function): void; 875 | listen(path: string, listeningListener?: Function): void; 876 | listen(handle: any, listeningListener?: Function): void; 877 | 878 | listen(port: number, host?: string, callback?: Function): void; 879 | close(): void; 880 | address(): { port: number; family: string; address: string; }; 881 | addContext(hostName: string, credentials: { 882 | key: string; 883 | cert: string; 884 | ca: string; 885 | }): void; 886 | maxConnections: number; 887 | connections: number; 888 | } 889 | 890 | export class ClearTextStream extends stream.ReadWriteStream { 891 | authorized: boolean; 892 | authorizationError: Error; 893 | getPeerCertificate(): any; 894 | getCipher: { 895 | name: string; 896 | version: string; 897 | }; 898 | address: { 899 | port: number; 900 | family: string; 901 | address: string; 902 | }; 903 | remoteAddress: string; 904 | remotePort: number; 905 | } 906 | 907 | export interface SecurePair { 908 | encrypted: any; 909 | cleartext: any; 910 | } 911 | 912 | export function createServer(options: TlsOptions, secureConnectionListener?: (cleartextStream: ClearTextStream) =>void ): Server; 913 | export function connect(options: TlsOptions, secureConnectionListener?: () =>void ): ClearTextStream; 914 | export function connect(port: number, host?: string, options?: ConnectionOptions, secureConnectListener?: () =>void ): ClearTextStream; 915 | export function connect(port: number, options?: ConnectionOptions, secureConnectListener?: () =>void ): ClearTextStream; 916 | export function createSecurePair(credentials?: crypto.Credentials, isServer?: boolean, requestCert?: boolean, rejectUnauthorized?: boolean): SecurePair; 917 | } 918 | 919 | declare module "crypto" { 920 | export interface CredentialDetails { 921 | pfx: string; 922 | key: string; 923 | passphrase: string; 924 | cert: string; 925 | ca: any; //string | string array 926 | crl: any; //string | string array 927 | ciphers: string; 928 | } 929 | export interface Credentials { context?: any; } 930 | export function createCredentials(details: CredentialDetails): Credentials; 931 | export function createHash(algorithm: string): Hash; 932 | export function createHmac(algorithm: string, key: string): Hmac; 933 | export function createHmac(algorithm: string, key: NodeBuffer): Hmac; 934 | export interface Hash { 935 | update(data: any, input_encoding?: string): Hash; 936 | digest(encoding?: string): any; 937 | } 938 | export interface Hmac { 939 | update(data: any): Hmac; 940 | digest(encoding?: string): any; 941 | } 942 | export function createCipher(algorithm: string, password: any): Cipher; 943 | export function createCipheriv(algorithm: string, key: any, iv: any): Cipher; 944 | export interface Cipher { 945 | update(data: any, input_encoding: string, output_encoding: string): string; 946 | update(data: any, input_encoding?: string): NodeBuffer; 947 | final(output_encoding: string): string; 948 | final(): NodeBuffer; 949 | setAutoPadding(auto_padding: boolean): void; 950 | } 951 | export function createDecipher(algorithm: string, password: any): Decipher; 952 | export function createDecipheriv(algorithm: string, key: any, iv: any): Decipher; 953 | export interface Decipher { 954 | update(data: any, input_encoding: string, output_encoding: string): string; 955 | update(data: any, input_encoding?: string): NodeBuffer; 956 | final(output_encoding: string): string; 957 | final(): NodeBuffer; 958 | setAutoPadding(auto_padding: boolean): void; 959 | } 960 | export function createSign(algorithm: string): Signer; 961 | export interface Signer { 962 | update(data: any): void; 963 | sign(private_key: string, output_format: string): string; 964 | } 965 | export function createVerify(algorith: string): Verify; 966 | export interface Verify { 967 | update(data: any): void; 968 | verify(object: string, signature: string, signature_format?: string): boolean; 969 | } 970 | export function createDiffieHellman(prime_length: number): DiffieHellman; 971 | export function createDiffieHellman(prime: number, encoding?: string): DiffieHellman; 972 | export interface DiffieHellman { 973 | generateKeys(encoding?: string): string; 974 | computeSecret(other_public_key: string, input_encoding?: string, output_encoding?: string): string; 975 | getPrime(encoding?: string): string; 976 | getGenerator(encoding: string): string; 977 | getPublicKey(encoding?: string): string; 978 | getPrivateKey(encoding?: string): string; 979 | setPublicKey(public_key: string, encoding?: string): void; 980 | setPrivateKey(public_key: string, encoding?: string): void; 981 | } 982 | export function getDiffieHellman(group_name: string): DiffieHellman; 983 | export function pbkdf2(password: string, salt: string, iterations: number, keylen: number, callback: (err: Error, derivedKey: string) => any): void; 984 | export function randomBytes(size: number, callback?: (err: Error, buf: NodeBuffer) => void) : NodeBuffer; 985 | export function pseudoRandomBytes(size: number, callback?: (err: Error, buf: NodeBuffer) => void) : NodeBuffer; 986 | } 987 | 988 | declare module "stream" { 989 | import events = require("events"); 990 | 991 | export interface WriteStream { 992 | writable: boolean; 993 | write(str: string, encoding?: string, fd?: string): boolean; 994 | write(buffer: NodeBuffer): boolean; 995 | end(): void; 996 | end(str: string, enconding: string): void; 997 | end(buffer: NodeBuffer): void; 998 | destroy(): void; 999 | destroySoon(): void; 1000 | } 1001 | 1002 | export class WritableStream extends events.EventEmitter implements WriteStream { 1003 | writable: boolean; 1004 | write(str: string, encoding?: string, fd?: string): boolean; 1005 | write(buffer: NodeBuffer): boolean; 1006 | end(): void; 1007 | end(str: string, enconding: string): void; 1008 | end(buffer: NodeBuffer): void; 1009 | destroy(): void; 1010 | destroySoon(): void; 1011 | } 1012 | 1013 | export class Readable extends events.EventEmitter { 1014 | readable: boolean; 1015 | setEncoding(encoding: string): void; 1016 | pause(): void; 1017 | resume(): void; 1018 | destroy(): void; 1019 | push(chunk, encoding?): void; 1020 | pipe(destination: WriteStream, options?: { end?: boolean; }): void; 1021 | } 1022 | 1023 | export class ReadableStream extends events.EventEmitter { 1024 | readable: boolean; 1025 | setEncoding(encoding: string): void; 1026 | pause(): void; 1027 | resume(): void; 1028 | destroy(): void; 1029 | push(chunk, encoding?): void; 1030 | pipe(destination: WriteStream, options?: { end?: boolean; }): void; 1031 | } 1032 | 1033 | export class ReadWriteStream extends events.EventEmitter implements WriteStream { 1034 | readable: boolean; 1035 | setEncoding(encoding: string): void; 1036 | pause(): void; 1037 | resume(): void; 1038 | pipe(destination: WriteStream, options?: { end?: boolean; }): void; 1039 | 1040 | writable: boolean; 1041 | write(str: string, encoding?: string, fd?: string): boolean; 1042 | write(buffer: NodeBuffer): boolean; 1043 | end(): void; 1044 | end(str: string, enconding: string): void; 1045 | end(buffer: NodeBuffer): void; 1046 | destroy(): void; 1047 | destroySoon(): void; 1048 | } 1049 | } 1050 | 1051 | declare module "util" { 1052 | export function format(format: any, ...param: any[]): string; 1053 | export function debug(string: string): void; 1054 | export function error(...param: any[]): void; 1055 | export function puts(...param: any[]): void; 1056 | export function print(...param: any[]): void; 1057 | export function log(string: string): void; 1058 | export function inspect(object: any, showHidden?: boolean, depth?: number, color?: boolean): string; 1059 | export function isArray(object: any): boolean; 1060 | export function isRegExp(object: any): boolean; 1061 | export function isDate(object: any): boolean; 1062 | export function isError(object: any): boolean; 1063 | export function inherits(constructor: any, superConstructor: any): void; 1064 | } 1065 | 1066 | declare module "assert" { 1067 | export function fail(actual: any, expected: any, message: string, operator: string): void; 1068 | export function assert(value: any, message: string): void; 1069 | export function ok(value: any, message?: string): void; 1070 | export function equal(actual: any, expected: any, message?: string): void; 1071 | export function notEqual(actual: any, expected: any, message?: string): void; 1072 | export function deepEqual(actual: any, expected: any, message?: string): void; 1073 | export function notDeepEqual(acutal: any, expected: any, message?: string): void; 1074 | export function strictEqual(actual: any, expected: any, message?: string): void; 1075 | export function notStrictEqual(actual: any, expected: any, message?: string): void; 1076 | export function throws(block: any, error?: any, messsage?: string): void; 1077 | export function doesNotThrow(block: any, error?: any, messsage?: string): void; 1078 | export function ifError(value: any): void; 1079 | } 1080 | 1081 | declare module "tty" { 1082 | import net = require("net"); 1083 | 1084 | export function isatty(fd: string): boolean; 1085 | export class ReadStream extends net.NodeSocket { 1086 | isRaw: boolean; 1087 | setRawMode(mode: boolean): void; 1088 | } 1089 | export class WriteStream extends net.NodeSocket { 1090 | columns: number; 1091 | rows: number; 1092 | } 1093 | } 1094 | 1095 | declare module "domain" { 1096 | import events = require("events"); 1097 | 1098 | export class Domain extends events.EventEmitter { } 1099 | 1100 | export function create(): Domain; 1101 | export function run(fn: Function): void; 1102 | export function add(emitter: events.EventEmitter): void; 1103 | export function remove(emitter: events.EventEmitter): void; 1104 | export function bind(cb: (er: Error, data: any) =>any): any; 1105 | export function intercept(cb: (data: any) => any): any; 1106 | export function dispose(): void; 1107 | } 1108 | -------------------------------------------------------------------------------- /tests/Test01+Extensions.swift: -------------------------------------------------------------------------------- 1 | struct TestExtension { 2 | } -------------------------------------------------------------------------------- /tests/Test01.swift: -------------------------------------------------------------------------------- 1 | struct Test01 { 2 | let one: Int 3 | let two: String? 4 | } 5 | 6 | -------------------------------------------------------------------------------- /tests/Test02.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | typealias MyInt = Int 4 | 5 | struct Test02 { 6 | let one: MyInt 7 | let two: String? 8 | let sub: Sub 9 | } 10 | 11 | struct Sub { 12 | let one: URL 13 | let two: Date 14 | 15 | // static func decode(json: AnyObject) -> Sub? { 16 | // return Sub(one: NSURL(), two: NSDate()) 17 | // } 18 | } 19 | 20 | //extension Test02 { 21 | // func encodeJson() -> AnyObject { 22 | // var dict: [String: AnyObject] = [:] 23 | // dict["one"] = one.encodeJson() 24 | // return dict 25 | // } 26 | //} 27 | -------------------------------------------------------------------------------- /tests/Test03.swift: -------------------------------------------------------------------------------- 1 | struct Test03 { 2 | let one: Int 3 | let two: String? 4 | let three: [Bool] 5 | } 6 | 7 | -------------------------------------------------------------------------------- /tests/Test04.swift: -------------------------------------------------------------------------------- 1 | typealias MyBool = Bool 2 | typealias MyOptionalBool = MyBool? 3 | typealias MySecondOptionalBool = MyOptionalBool 4 | 5 | struct Test04 { 6 | let one: Int 7 | let two: MyBool? 8 | let three: MySecondOptionalBool 9 | let four: [String?] 10 | let five: [Double]? 11 | let six: [Bool?]? 12 | } 13 | -------------------------------------------------------------------------------- /tests/Test05.swift: -------------------------------------------------------------------------------- 1 | import Statham 2 | 3 | struct Test05 { 4 | let one: AnyJson 5 | let two: JsonObject 6 | let three: JsonArray 7 | let four: JsonObject? 8 | let five: [JsonArray] 9 | let six: [[AnyJson?]?]? 10 | let seven: [String: Int?] 11 | } 12 | 13 | -------------------------------------------------------------------------------- /tests/Test06a.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | struct Test06a { 4 | let one: Int 5 | let sub: Sub06b 6 | } 7 | 8 | struct Sub06a { 9 | let two: Date 10 | } 11 | 12 | -------------------------------------------------------------------------------- /tests/Test06b.swift: -------------------------------------------------------------------------------- 1 | struct Sub06b { 2 | let one: Int 3 | let sub: Sub06a 4 | } 5 | 6 | -------------------------------------------------------------------------------- /tests/Test07.swift: -------------------------------------------------------------------------------- 1 | struct Test07 { 2 | let one: Int 3 | let nested: Nested 4 | 5 | struct Nested { 6 | let one: Int 7 | let two: Bool 8 | } 9 | } 10 | 11 | -------------------------------------------------------------------------------- /tests/Test08.swift: -------------------------------------------------------------------------------- 1 | import Statham 2 | 3 | struct Test08 { 4 | let one: Int 5 | let two: [String: Int] 6 | // let three: [Bool: Float] // Can't encode non-string based keys in Json 7 | let four: [Enum08: Int] 8 | let five: JsonObject 9 | } 10 | 11 | typealias Test08String = String 12 | 13 | enum Enum08: Test08String { 14 | case One = "One" 15 | case Two = "Two" 16 | } 17 | -------------------------------------------------------------------------------- /tests/Test09.swift: -------------------------------------------------------------------------------- 1 | struct Test09 { 2 | let one: Int 3 | let intSub1: Sub1 4 | let stringSub1: Sub1 5 | let sub2: Sub2 6 | let sub3: Sub3 7 | 8 | var computed: String { 9 | return stringSub1.value + "!" 10 | } 11 | } 12 | 13 | struct Sub1 { 14 | let one: Bool 15 | let value: T 16 | } 17 | 18 | struct Sub2 { 19 | let a: A 20 | let b: B? 21 | let c: [[B?]?]? 22 | } 23 | 24 | struct Sub3 { 25 | let a1: A 26 | let a2: A 27 | let b: B? 28 | let c: [C] 29 | let sub2: Sub2 30 | } 31 | -------------------------------------------------------------------------------- /tests/Test10.swift: -------------------------------------------------------------------------------- 1 | enum Test10a { 2 | case one(Int) 3 | case two(Bool) 4 | } 5 | 6 | enum Test10b : String { 7 | case One = "One" 8 | case Two = "Two" 9 | } 10 | 11 | enum Test10c : Int { 12 | case one = 1 13 | case two = 2 14 | } 15 | -------------------------------------------------------------------------------- /tests/Test11_nested_enums.swift: -------------------------------------------------------------------------------- 1 | // Deeply nested implementations: https://github.com/tomlokhorst/swift-json-gen/issues/9 2 | import Statham 3 | 4 | typealias X = Int 5 | 6 | struct Test11a { 7 | let s: String 8 | 9 | enum Test11b : X { 10 | case one = 1 11 | case two = 2 12 | 13 | struct Test11c { 14 | let x: Int 15 | 16 | enum Test11d : X { 17 | case one = 1 18 | case two = 2 19 | } 20 | 21 | func encodeJson() -> [String: Any] { 22 | var dict: [String: Any] = [:] 23 | 24 | dict["x"] = x.encodeJson() 25 | 26 | return dict 27 | } 28 | } 29 | 30 | static func decodeJson(_ json: AnyObject) throws -> Test11b { 31 | guard let rawValue = json as? X else { 32 | throw JsonDecodeError.wrongType(rawValue: json, expectedType: "X") 33 | } 34 | guard let value = Test11a.Test11b(rawValue: rawValue) else { 35 | throw JsonDecodeError.wrongEnumRawValue(rawValue: rawValue, enumType: "Test11a.Test11b") 36 | } 37 | 38 | return value 39 | } 40 | } 41 | } 42 | 43 | 44 | extension Test11a.Test11b.Test11c.Test11d { 45 | 46 | func encodeJson() -> X { 47 | return rawValue 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /tests/Test12_empty_struct.swift: -------------------------------------------------------------------------------- 1 | struct Test12 { 2 | struct Test12b { } 3 | } 4 | 5 | -------------------------------------------------------------------------------- /tests/Test13_struct_in_extension.swift: -------------------------------------------------------------------------------- 1 | // Struct in extension: https://github.com/tomlokhorst/swift-json-gen/issues/22 2 | // Doesn't appear to be possible to generate something for this? 3 | 4 | struct Test13 { 5 | let title: String 6 | // let two: Test13.Test13b 7 | } 8 | 9 | extension Test13 { 10 | struct Test13b { 11 | let title: String 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tests/Test14_generate_init.swift: -------------------------------------------------------------------------------- 1 | // Generate initializer: https://github.com/tomlokhorst/swift-json-gen/issues/20 2 | 3 | struct Test14a { 4 | let one: Int 5 | let two: String? 6 | 7 | init(one: Int) { 8 | self.one = one 9 | self.two = nil 10 | } 11 | 12 | init(two: String) { 13 | self.one = 0 14 | self.two = two 15 | } 16 | 17 | init(two: String, one: Int) { 18 | self.one = one 19 | self.two = two 20 | } 21 | 22 | fileprivate init(one: Int, two: String) { 23 | self.one = one 24 | self.two = two 25 | } 26 | } 27 | 28 | struct Test14b { 29 | let one: Int 30 | let two: String? 31 | 32 | init(one: Int) { 33 | self.one = one 34 | self.two = nil 35 | } 36 | } 37 | 38 | extension Test14b { 39 | init(one: Int, two: String?) { 40 | self.one = one 41 | self.two = two 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /tests/Test15_keywords.swift: -------------------------------------------------------------------------------- 1 | struct `if` { 2 | let `break`: Bool 3 | } 4 | 5 | typealias `for` = Int 6 | 7 | enum `__FILE__` : `for` { 8 | case one = 1 9 | } 10 | 11 | struct Bar<`do`> { 12 | } 13 | 14 | -------------------------------------------------------------------------------- /tests/Test16_inits.swift: -------------------------------------------------------------------------------- 1 | struct Init1 { 2 | } 3 | 4 | struct Init2 { 5 | private init() {} 6 | } 7 | 8 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "ES6", 5 | "outDir": "lib", 6 | "rootDir": "src" 7 | } 8 | } 9 | --------------------------------------------------------------------------------