@trayio/tray-schema 0.12.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.md +70 -0
  2. package/dist/schema/TJSTraySchemaTypeTransformer.d.ts +9 -0
  3. package/dist/schema/TJSTraySchemaTypeTransformer.d.ts.map +1 -0
  4. package/dist/schema/TJSTraySchemaTypeTransformer.js +135 -0
  5. package/dist/schema/TJSTraySchemaTypeTransformer.test.d.ts +2 -0
  6. package/dist/schema/TJSTraySchemaTypeTransformer.test.d.ts.map +1 -0
  7. package/dist/schema/TJSTraySchemaTypeTransformer.test.js +290 -0
  8. package/dist/schema/TraySchemaTypeTransformer.d.ts +6 -0
  9. package/dist/schema/TraySchemaTypeTransformer.d.ts.map +1 -0
  10. package/dist/schema/TraySchemaTypeTransformer.js +2 -0
  11. package/dist/schema/dataTypes.test.data.d.ts +12 -0
  12. package/dist/schema/dataTypes.test.data.d.ts.map +1 -0
  13. package/dist/schema/dataTypes.test.data.js +2 -0
  14. package/dist/schema/ddl.test.data.d.ts +8 -0
  15. package/dist/schema/ddl.test.data.d.ts.map +1 -0
  16. package/dist/schema/ddl.test.data.js +2 -0
  17. package/dist/schema/default.test.data.d.ts +28 -0
  18. package/dist/schema/default.test.data.d.ts.map +1 -0
  19. package/dist/schema/default.test.data.js +2 -0
  20. package/dist/schema/enum.test.data.d.ts +17 -0
  21. package/dist/schema/enum.test.data.d.ts.map +1 -0
  22. package/dist/schema/enum.test.data.js +8 -0
  23. package/dist/schema/format.test.data.d.ts +23 -0
  24. package/dist/schema/format.test.data.d.ts.map +1 -0
  25. package/dist/schema/format.test.data.js +2 -0
  26. package/dist/schema/importsReusable.test.data.d.ts +9 -0
  27. package/dist/schema/importsReusable.test.data.d.ts.map +1 -0
  28. package/dist/schema/importsReusable.test.data.js +2 -0
  29. package/dist/schema/oneOf.test.data.d.ts +28 -0
  30. package/dist/schema/oneOf.test.data.d.ts.map +1 -0
  31. package/dist/schema/oneOf.test.data.js +2 -0
  32. package/dist/schema/required.test.data.d.ts +5 -0
  33. package/dist/schema/required.test.data.d.ts.map +1 -0
  34. package/dist/schema/required.test.data.js +2 -0
  35. package/dist/schema/reusableField.test.data.d.ts +5 -0
  36. package/dist/schema/reusableField.test.data.d.ts.map +1 -0
  37. package/dist/schema/reusableField.test.data.js +2 -0
  38. package/dist/schema/reusableSchema.test.data.d.ts +5 -0
  39. package/dist/schema/reusableSchema.test.data.d.ts.map +1 -0
  40. package/dist/schema/reusableSchema.test.data.js +2 -0
  41. package/package.json +8 -3
