├── .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 |
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 |
--------------------------------------------------------------------------------