package/README.md ADDED
@@ -0,0 +1,70 @@
1
+ # Tray-schema
2
+ This module contains a collection of utilities for transforming and manipulating various representations of Tray's connector schema.
3
+
4
+ # TJSTraySchemaTypeTransformer
5
+
6
+ ## Overview
7
+ This part of the module takes a CDK connectors input or output typescript type definitions, along with any JSdoc annotations, and generates JSON schema representing these types. Specifically this format is Tray schema, otherwise known as CAPI schema, but importantly it is not the old way of writing connector JSON schema, which is reffered to as the legacy connector schema.
8
+
9
+ To generate the full schema for a connector this utility will be invoked for each operation's input and output. Operation metadata is pulled from the handler (using a different util) and then all of this schema is stiched together (using yet another different util) to produce the final connectors.json in Tray schema format. Which will then be transformed into legcay connector schema (by yet another different util) to ensure the connector works with the legacy deployment process.
10
+
11
+ Have a look at the example types used for unit tests within `src/TJSTraySchemaTypeTransformer/tests/` for examples of how to do different things with typescript and JSdoc.
12
+
13
+ ## Why use NPM lib typescript-json-schema
14
+
15
+ We found only 2 suitable libraries for converting typescript types to JSON schema:
16
+ - typescript-json-schema:
17
+ - It's functionality cannot be extended
18
+ - It won't throw an exception if you ask it to generate "invalid" schema
19
+ - ts-json-schema-generator
20
+ - Is an extension of typescript-json-schema
21
+ - It's functionality can be extended
22
+ - It will throw an exception if you ask it to generate "invalid" schema. And this is the main reason we did not chose this library, because this library sees some of the extra properties Tray schema has as invalid.
23
+
24
+ ## Post processing
25
+ To get around the non extendable nature of the typescript-json-schema lib we perform a number of different post processing steps on the generated JSON schema.
26
+ ## Enums
27
+ Tray schema supports enum labels so users can have a enum value which is sent and an enum label which is just displayed in the UI. Adding support for enum lables is trivial, until you realise that typescript-json-schema sorts the enums alphabetically. There are a few different ways to handle this, all of them are not ideal.
28
+
29
+ You can force the user to specify their enum, enum labels and enum order, which is incredibley cumbersome, they would have to write the enum list 4 times (its 4 not 3 because a TS enum needs a key and value).
30
+
31
+ For now we will not allow custom enum labels, instead we try to generate they best enum label possible automatically, in addition the order of enums can't be specified. We are planning on opening a PR to the typescript-json-schema lib to add a config option to disable this sorting. This way when we have this PR merged we can enable enum labels through the @enumLabel JSdoc annotation and it will be backwards compatible for end users.
32
+
33
+ ## Lookup / DDLs
34
+ Ideally DDLs would be defined in JSdoc like this, using the dot to target the property in the resulting JSON schema (e.g. @lookup.operation). Unfortunately this doesn't work with the typescript-json-schema library. So instead we use camelCased annotation names (e.g. @lookupOperation) and then use post processing to rearrange the schema. Potentially we could also raise a PR to the lib to add this dot notation support.
35
+ ```
36
+ // ideal input
37
+ export type Input = {
38
+ /**
39
+ * @lookup.operation list_users_actual_ddl
40
+ * @lookup.input {"include_private_channels": false,"workspace_id": "{{{workspace_id}}}"}
41
+ */
42
+ emails: string;
43
+ };
44
+
45
+ // actual input
46
+ export type Input = {
47
+ /**
48
+ * @lookupOperation list_users_actual_ddl
49
+ * @lookupInput {"include_private_channels": false,"workspace_id": "{{{workspace_id}}}"}
50
+ */
51
+ emails: string;
52
+ };
53
+
54
+ // Output
55
+ emails: {
56
+ type: 'string',
57
+ lookup: {
58
+ operation: 'list_users_actual_ddl',
59
+ input: {
60
+ include_private_channels: false,
61
+ workspace_id: '{{{workspace_id}}}',
62
+ },
63
+ },
64
+ },
65
+ ```
66
+
67
+ ## Advance fields not supported yet
68
+ Some more work is required to support advanced fields, which is when a field is hidden within the Tray UI in an expandable advanced section.
69
+
70
+ Would need to add a new JSdoc annotation @advanced, this will be added to each item of the schema though when it needs to be in an array, similar to how the required fields works. So post processing would be required to strip out the individual required: true on each item and combine them into an array at the parent item level.
@@ -0,0 +1,9 @@
1
+ import * as TJS from 'typescript-json-schema';
2
+ import { Either } from 'fp-ts/Either';
3
+ import { DynamicObject } from '@trayio/tray-commons/dynamictype/DynamicType';
4
+ import { TraySchemaTypeTransformer } from './TraySchemaTypeTransformer';
5
+ export declare class TJSTraySchemaTypeTransformer implements TraySchemaTypeTransformer {
6
+ generateFromTypes(type: string, path: string): Either<Error, DynamicObject>;
7
+ jsonSchemaToTraySchema(schema: TJS.Definition): TJS.Definition;
8
+ }
9
+ //# sourceMappingURL=TJSTraySchemaTypeTransformer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TJSTraySchemaTypeTransformer.d.ts","sourceRoot":"","sources":["../../src/schema/TJSTraySchemaTypeTransformer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,GAAG,MAAM,wBAAwB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAe,MAAM,cAAc,CAAC;AAEnD,OAAO,EAAE,aAAa,EAAE,MAAM,8CAA8C,CAAC;AAC7E,OAAO,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AAExE,qBAAa,4BAA6B,YAAW,yBAAyB;IAC7E,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,KAAK,EAAE,aAAa,CAAC;IAwB3E,sBAAsB,CAAC,MAAM,EAAE,GAAG,CAAC,UAAU,GAAG,GAAG,CAAC,UAAU;CAsF9D"}
@@ -0,0 +1,135 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.TJSTraySchemaTypeTransformer = void 0;
27
+ const path_1 = require("path");
28
+ const TJS = __importStar(require("typescript-json-schema"));
29
+ const Either_1 = require("fp-ts/Either");
30
+ const lodash_1 = require("lodash");
31
+ class TJSTraySchemaTypeTransformer {
32
+ generateFromTypes(type, path) {
33
+ const settings = {
34
+ // this will prevent creating references in the schema when references are used in the types
35
+ ref: false,
36
+ // adds support for DDLs and more in the JSdoc annotations
37
+ validationKeywords: ['lookupInput', 'lookupOperation', 'enumLabels'],
38
+ // adds a required array to every entitiy in the schema which describes which children are required
39
+ required: true,
40
+ };
41
+ const compilerOptions = {
42
+ strictNullChecks: true,
43
+ };
44
+ const program = TJS.getProgramFromFiles([(0, path_1.resolve)(path)], compilerOptions);
45
+ const schema = TJS.generateSchema(program, type, settings);
46
+ if (schema !== null) {
47
+ const traySchema = this.jsonSchemaToTraySchema(schema);
48
+ return (0, Either_1.right)(traySchema);
49
+ }
50
+ return (0, Either_1.left)(new Error('Failed to generate JSON schema from type'));
51
+ }
52
+ jsonSchemaToTraySchema(schema) {
53
+ const transformLookup = (object) => {
54
+ if (object.lookupOperation && object.lookupInput) {
55
+ object.lookup = {
56
+ operation: object.lookupOperation,
57
+ input: object.lookupInput,
58
+ };
59
+ delete object.lookupOperation;
60
+ delete object.lookupInput;
61
+ }
62
+ };
63
+ const transformEnumLabels = (object) => {
64
+ if (object.enumLabels && typeof object.enumLabels === 'string') {
65
+ const enumLabelsString = object.enumLabels;
66
+ const enumLabelsArray = enumLabelsString.split(', ');
67
+ object.enumLabels = enumLabelsArray;
68
+ }
69
+ };
70
+ const generateEnumLabels = (object) => {
71
+ if (object.enum && Array.isArray(object.enum)) {
72
+ const enumLabels = [];
73
+ const enums = object.enum;
74
+ enums.forEach((enumItem) => {
75
+ if (typeof enumItem === 'string') {
76
+ enumLabels.push((0, lodash_1.startCase)((0, lodash_1.camelCase)(enumItem)));
77
+ }
78
+ else {
79
+ enumLabels.push(enumItem.toString());
80
+ }
81
+ });
82
+ object.enum = enums;
83
+ object.enumLabels = enumLabels;
84
+ }
85
+ };
86
+ const transformOneOf = (object) => {
87
+ if (object.anyOf) {
88
+ object.oneOf = object.anyOf;
89
+ delete object.anyOf;
90
+ }
91
+ };
92
+ const transformAllOf = (object) => {
93
+ if (object.allOf && Array.isArray(object.allOf)) {
94
+ object.allOf.forEach((part) => {
95
+ // eslint-disable-next-line no-restricted-syntax
96
+ for (const [key, value] of Object.entries(part)) {
97
+ if (Array.isArray(value)) {
98
+ if (!object[key]) {
99
+ object[key] = value;
100
+ }
101
+ else {
102
+ object[key] = [
103
+ ...object[key],
104
+ ...value,
105
+ ];
106
+ }
107
+ }
108
+ else if (typeof value === 'object' && value !== null) {
109
+ object[key] = Object.assign(Object.assign({}, object[key]), value);
110
+ }
111
+ else {
112
+ object[key] = value;
113
+ }
114
+ }
115
+ });
116
+ delete object.allOf;
117
+ }
118
+ };
119
+ const recursiveObjectSearch = (object) => {
120
+ transformAllOf(object);
121
+ // eslint-disable-next-line no-restricted-syntax
122
+ for (const [key, value] of Object.entries(object)) {
123
+ if (typeof value === 'object' && value !== null) {
124
+ transformLookup(value);
125
+ generateEnumLabels(value);
126
+ transformOneOf(value);
127
+ recursiveObjectSearch(value);
128
+ }
129
+ }
130
+ };
131
+ recursiveObjectSearch(schema);
132
+ return schema;
133
+ }
134
+ }
135
+ exports.TJSTraySchemaTypeTransformer = TJSTraySchemaTypeTransformer;
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=TJSTraySchemaTypeTransformer.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TJSTraySchemaTypeTransformer.test.d.ts","sourceRoot":"","sources":["../../src/schema/TJSTraySchemaTypeTransformer.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,290 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ const E = __importStar(require("fp-ts/Either"));
27
+ const path_1 = require("path");
28
+ const TJSTraySchemaTypeTransformer_1 = require("./TJSTraySchemaTypeTransformer");
29
+ describe('TJSTraySchemaTypeTransformer', () => {
30
+ it('Generates data types', () => {
31
+ const type = 'Input';
32
+ const dirPath = __dirname;
33
+ const path = (0, path_1.join)(dirPath, 'datatypes.test.data.ts');
34
+ const result = new TJSTraySchemaTypeTransformer_1.TJSTraySchemaTypeTransformer().generateFromTypes(type, path);
35
+ const actual = E.getOrElse((error) => {
36
+ console.warn(error);
37
+ throw new Error(`Failed to generate JSON schema from type`);
38
+ })(result);
39
+ const expected = {
40
+ type: 'object',
41
+ properties: {
42
+ str: { type: 'string' },
43
+ num: { type: 'number' },
44
+ int: { type: 'integer' },
45
+ bool: { type: 'boolean' },
46
+ obj: { type: 'object', properties: {}, additionalProperties: true },
47
+ arr: {
48
+ type: 'array',
49
+ items: { type: 'object', properties: {}, additionalProperties: true },
50
+ },
51
+ },
52
+ required: ['arr', 'bool', 'int', 'num', 'obj', 'str'],
53
+ $schema: 'http://json-schema.org/draft-07/schema#',
54
+ };
55
+ expect(actual).toEqual(expected);
56
+ });
57
+ it('Generates reusable parts of the schema by importing types and using typescript intersections', () => {
58
+ const type = 'Input';
59
+ const dirPath = __dirname;
60
+ const path = (0, path_1.join)(dirPath, 'importsReusable.test.data.ts');
61
+ const result = new TJSTraySchemaTypeTransformer_1.TJSTraySchemaTypeTransformer().generateFromTypes(type, path);
62
+ const actual = E.getOrElse((error) => {
63
+ console.warn(error);
64
+ throw new Error(`Failed to generate JSON schema from type`);
65
+ })(result);
66
+ const expected = {
67
+ type: 'object',
68
+ properties: {
69
+ specificField: { type: 'string' },
70
+ reusableFields: {
71
+ type: 'object',
72
+ properties: {
73
+ reusableFieldA: { type: 'number' },
74
+ reusableFieldB: { type: 'string' },
75
+ },
76
+ required: ['reusableFieldA', 'reusableFieldB'],
77
+ },
78
+ reusableSchemaA: { type: 'number' },
79
+ reusableSchemaB: { type: 'string' },
80
+ },
81
+ required: [
82
+ 'reusableFields',
83
+ 'specificField',
84
+ 'reusableSchemaA',
85
+ 'reusableSchemaB',
86
+ ],
87
+ $schema: 'http://json-schema.org/draft-07/schema#',
88
+ };
89
+ expect(actual).toEqual(expected);
90
+ });
91
+ it('Generates oneOfs and nested oneOfs from typescript union types by converting anyOfs during post processing', () => {
92
+ const type = 'Input';
93
+ const dirPath = __dirname;
94
+ const path = (0, path_1.join)(dirPath, 'oneOf.test.data.ts');
95
+ const result = new TJSTraySchemaTypeTransformer_1.TJSTraySchemaTypeTransformer().generateFromTypes(type, path);
96
+ const actual = E.getOrElse((error) => {
97
+ console.warn(error);
98
+ throw new Error(`Failed to generate JSON schema from type`);
99
+ })(result);
100
+ const expected = {
101
+ type: 'object',
102
+ properties: {
103
+ elements: {
104
+ title: 'Elements',
105
+ description: 'Add images or text to the context. Maximum number of items is 10.',
106
+ type: 'array',
107
+ items: {
108
+ oneOf: [
109
+ {
110
+ type: 'object',
111
+ properties: {
112
+ src: {
113
+ oneOf: [
114
+ {
115
+ type: 'object',
116
+ properties: {
117
+ path: { type: 'string' },
118
+ metadata: { type: 'string' },
119
+ },
120
+ required: ['metadata', 'path'],
121
+ },
122
+ {
123
+ type: 'object',
124
+ properties: { imgId: { type: 'number' } },
125
+ required: ['imgId'],
126
+ },
127
+ ],
128
+ },
129
+ },
130
+ required: ['src'],
131
+ },
132
+ {
133
+ type: 'object',
134
+ properties: {
135
+ msg: {
136
+ title: 'myText',
137
+ description: 'the text.',
138
+ type: 'string',
139
+ },
140
+ },
141
+ required: ['msg'],
142
+ },
143
+ ],
144
+ },
145
+ },
146
+ },
147
+ required: ['elements'],
148
+ $schema: 'http://json-schema.org/draft-07/schema#',
149
+ };
150
+ expect(actual).toEqual(expected);
151
+ });
152
+ it('Generates enums and enumLabels', () => {
153
+ const type = 'Input';
154
+ const dirPath = __dirname;
155
+ const path = (0, path_1.join)(dirPath, 'enum.test.data.ts');
156
+ const result = new TJSTraySchemaTypeTransformer_1.TJSTraySchemaTypeTransformer().generateFromTypes(type, path);
157
+ const actual = E.getOrElse((error) => {
158
+ console.warn(error);
159
+ throw new Error(`Failed to generate JSON schema from type`);
160
+ })(result);
161
+ const expected = {
162
+ type: 'object',
163
+ properties: {
164
+ actions: {
165
+ description: 'example dropdown',
166
+ type: 'array',
167
+ items: {
168
+ type: 'object',
169
+ properties: {
170
+ text: { type: 'string' },
171
+ type: {
172
+ enumLabels: ['Default Always', 'Primary One', 'The Danger'],
173
+ enum: ['default always', 'primary-one', 'the_danger'],
174
+ type: 'string',
175
+ },
176
+ },
177
+ required: ['text', 'type'],
178
+ },
179
+ },
180
+ },
181
+ required: ['actions'],
182
+ $schema: 'http://json-schema.org/draft-07/schema#',
183
+ };
184
+ expect(actual).toEqual(expected);
185
+ });
186
+ it('Generates DDL lookup format during post processing', () => {
187
+ const type = 'Input';
188
+ const dirPath = __dirname;
189
+ const path = (0, path_1.join)(dirPath, 'ddl.test.data.ts');
190
+ const result = new TJSTraySchemaTypeTransformer_1.TJSTraySchemaTypeTransformer().generateFromTypes(type, path);
191
+ const actual = E.getOrElse((error) => {
192
+ console.warn(error);
193
+ throw new Error(`Failed to generate JSON schema from type`);
194
+ })(result);
195
+ const expected = {
196
+ type: 'object',
197
+ properties: {
198
+ emails: {
199
+ type: 'string',
200
+ lookup: {
201
+ operation: 'list_users_actual_ddl',
202
+ input: {
203
+ include_private_channels: false,
204
+ workspace_id: '{{{workspace_id}}}',
205
+ },
206
+ },
207
+ },
208
+ },
209
+ required: ['emails'],
210
+ $schema: 'http://json-schema.org/draft-07/schema#',
211
+ };
212
+ expect(actual).toEqual(expected);
213
+ });
214
+ it('Generates required fields array based on typescripts optional (?) symbol', () => {
215
+ const type = 'Input';
216
+ const dirPath = __dirname;
217
+ const path = (0, path_1.join)(dirPath, 'required.test.data.ts');
218
+ const result = new TJSTraySchemaTypeTransformer_1.TJSTraySchemaTypeTransformer().generateFromTypes(type, path);
219
+ const actual = E.getOrElse((error) => {
220
+ console.warn(error);
221
+ throw new Error(`Failed to generate JSON schema from type`);
222
+ })(result);
223
+ const expected = {
224
+ type: 'object',
225
+ properties: {
226
+ mandatoryField: { type: 'string' },
227
+ optionalField: { type: 'string' },
228
+ },
229
+ required: ['mandatoryField'],
230
+ $schema: 'http://json-schema.org/draft-07/schema#',
231
+ };
232
+ expect(actual).toEqual(expected);
233
+ });
234
+ it('Generates format properties from JSdoc annotations', () => {
235
+ const type = 'Input';
236
+ const dirPath = __dirname;
237
+ const path = (0, path_1.join)(dirPath, 'format.test.data.ts');
238
+ const result = new TJSTraySchemaTypeTransformer_1.TJSTraySchemaTypeTransformer().generateFromTypes(type, path);
239
+ const actual = E.getOrElse((error) => {
240
+ console.warn(error);
241
+ throw new Error(`Failed to generate JSON schema from type`);
242
+ })(result);
243
+ const expected = {
244
+ type: 'object',
245
+ properties: {
246
+ timestamp: { format: 'datetime', type: 'string' },
247
+ html: { format: 'code', type: 'string' },
248
+ longNotes: { format: 'text', type: 'string' },
249
+ password: { format: 'password', type: 'string' },
250
+ file: { format: 'file', type: 'string' },
251
+ },
252
+ required: ['file', 'html', 'longNotes', 'password', 'timestamp'],
253
+ $schema: 'http://json-schema.org/draft-07/schema#',
254
+ };
255
+ expect(actual).toEqual(expected);
256
+ });
257
+ it('Generates default properties from JSdoc annotations', () => {
258
+ const type = 'Input';
259
+ const dirPath = __dirname;
260
+ const path = (0, path_1.join)(dirPath, 'default.test.data.ts');
261
+ const result = new TJSTraySchemaTypeTransformer_1.TJSTraySchemaTypeTransformer().generateFromTypes(type, path);
262
+ const actual = E.getOrElse((error) => {
263
+ console.warn(error);
264
+ throw new Error(`Failed to generate JSON schema from type`);
265
+ })(result);
266
+ const expected = {
267
+ type: 'object',
268
+ properties: {
269
+ str: { default: 'string default', type: 'string' },
270
+ num: { default: 0.1, type: 'number' },
271
+ int: { type: 'integer', default: 1 },
272
+ bool: { default: true, type: 'boolean' },
273
+ obj: {
274
+ default: { default: true },
275
+ type: 'object',
276
+ properties: {},
277
+ additionalProperties: true,
278
+ },
279
+ arr: {
280
+ default: ['default'],
281
+ type: 'array',
282
+ items: { type: 'object', properties: {}, additionalProperties: true },
283
+ },
284
+ },
285
+ required: ['arr', 'bool', 'int', 'num', 'obj', 'str'],
286
+ $schema: 'http://json-schema.org/draft-07/schema#',
287
+ };
288
+ expect(actual).toEqual(expected);
289
+ });
290
+ });
@@ -0,0 +1,6 @@
1
+ import { Either } from 'fp-ts/lib/Either';
2
+ import { DynamicObject } from '@trayio/tray-commons/dynamictype/DynamicType';
3
+ export interface TraySchemaTypeTransformer {
4
+ generateFromTypes(type: string, path: string): Either<Error, DynamicObject>;
5
+ }
6
+ //# sourceMappingURL=TraySchemaTypeTransformer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TraySchemaTypeTransformer.d.ts","sourceRoot":"","sources":["../../src/schema/TraySchemaTypeTransformer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,8CAA8C,CAAC;AAE7E,MAAM,WAAW,yBAAyB;IACzC,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC;CAC5E"}
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,12 @@
1
+ export declare type Input = {
2
+ str: string;
3
+ num: number;
4
+ /**
5
+ * @TJS-type integer
6
+ */
7
+ int: number;
8
+ bool: boolean;
9
+ obj: object;
10
+ arr: object[];
11
+ };
12
+ //# sourceMappingURL=dataTypes.test.data.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dataTypes.test.data.d.ts","sourceRoot":"","sources":["../../src/schema/dataTypes.test.data.ts"],"names":[],"mappings":"AAAA,oBAAY,KAAK,GAAG;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ;;OAEG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,OAAO,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,EAAE,CAAC;CACd,CAAC"}
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,8 @@
1
+ export declare type Input = {
2
+ /**
3
+ * @lookupOperation list_users_actual_ddl
4
+ * @lookupInput {"include_private_channels": false,"workspace_id": "{{{workspace_id}}}"}
5
+ */
6
+ emails: string;
7
+ };
8
+ //# sourceMappingURL=ddl.test.data.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ddl.test.data.d.ts","sourceRoot":"","sources":["../../src/schema/ddl.test.data.ts"],"names":[],"mappings":"AAAA,oBAAY,KAAK,GAAG;IACnB;;;OAGG;IACH,MAAM,EAAE,MAAM,CAAC;CACf,CAAC"}
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,28 @@
1
+ export declare type Input = {
2
+ /**
3
+ * @default string default
4
+ */
5
+ str: string;
6
+ /**
7
+ * @default 0.1
8
+ */
9
+ num: number;
10
+ /**
11
+ * @TJS-type integer
12
+ * @default 1
13
+ */
14
+ int: number;
15
+ /**
16
+ * @default true
17
+ */
18
+ bool: boolean;
19
+ /**
20
+ * @default { "default": true }
21
+ */
22
+ obj: object;
23
+ /**
24
+ * @default ["default"]
25
+ */
26
+ arr: object[];
27
+ };
28
+ //# sourceMappingURL=default.test.data.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"default.test.data.d.ts","sourceRoot":"","sources":["../../src/schema/default.test.data.ts"],"names":[],"mappings":"AAAA,oBAAY,KAAK,GAAG;IACnB;;OAEG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ;;OAEG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ;;;OAGG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ;;OAEG;IACH,IAAI,EAAE,OAAO,CAAC;IACd;;OAEG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ;;OAEG;IACH,GAAG,EAAE,MAAM,EAAE,CAAC;CACd,CAAC"}
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,17 @@
1
+ export declare type Input = {
2
+ /**
3
+ * @description example dropdown
4
+ */
5
+ actions: Action[];
6
+ };
7
+ declare type Action = {
8
+ text: string;
9
+ type: ActionType;
10
+ };
11
+ declare enum ActionType {
12
+ default = "default always",
13
+ danger = "the_danger",
14
+ primary = "primary-one"
15
+ }
16
+ export {};
17
+ //# sourceMappingURL=enum.test.data.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enum.test.data.d.ts","sourceRoot":"","sources":["../../src/schema/enum.test.data.ts"],"names":[],"mappings":"AAAA,oBAAY,KAAK,GAAG;IACnB;;OAEG;IACH,OAAO,EAAE,MAAM,EAAE,CAAC;CAClB,CAAC;AAEF,aAAK,MAAM,GAAG;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,UAAU,CAAC;CACjB,CAAC;AAEF,aAAK,UAAU;IACd,OAAO,mBAAmB;IAC1B,MAAM,eAAe;IACrB,OAAO,gBAAgB;CACvB"}
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ var ActionType;
4
+ (function (ActionType) {
5
+ ActionType["default"] = "default always";
6
+ ActionType["danger"] = "the_danger";
7
+ ActionType["primary"] = "primary-one";
8
+ })(ActionType || (ActionType = {}));
@@ -0,0 +1,23 @@
1
+ export declare type Input = {
2
+ /**
3
+ * @format datetime
4
+ */
5
+ timestamp: string;
6
+ /**
7
+ * @format code
8
+ */
9
+ html: string;
10
+ /**
11
+ * @format text
12
+ */
13
+ longNotes: string;
14
+ /**
15
+ * @format password
16
+ */
17
+ password: string;
18
+ /**
19
+ * @format file
20
+ */
21
+ file: string;
22
+ };
23
+ //# sourceMappingURL=format.test.data.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.test.data.d.ts","sourceRoot":"","sources":["../../src/schema/format.test.data.ts"],"names":[],"mappings":"AAAA,oBAAY,KAAK,GAAG;IACnB;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;CACb,CAAC"}
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,9 @@
1
+ import { ReusableField } from './reusableField.test.data';
2
+ import { ReusableSchema } from './reusableSchema.test.data';
3
+ export declare type Input = SpecificSchema & ReusableSchema;
4
+ declare type SpecificSchema = {
5
+ specificField: string;
6
+ reusableFields: ReusableField;
7
+ };
8
+ export {};
9
+ //# sourceMappingURL=importsReusable.test.data.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"importsReusable.test.data.d.ts","sourceRoot":"","sources":["../../src/schema/importsReusable.test.data.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAE5D,oBAAY,KAAK,GAAG,cAAc,GAAG,cAAc,CAAC;AAEpD,aAAK,cAAc,GAAG;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,aAAa,CAAC;CAC9B,CAAC"}
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,28 @@
1
+ declare type Src = {
2
+ path: string;
3
+ metadata: string;
4
+ };
5
+ declare type Id = {
6
+ imgId: number;
7
+ };
8
+ declare type SrcOrId = Src | Id;
9
+ declare type Image = {
10
+ src: SrcOrId;
11
+ };
12
+ declare type Text = {
13
+ /**
14
+ * @title myText
15
+ * @description the text.
16
+ */
17
+ msg: string;
18
+ };
19
+ declare type ImageOrText = Image | Text;
20
+ export declare type Input = {
21
+ /**
22
+ * @title Elements
23
+ * @description Add images or text to the context. Maximum number of items is 10.
24
+ */
25
+ elements: ImageOrText[];
26
+ };
27
+ export {};
28
+ //# sourceMappingURL=oneOf.test.data.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oneOf.test.data.d.ts","sourceRoot":"","sources":["../../src/schema/oneOf.test.data.ts"],"names":[],"mappings":"AAAA,aAAK,GAAG,GAAG;IACV,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,aAAK,EAAE,GAAG;IACT,KAAK,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,aAAK,OAAO,GAAG,GAAG,GAAG,EAAE,CAAC;AAExB,aAAK,KAAK,GAAG;IACZ,GAAG,EAAE,OAAO,CAAC;CACb,CAAC;AAEF,aAAK,IAAI,GAAG;IACX;;;OAGG;IACH,GAAG,EAAE,MAAM,CAAC;CACZ,CAAC;AAEF,aAAK,WAAW,GAAG,KAAK,GAAG,IAAI,CAAC;AAEhC,oBAAY,KAAK,GAAG;IACnB;;;OAGG;IACH,QAAQ,EAAE,WAAW,EAAE,CAAC;CACxB,CAAC"}
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,5 @@
1
+ export declare type Input = {
2
+ mandatoryField: string;
3
+ optionalField?: string;
4
+ };
5
+ //# sourceMappingURL=required.test.data.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"required.test.data.d.ts","sourceRoot":"","sources":["../../src/schema/required.test.data.ts"],"names":[],"mappings":"AAAA,oBAAY,KAAK,GAAG;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC"}
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,5 @@
1
+ export declare type ReusableField = {
2
+ reusableFieldA: number;
3
+ reusableFieldB: string;
4
+ };
5
+ //# sourceMappingURL=reusableField.test.data.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reusableField.test.data.d.ts","sourceRoot":"","sources":["../../src/schema/reusableField.test.data.ts"],"names":[],"mappings":"AAAA,oBAAY,aAAa,GAAG;IAC3B,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;CACvB,CAAC"}
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,5 @@
1
+ export declare type ReusableSchema = {
2
+ reusableSchemaA: number;
3
+ reusableSchemaB: string;
4
+ };
5
+ //# sourceMappingURL=reusableSchema.test.data.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reusableSchema.test.data.d.ts","sourceRoot":"","sources":["../../src/schema/reusableSchema.test.data.ts"],"names":[],"mappings":"AAAA,oBAAY,cAAc,GAAG;IAC5B,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;CACxB,CAAC"}
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trayio/tray-schema",
3
- "version": "0.12.0",
3
+ "version": "0.14.0",
4
4
  "description": "Vanilla typescript code with extensions to the language or basic features",
5
5
  "exports": {
6
6
  "./*": "./dist/*.js"
@@ -8,8 +8,13 @@
8
8
  "author": "Tray.io",
9
9
  "license": "Proprietary",
10
10
  "dependencies": {
11
- "@trayio/tray-commons": "0.12.0",
12
- "@types/node": "*"
11
+ "@trayio/tray-commons": "0.14.0",
12
+ "@types/node": "*",
13
+ "lodash": "*",
14
+ "typescript-json-schema": "*"
15
+ },
16
+ "resolutions": {
17
+ "typescript-json-schema": "*"
13
18
  },
14
19
  "typesVersions": {
15
20
  "*": {