zapier-platform-core 17.7.1 → 17.7.2

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zapier-platform-core",
3
- "version": "17.7.1",
3
+ "version": "17.7.2",
4
4
  "description": "The core SDK for CLI apps in the Zapier Developer Platform.",
5
5
  "repository": "zapier/zapier-platform",
6
6
  "homepage": "https://platform.zapier.com/",
@@ -63,7 +63,7 @@
63
63
  "node-fetch": "2.7.0",
64
64
  "oauth-sign": "0.9.0",
65
65
  "semver": "7.7.1",
66
- "zapier-platform-schema": "17.7.1"
66
+ "zapier-platform-schema": "17.7.2"
67
67
  },
68
68
  "devDependencies": {
69
69
  "@types/node-fetch": "^2.6.11",
package/types/custom.d.ts CHANGED
@@ -112,6 +112,14 @@ export interface Bundle<
112
112
  };
113
113
  };
114
114
 
115
+ /**
116
+ * A token, such as a pagination cursor, that means this run should
117
+ * continue pulling results. Currently only used for search
118
+ * pagination. Set by previous invocations by returning `{results:
119
+ * […], paging_token: '…'}`
120
+ */
121
+ paging_token?: string;
122
+
115
123
  /**
116
124
  * Contains metadata about the input fields, optionally provided
117
125
  * by the inputField.meta property. Useful for storing extra data
@@ -142,7 +150,11 @@ export interface Bundle<
142
150
 
143
151
  // Error class types that match the runtime structure from src/errors.js
144
152
  type ErrorConstructor = new (message?: string) => Error;
145
- type AppErrorConstructor = new (message: string, code?: string, status?: number) => Error;
153
+ type AppErrorConstructor = new (
154
+ message: string,
155
+ code?: string,
156
+ status?: number,
157
+ ) => Error;
146
158
  type ThrottledErrorConstructor = new (message: string, delay?: number) => Error;
147
159
  type ResponseErrorConstructor = new (response: HttpResponse) => Error;
148
160
 
@@ -163,7 +175,6 @@ interface ErrorsModule {
163
175
  handleError: (...args: any[]) => never;
164
176
  }
165
177
 
166
-
167
178
  // copied http stuff from external typings
168
179
  export interface HttpRequestOptions {
169
180
  agent?: Agent;
@@ -1,7 +1,20 @@
1
1
  import type { Bundle, ZObject } from './custom';
2
+ import type { InferInputData, InputField } from './inputs';
2
3
 
3
4
  type DefaultInputData = Record<string, unknown>;
4
5
 
6
+ /**
7
+ * Automatically infer the type of the bundle based on if a raw
8
+ * inputData object shape is given, or an array of input fields that
9
+ * should be automatically inferred into an inputData object.
10
+ */
11
+ type AutoBundle<$InputDataOrFields extends DefaultInputData | InputField[]> =
12
+ $InputDataOrFields extends InputField[]
13
+ ? Bundle<InferInputData<$InputDataOrFields>>
14
+ : $InputDataOrFields extends DefaultInputData
15
+ ? Bundle<$InputDataOrFields>
16
+ : never;
17
+
5
18
  /**
6
19
  * Wraps a `perform` function that is used to poll for data from an API.
7
20
  * By default must return an array of objects with an `id` field, but
@@ -10,9 +23,12 @@ type DefaultInputData = Record<string, unknown>;
10
23
  * those keys.
11
24
  */
12
25
  export type PollingTriggerPerform<
13
- $InputData extends DefaultInputData = DefaultInputData,
26
+ $InputDataOrFields extends DefaultInputData | InputField[] = DefaultInputData,
14
27
  $Return extends {} = { id: string },
15
- > = (z: ZObject, bundle: Bundle<$InputData>) => $Return[] | Promise<$Return[]>;
28
+ > = (
29
+ z: ZObject,
30
+ bundle: AutoBundle<$InputDataOrFields>,
31
+ ) => $Return[] | Promise<$Return[]>;
16
32
 
17
33
  /**
18
34
  * Process the data of a webhook sent to Zapier.
@@ -21,62 +37,83 @@ export type PollingTriggerPerform<
21
37
  * in `bundle.cleanedRequest` (and `bundle.rawRequest`).
22
38
  */
23
39
  export type WebhookTriggerPerform<
24
- $InputData extends DefaultInputData = DefaultInputData,
40
+ $InputDataOrFields extends DefaultInputData | InputField[] = DefaultInputData,
25
41
  $Return extends {} = {},
26
- > = (z: ZObject, bundle: Bundle<$InputData>) => $Return[] | Promise<$Return[]>;
42
+ > = (
43
+ z: ZObject,
44
+ bundle: AutoBundle<$InputDataOrFields>,
45
+ ) => $Return[] | Promise<$Return[]>;
27
46
 
28
47
  /**
29
48
  * Pull sample data from the webhook trigger. Try to make these resemble
30
49
  * to data of the hooks as closely as possible.
31
50
  */
32
51
  export type WebhookTriggerPerformList<
33
- $InputData extends DefaultInputData = DefaultInputData,
52
+ $InputDataOrFields extends DefaultInputData | InputField[] = DefaultInputData,
34
53
  $Return extends {} = {},
35
- > = (z: ZObject, bundle: Bundle<$InputData>) => $Return[] | Promise<$Return[]>;
54
+ > = (
55
+ z: ZObject,
56
+ bundle: AutoBundle<$InputDataOrFields>,
57
+ ) => $Return[] | Promise<$Return[]>;
36
58
 
37
59
  /**
38
60
  * Return must be an object of subscription data. It will be passed as
39
61
  * `bundle.subscribeData` in the performUnsubscribe function.
40
62
  */
41
63
  export type WebhookTriggerPerformSubscribe<
42
- $InputData extends DefaultInputData = DefaultInputData,
64
+ $InputDataOrFields extends DefaultInputData | InputField[] = DefaultInputData,
43
65
  $Return extends {} = {},
44
- > = (z: ZObject, bundle: Bundle<$InputData>) => $Return | Promise<$Return>;
66
+ > = (
67
+ z: ZObject,
68
+ bundle: AutoBundle<$InputDataOrFields>,
69
+ ) => $Return | Promise<$Return>;
45
70
 
46
71
  /**
47
72
  * Unsubscribe from the webhook.
48
73
  * Data from the subscribe function is provided in `bundle.subscribeData`.
49
74
  */
50
75
  export type WebhookTriggerPerformUnsubscribe<
51
- $InputData extends DefaultInputData = DefaultInputData,
76
+ $InputDataOrFields extends DefaultInputData | InputField[] = DefaultInputData,
52
77
  $Return extends {} = {},
53
- > = (z: ZObject, bundle: Bundle<$InputData>) => $Return | Promise<$Return>;
78
+ > = (
79
+ z: ZObject,
80
+ bundle: AutoBundle<$InputDataOrFields>,
81
+ ) => $Return | Promise<$Return>;
54
82
 
55
83
  /**
56
84
  * Pull data from the API service, same as a polling trigger.
57
85
  */
58
86
  export type HookToPollTriggerPerformList<
59
- $InputData extends DefaultInputData = DefaultInputData,
87
+ $InputDataOrFields extends DefaultInputData | InputField[] = DefaultInputData,
60
88
  $Return extends {} = {},
61
- > = (z: ZObject, bundle: Bundle<$InputData>) => $Return[] | Promise<$Return[]>;
89
+ > = (
90
+ z: ZObject,
91
+ bundle: AutoBundle<$InputDataOrFields>,
92
+ ) => $Return[] | Promise<$Return[]>;
62
93
 
63
94
  /**
64
95
  * Return must be an object of subscription data. It will be passed as
65
96
  * `bundle.subscribeData` in the performUnsubscribe function.
66
97
  */
67
98
  export type HookToPollTriggerPerformSubscribe<
68
- $InputData extends DefaultInputData = DefaultInputData,
99
+ $InputDataOrFields extends DefaultInputData | InputField[] = DefaultInputData,
69
100
  $Return extends {} = {},
70
- > = (z: ZObject, bundle: Bundle<$InputData>) => $Return | Promise<$Return>;
101
+ > = (
102
+ z: ZObject,
103
+ bundle: AutoBundle<$InputDataOrFields>,
104
+ ) => $Return | Promise<$Return>;
71
105
 
72
106
  /**
73
107
  * Unsubscribe from the HookToPoll.
74
108
  * Data from the subscribe function is provided in `bundle.subscribeData`.
75
109
  */
76
110
  export type HookToPollTriggerPerformUnsubscribe<
77
- $InputData extends DefaultInputData = DefaultInputData,
111
+ $InputDataOrFields extends DefaultInputData | InputField[] = DefaultInputData,
78
112
  $Return extends {} = {},
79
- > = (z: ZObject, bundle: Bundle<$InputData>) => $Return | Promise<$Return>;
113
+ > = (
114
+ z: ZObject,
115
+ bundle: AutoBundle<$InputDataOrFields>,
116
+ ) => $Return | Promise<$Return>;
80
117
 
81
118
  /**
82
119
  * Create an item on a partner API.
@@ -85,9 +122,12 @@ export type HookToPollTriggerPerformUnsubscribe<
85
122
  * to populate more data.
86
123
  */
87
124
  export type CreatePerform<
88
- $InputData extends DefaultInputData = DefaultInputData,
125
+ $InputDataOrFields extends DefaultInputData | InputField[] = DefaultInputData,
89
126
  $Return extends {} = {},
90
- > = (z: ZObject, bundle: Bundle<$InputData>) => $Return | Promise<$Return>;
127
+ > = (
128
+ z: ZObject,
129
+ bundle: AutoBundle<$InputDataOrFields>,
130
+ ) => $Return | Promise<$Return>;
91
131
 
92
132
  /**
93
133
  * A `perform` function can setup a partner API to call back to this
@@ -104,18 +144,24 @@ export type CreatePerform<
104
144
  * - bundle.outputData: The output data from the original `perform`.
105
145
  */
106
146
  export type CreatePerformResume<
107
- $InputData extends DefaultInputData = DefaultInputData,
147
+ $InputDataOrFields extends DefaultInputData | InputField[] = DefaultInputData,
108
148
  // TODO: Type cleanedRequest & outputData on Bundle interface
109
149
  $Return extends {} = {},
110
- > = (z: ZObject, bundle: Bundle<$InputData>) => $Return | Promise<$Return>;
150
+ > = (
151
+ z: ZObject,
152
+ bundle: AutoBundle<$InputDataOrFields>,
153
+ ) => $Return | Promise<$Return>;
111
154
 
112
155
  /**
113
156
  * Look up an object to populate it after creation?
114
157
  */
115
158
  export type CreatePerformGet<
116
- $InputData extends DefaultInputData = DefaultInputData,
159
+ $InputDataOrFields extends DefaultInputData | InputField[] = DefaultInputData,
117
160
  $Return extends {} = {},
118
- > = (z: ZObject, bundle: Bundle<$InputData>) => $Return | Promise<$Return>;
161
+ > = (
162
+ z: ZObject,
163
+ bundle: AutoBundle<$InputDataOrFields>,
164
+ ) => $Return | Promise<$Return>;
119
165
 
120
166
  /**
121
167
  * Helper type for search results that can optionally include pagination.
@@ -125,7 +171,7 @@ export type CreatePerformGet<
125
171
  *
126
172
  * When `canPaginate` is true for the search, the object shape is required.
127
173
  */
128
- type SearchResult<T> = T[] | { results: T[], paging_token: string };
174
+ type SearchResult<T> = T[] | { results: T[]; paging_token: string };
129
175
 
130
176
  /**
131
177
  * Search for objects on a partner API.
@@ -136,9 +182,12 @@ type SearchResult<T> = T[] | { results: T[], paging_token: string };
136
182
  * revisit this?
137
183
  */
138
184
  export type SearchPerform<
139
- $InputData extends DefaultInputData = DefaultInputData,
185
+ $InputDataOrFields extends DefaultInputData | InputField[] = DefaultInputData,
140
186
  $Return extends {} = {},
141
- > = (z: ZObject, bundle: Bundle<$InputData>) => SearchResult<$Return> | Promise<SearchResult<$Return>>;
187
+ > = (
188
+ z: ZObject,
189
+ bundle: AutoBundle<$InputDataOrFields>,
190
+ ) => SearchResult<$Return> | Promise<SearchResult<$Return>>;
142
191
 
143
192
  /**
144
193
  * Follow up a search's perform with additional data.
@@ -148,17 +197,23 @@ export type SearchPerform<
148
197
  * -> PROBABLY: Just the result of searchPerform, no inputFields.
149
198
  */
150
199
  export type SearchPerformGet<
151
- $InputData extends DefaultInputData = DefaultInputData,
200
+ $InputDataOrFields extends DefaultInputData | InputField[] = DefaultInputData,
152
201
  $Return extends {} = {},
153
- > = (z: ZObject, bundle: Bundle<$InputData>) => $Return | Promise<$Return>;
202
+ > = (
203
+ z: ZObject,
204
+ bundle: AutoBundle<$InputDataOrFields>,
205
+ ) => $Return | Promise<$Return>;
154
206
 
155
207
  /**
156
208
  *
157
209
  */
158
210
  export type SearchPerformResume<
159
- $InputData extends DefaultInputData = DefaultInputData,
211
+ $InputDataOrFields extends DefaultInputData | InputField[] = DefaultInputData,
160
212
  $Return extends {} = {},
161
- > = (z: ZObject, bundle: Bundle<$InputData>) => $Return | Promise<$Return>;
213
+ > = (
214
+ z: ZObject,
215
+ bundle: AutoBundle<$InputDataOrFields>,
216
+ ) => $Return | Promise<$Return>;
162
217
 
163
218
  /**
164
219
  * Produce the URL to send the user to authorise with the OAuth2 provider.
@@ -1,5 +1,8 @@
1
- import { expectAssignable } from 'tsd';
1
+ import { expectAssignable, expectType } from 'tsd';
2
2
  import type { PollingTriggerPerform } from './functions';
3
+ import { Bundle, ZObject } from './custom';
4
+ import { InferInputData } from './inputs';
5
+ import { defineInputFields } from './typeHelpers';
3
6
 
4
7
  const simplePerform = (async (z, bundle) => {
5
8
  return [{ id: '1', name: 'test' }];
@@ -16,3 +19,46 @@ const primaryKeyOverridePerform = (async (z, bundle) => {
16
19
  expectAssignable<PollingTriggerPerform<{}, { itemId: number; name: string }>>(
17
20
  primaryKeyOverridePerform,
18
21
  );
22
+
23
+ //
24
+ // Automatic inputData inference
25
+ //
26
+ // Pass shape directly
27
+ const simplePerformWithInputFields = (async (z, bundle) => {
28
+ return [{ id: '1', name: 'test' }];
29
+ }) satisfies PollingTriggerPerform<{ key: 'string' }>;
30
+ expectType<
31
+ (
32
+ z: ZObject,
33
+ bundle: Bundle<{ key: 'string' }>,
34
+ ) => Promise<{ id: string; name: string }[]>
35
+ >(simplePerformWithInputFields);
36
+
37
+ // Use InputFields and manually infer inputData
38
+ const inputFields = defineInputFields([
39
+ { key: 'key1', type: 'string', required: true },
40
+ { key: 'key2', type: 'number', required: false },
41
+ ]);
42
+ const simplePerformWithInputFieldsAndManualInference = (async (z, bundle) => {
43
+ return [{ id: '1', name: 'test' }];
44
+ }) satisfies PollingTriggerPerform<InferInputData<typeof inputFields>>;
45
+ expectType<
46
+ (
47
+ z: ZObject,
48
+ bundle: Bundle<{ key1: string; key2?: number | undefined }>,
49
+ ) => Promise<{ id: string; name: string }[]>
50
+ >(simplePerformWithInputFieldsAndManualInference);
51
+
52
+ // Use inputFields and automatically infer inputData
53
+ const simplePerformWithInputFieldsAndAutomaticInference = (async (
54
+ z,
55
+ bundle,
56
+ ) => {
57
+ return [{ id: '1', name: 'test' }];
58
+ }) satisfies PollingTriggerPerform<typeof inputFields>;
59
+ expectType<
60
+ (
61
+ z: ZObject,
62
+ bundle: Bundle<{ key1: string; key2?: number | undefined }>,
63
+ ) => Promise<{ id: string; name: string }[]>
64
+ >(simplePerformWithInputFieldsAndAutomaticInference);
package/types/inputs.d.ts CHANGED
@@ -1,4 +1,7 @@
1
- import type { PlainInputField } from './schemas.generated';
1
+ import type {
2
+ FieldChoiceWithLabel,
3
+ PlainInputField,
4
+ } from './schemas.generated';
2
5
  import type { ZObject, Bundle } from './custom';
3
6
 
4
7
  // #region UTILITIES
@@ -132,9 +135,24 @@ type FieldResultTypes = {
132
135
 
133
136
  /**
134
137
  * Get the TypeScript type that corresponds to the zapier field type. If
135
- * `type` is not set, the field defaults to `string`.
138
+ * `type` is not set, the field defaults to `string`. Does not pay
139
+ * attention to `list` `, `dict`, or `required` statuses. Does not work
140
+ * for fields with `children` subfields either.
141
+ *
142
+ * @example
143
+ * type result = PrimitiveFieldResultType<{ }>;
144
+ * // string (string is default when `type` is not set)
145
+ *
146
+ * type result = PrimitiveFieldResultType<{ type: 'string' }>;
147
+ * // string
148
+ *
149
+ * type result = PrimitiveFieldResultType<{ type: 'number' }>;
150
+ * // number
151
+ *
152
+ * type result = PrimitiveFieldResultType<{ type: 'boolean' }>;
153
+ * // boolean
136
154
  */
137
- type FieldResultType<F extends PlainInputField> = F extends {
155
+ type PrimitiveFieldResultType<$Field extends PlainInputField> = $Field extends {
138
156
  type: infer $T extends PlainInputField['type'];
139
157
  }
140
158
  ? $T extends string
@@ -142,6 +160,29 @@ type FieldResultType<F extends PlainInputField> = F extends {
142
160
  : string
143
161
  : string;
144
162
 
163
+ /**
164
+ * Capture a union of string literals while also allowing the string
165
+ * type. This allows the available choices to show in autocomplete,
166
+ * while also allowing arbitrary strings to still be valid.
167
+ *
168
+ * @example
169
+ * type result = StringHints<'a' | 'b'>;
170
+ * const A: result = 'a'; // Ok and autocomplete shows 'a' and 'b'.
171
+ * const C: result = 'c'; // Any string still ok.
172
+ */
173
+ export type StringHints<S> = S | (string & {});
174
+
175
+ type PrimitiveFieldResultTypesWithChoiceHints<$Field extends PlainInputField> =
176
+ $Field extends { choices: infer $Choices }
177
+ ? $Choices extends Record<string, string>
178
+ ? StringHints<keyof $Choices>
179
+ : $Choices extends FieldChoiceWithLabel[]
180
+ ? StringHints<$Choices[number]['value']>
181
+ : $Choices extends string[]
182
+ ? StringHints<$Choices[number]>
183
+ : PrimitiveFieldResultType<$Field>
184
+ : PrimitiveFieldResultType<$Field>;
185
+
145
186
  /**
146
187
  * A function that returns a list of plain fields, sync or async.
147
188
  * Can be used as a member of an array of input fields itself.
@@ -179,15 +220,93 @@ export type InputFields = InputField[];
179
220
  * type result3 = PlainFieldContribution<{ key: "c"; type: "boolean" }>;
180
221
  * // { c?: boolean | undefined }
181
222
  */
182
- type PlainFieldContribution<$Field extends PlainInputField> = $Field extends {
183
- required: true;
184
- }
185
- ? FieldResultType<$Field> extends never
186
- ? {}
187
- : Record<$Field['key'], FieldResultType<$Field>>
188
- : FieldResultType<$Field> extends never
223
+ export type PlainFieldContribution<$Field extends PlainInputField> =
224
+ $Field extends { children: PlainInputField[] }
225
+ ? ParentFieldContribution<$Field>
226
+ : $Field extends { dict: true }
227
+ ? DictFieldContribution<$Field>
228
+ : $Field extends { list: true }
229
+ ? ListFieldContribution<$Field>
230
+ : PrimitiveFieldContribution<$Field>;
231
+
232
+ /**
233
+ * Extract the contribution of a parent field to the input data. A parent
234
+ * Field has a `children` field array. The parent's own `key` will be
235
+ * ignored, and the children's contributions will be merged into the top
236
+ * level inputData object.
237
+ *
238
+ * @example
239
+ * type result = ParentFieldContribution<{ key: "a"; children: [{ key: "b"; required: true }] }>;
240
+ * // { b: string }
241
+ */
242
+ type ParentFieldContribution<
243
+ $Field extends PlainInputField & { children: PlainInputField[] },
244
+ > = PlainFieldArrayContribution<$Field['children']>;
245
+
246
+ /**
247
+ * Extract the contribution of a dictionary field to the input data. A
248
+ * dictionary field has a `dict:true` field. The type for this `key`
249
+ * field in the inputData object will therefore be a record of the key.
250
+ * Currently, the value type is always `string`, but this may change in
251
+ * the future.
252
+ *
253
+ * @see https://zapier.atlassian.net/browse/PDE-6547 for when non-string
254
+ * values will be supported.
255
+ *
256
+ * @example
257
+ * type result = DictFieldContribution<{ key: "a"; dict: true, required: true }>;
258
+ * // { a: Record<string, string> }
259
+ */
260
+ type DictFieldContribution<$Field extends PlainInputField & { dict: true }> =
261
+ $Field extends { required: true }
262
+ ? Record<$Field['key'], Record<string, string>>
263
+ : Partial<Record<$Field['key'], Record<string, string>>>;
264
+
265
+ /**
266
+ * Extract the contribution of a list field to the input data. A list
267
+ * field has a `list:true` field. The type for this `key` field in the
268
+ * inputData object will therefore be an array of the value type.
269
+ *
270
+ * @example
271
+ * type result1 = ListFieldContribution<{ key: "a"; list: true, required: true }>;
272
+ * // { a: string[] }
273
+ *
274
+ * type result2 = ListFieldContribution<{ key: "a"; list: true; type: "integer" }>;
275
+ * // { a?: number[] | undefined }
276
+ */
277
+ type ListFieldContribution<$Field extends PlainInputField & { list: true }> =
278
+ $Field extends { required: true }
279
+ ? Record<$Field['key'], PrimitiveFieldResultTypesWithChoiceHints<$Field>[]>
280
+ : Partial<
281
+ Record<
282
+ $Field['key'],
283
+ PrimitiveFieldResultTypesWithChoiceHints<$Field>[]
284
+ >
285
+ >;
286
+
287
+ /**
288
+ * Extract the contribution of a primitive field to the input data. A
289
+ * primitive field is a PlainInputField that is not a parent, dict, or
290
+ * list field. The `type` field MAY be set, but will default to `string`.
291
+ *
292
+ * @example
293
+ * type result1 = PrimitiveFieldContribution<{ key: "a" }>;
294
+ * // { a?: string | undefined }
295
+ *
296
+ * type result2 = PrimitiveFieldContribution<{ key: "a"; type: "integer", required: true }>;
297
+ * // { a: number }
298
+ */
299
+ type PrimitiveFieldContribution<$Field extends PlainInputField> =
300
+ PrimitiveFieldResultTypesWithChoiceHints<$Field> extends never
189
301
  ? {}
190
- : Partial<Record<$Field['key'], FieldResultType<$Field>>>;
302
+ : $Field extends { required: true }
303
+ ? Record<$Field['key'], PrimitiveFieldResultTypesWithChoiceHints<$Field>>
304
+ : Partial<
305
+ Record<
306
+ $Field['key'],
307
+ PrimitiveFieldResultTypesWithChoiceHints<$Field>
308
+ >
309
+ >;
191
310
 
192
311
  /**
193
312
  * Extract the contribution of multiple plain fields defined in an
@@ -297,6 +416,18 @@ type FieldFunctionContribution<$F> = $F extends (
297
416
  // the fields that a plain field or field function will contribute to
298
417
  // the bundle, but the more straightforward term "InputData" is
299
418
  // exposed to for the public API.
419
+ //
420
+ // TERMINOLOGY
421
+ // -----------
422
+ // InputField: A PlainInputField or a FieldFunction.
423
+ // FieldFunction: A function that returns an array of InputFields.
424
+ // KnownFieldFunction: A FieldFunction that returns explicitly named InputFields.
425
+ // UnknownFieldFunction: A FieldFunction that returns an array of InputFields that are not explicitly named.
426
+ // PlainInputField: From the schema. Object with a key, and possibly `children`, `dict`, `list`, `type`, `required`, fields.
427
+ // ParentInputField: A PlainInputField with a `children` field array.
428
+ // DictInputField: A PlainInputField with a `dict:true` field.
429
+ // ListInputField: A PlainInputField with a `list:true` field.
430
+ // PrimitiveInputField: A PlainInputField with a `type` field that is not a parent, dict, or list field.
300
431
 
301
432
  /**
302
433
  * Get the bundle contribution of a single field. This is either a plain
@@ -0,0 +1,484 @@
1
+ import { expectAssignable, expectType } from 'tsd';
2
+
3
+ import type { PlainFieldContribution } from './inputs';
4
+
5
+ //
6
+ // Parent fields (where `children` is set)
7
+ //
8
+
9
+ // Simplest `children: [{...}]` case.
10
+ const singleRequiredChild = {
11
+ string_required: 'some_string',
12
+ };
13
+ type singleRequiredChildren = PlainFieldContribution<{
14
+ key: 'parent_input';
15
+ children: [{ key: 'string_required'; type: 'string'; required: true }];
16
+ }>;
17
+ expectType<singleRequiredChildren>(singleRequiredChild);
18
+
19
+ // Complete `children: [{...}]` case.
20
+ const multipleRequiredChild = {
21
+ string_required: 'some_string',
22
+ number_required: 1,
23
+ boolean_required: true,
24
+ datetime_required: '2021-01-01T00:00:00Z',
25
+ file_required: 'some_file',
26
+ password_required: 'some_password',
27
+ code_required: 'some_code',
28
+ };
29
+ type multipleRequiredChildren = PlainFieldContribution<{
30
+ key: 'parent_input';
31
+ children: [
32
+ { key: 'string_required'; type: 'string'; required: true },
33
+ { key: 'number_required'; type: 'number'; required: true },
34
+ { key: 'boolean_required'; type: 'boolean'; required: true },
35
+ { key: 'datetime_required'; type: 'datetime'; required: true },
36
+ { key: 'file_required'; type: 'file'; required: true },
37
+ { key: 'password_required'; type: 'password'; required: true },
38
+ { key: 'code_required'; type: 'code'; required: true },
39
+ ];
40
+ }>;
41
+ expectType<multipleRequiredChildren>(multipleRequiredChild);
42
+
43
+ // Complete `children: [{...}]` case where all children are optional.
44
+ const multipleOptionalChild = {
45
+ string_optional: 'some_string',
46
+ number_optional: 1,
47
+ boolean_optional: true,
48
+ datetime_optional: '2021-01-01T00:00:00Z',
49
+ file_optional: 'some_file',
50
+ password_optional: 'some_password',
51
+ code_optional: 'some_code',
52
+ };
53
+ type multipleOptionalChildren = PlainFieldContribution<{
54
+ key: 'parent_input';
55
+ children: [
56
+ { key: 'string_optional'; type: 'string'; required: false },
57
+ { key: 'number_optional'; type: 'number'; required: false },
58
+ { key: 'boolean_optional'; type: 'boolean'; required: false },
59
+ { key: 'datetime_optional'; type: 'datetime'; required: false },
60
+ { key: 'file_optional'; type: 'file'; required: false },
61
+ { key: 'password_optional'; type: 'password'; required: false },
62
+ { key: 'code_optional'; type: 'code'; required: false },
63
+ ];
64
+ }>;
65
+ expectAssignable<multipleOptionalChildren>(multipleOptionalChild);
66
+ expectAssignable<multipleOptionalChildren>({});
67
+
68
+ // Complete `children: [{...}]` case with complete mixture of required
69
+ // and optional fields.
70
+ const mixedOptionalChildren = {
71
+ string_required: 'some_string',
72
+ string_optional: 'some_string',
73
+ number_required: 1,
74
+ number_optional: 1,
75
+ boolean_required: true,
76
+ boolean_optional: true,
77
+ datetime_required: '2021-01-01T00:00:00Z',
78
+ datetime_optional: '2021-01-01T00:00:00Z',
79
+ file_required: 'some_file',
80
+ file_optional: 'some_file',
81
+ password_required: 'some_password',
82
+ password_optional: 'some_password',
83
+ code_optional: 'some_code',
84
+ };
85
+ type mixedOptionalChildren = PlainFieldContribution<{
86
+ key: 'parent_input';
87
+ children: [
88
+ { key: 'string_required'; type: 'string'; required: true },
89
+ { key: 'string_optional'; type: 'string'; required: false },
90
+ ];
91
+ }>;
92
+ expectAssignable<mixedOptionalChildren>(multipleRequiredChild);
93
+ expectAssignable<mixedOptionalChildren>({
94
+ ...multipleRequiredChild,
95
+ ...multipleOptionalChild,
96
+ });
97
+
98
+ //
99
+ // Dictionary fields (where `dict:true` is set)
100
+ //
101
+ // Required dictionary fields.
102
+ const expectedDictRequired = {
103
+ dict_required: {
104
+ some_string_1: 'some_string_1',
105
+ } as Record<string, string>,
106
+ };
107
+ type dictRequiredResult = PlainFieldContribution<{
108
+ key: 'dict_required';
109
+ type: 'string';
110
+ required: true;
111
+ dict: true;
112
+ }>;
113
+ expectType<dictRequiredResult>(expectedDictRequired);
114
+
115
+ // Optional dictionary fields.
116
+ type dictOptionalResult = PlainFieldContribution<{
117
+ key: 'dict_optional';
118
+ type: 'string';
119
+ dict: true;
120
+ }>;
121
+ expectAssignable<dictOptionalResult>({
122
+ dict_optional: { a: 'aaa' },
123
+ });
124
+ expectAssignable<dictOptionalResult>({
125
+ dict_optional: {} as Record<string, string>,
126
+ });
127
+ expectAssignable<dictOptionalResult>({
128
+ dict_optional: {},
129
+ });
130
+ expectAssignable<dictOptionalResult>({ dict_optional: undefined });
131
+ expectAssignable<dictOptionalResult>({});
132
+
133
+ //
134
+ // List fields (where `list:true` is set)
135
+ //
136
+ // Required string list fields.
137
+ const expectedStringListRequired = {
138
+ list_required_string: ['some_string_1', 'some_string_2'],
139
+ };
140
+ type stringListRequiredResult = PlainFieldContribution<{
141
+ key: 'list_required_string';
142
+ type: 'string';
143
+ required: true;
144
+ list: true;
145
+ }>;
146
+ expectType<stringListRequiredResult>(expectedStringListRequired);
147
+
148
+ // Optional string list fields.
149
+ type stringListOptionalResult = PlainFieldContribution<{
150
+ key: 'list_optional_string';
151
+ type: 'string';
152
+ list: true;
153
+ }>;
154
+ expectAssignable<stringListOptionalResult>({
155
+ list_optional_string: ['some_string_1', 'some_string_2'],
156
+ });
157
+ expectAssignable<stringListOptionalResult>({
158
+ list_optional_string: [],
159
+ });
160
+ expectAssignable<stringListOptionalResult>({
161
+ list_optional_string: undefined,
162
+ });
163
+ expectAssignable<stringListOptionalResult>({});
164
+
165
+ // Optional omitted type (string) list fields.
166
+ type omittedTypeListOptionalResult = PlainFieldContribution<{
167
+ key: 'list_optional_omitted_type';
168
+ // No `type` set.
169
+ list: true;
170
+ }>;
171
+ expectAssignable<omittedTypeListOptionalResult>({
172
+ list_optional_omitted_type: ['some_string_1', 'some_string_2'],
173
+ });
174
+ expectAssignable<omittedTypeListOptionalResult>({
175
+ list_optional_omitted_type: [],
176
+ });
177
+ expectAssignable<omittedTypeListOptionalResult>({
178
+ list_optional_omitted_type: undefined,
179
+ });
180
+ expectAssignable<omittedTypeListOptionalResult>({});
181
+
182
+ // Required integer list fields.
183
+ const expectedIntegerListRequired = {
184
+ list_required_integer: [1, 2],
185
+ };
186
+ type integerListRequiredResult = PlainFieldContribution<{
187
+ key: 'list_required_integer';
188
+ type: 'integer';
189
+ required: true;
190
+ list: true;
191
+ }>;
192
+ expectType<integerListRequiredResult>(expectedIntegerListRequired);
193
+
194
+ // Optional integer list fields.
195
+ type integerListOptionalResult = PlainFieldContribution<{
196
+ key: 'list_required';
197
+ type: 'integer';
198
+ list: true;
199
+ }>;
200
+ expectAssignable<integerListOptionalResult>({
201
+ list_required: [1, 2],
202
+ });
203
+ expectAssignable<integerListOptionalResult>({
204
+ list_required: [],
205
+ });
206
+ expectAssignable<integerListOptionalResult>({
207
+ list_required: undefined,
208
+ });
209
+ expectAssignable<integerListOptionalResult>({});
210
+
211
+ //
212
+ // Primitive fields (no parent, dict, or list. Single input field.)
213
+ //
214
+ // Required primitive string field.
215
+ const expectedPrimitiveRequired = {
216
+ primitive_required_string: 'some_string',
217
+ };
218
+ type primitiveRequiredStringResult = PlainFieldContribution<{
219
+ key: 'primitive_required_string';
220
+ type: 'string';
221
+ required: true;
222
+ }>;
223
+ expectType<primitiveRequiredStringResult>(expectedPrimitiveRequired);
224
+
225
+ // Optional primitive string field.
226
+ type primitiveOptionalStringResult = PlainFieldContribution<{
227
+ key: 'primitive_optional_string';
228
+ type: 'string';
229
+ }>;
230
+ expectAssignable<primitiveOptionalStringResult>({
231
+ primitive_optional_string: 'some_string',
232
+ });
233
+ expectAssignable<primitiveOptionalStringResult>({
234
+ primitive_optional_string: undefined,
235
+ });
236
+ expectAssignable<primitiveOptionalStringResult>({});
237
+
238
+ // Required primitive integer field.
239
+ const expectedPrimitiveRequiredInteger = {
240
+ primitive_required_integer: 1,
241
+ };
242
+ type primitiveRequiredIntegerResult = PlainFieldContribution<{
243
+ key: 'primitive_required_integer';
244
+ type: 'integer';
245
+ required: true;
246
+ }>;
247
+ expectType<primitiveRequiredIntegerResult>(expectedPrimitiveRequiredInteger);
248
+
249
+ // Optional primitive integer field.
250
+ type primitiveOptionalIntegerResult = PlainFieldContribution<{
251
+ key: 'primitive_optional_integer';
252
+ type: 'integer';
253
+ }>;
254
+ expectAssignable<primitiveOptionalIntegerResult>({
255
+ primitive_optional_integer: 1,
256
+ });
257
+ expectAssignable<primitiveOptionalIntegerResult>({
258
+ primitive_optional_integer: undefined,
259
+ });
260
+ expectAssignable<primitiveOptionalIntegerResult>({});
261
+
262
+ // Required primitive number field.
263
+ const expectedPrimitiveRequiredNumber = {
264
+ primitive_required_number: 1.1,
265
+ };
266
+ type primitiveRequiredNumberResult = PlainFieldContribution<{
267
+ key: 'primitive_required_number';
268
+ type: 'number';
269
+ required: true;
270
+ }>;
271
+ expectType<primitiveRequiredNumberResult>(expectedPrimitiveRequiredNumber);
272
+
273
+ // Optional primitive number field.
274
+ type primitiveOptionalNumberResult = PlainFieldContribution<{
275
+ key: 'primitive_optional_number';
276
+ type: 'number';
277
+ }>;
278
+ expectAssignable<primitiveOptionalNumberResult>({
279
+ primitive_optional_number: 1.1,
280
+ });
281
+ expectAssignable<primitiveOptionalNumberResult>({
282
+ primitive_optional_number: undefined,
283
+ });
284
+ expectAssignable<primitiveOptionalNumberResult>({});
285
+
286
+ // Required primitive boolean field.
287
+ const expectedPrimitiveRequiredBoolean = {
288
+ primitive_required_boolean: true,
289
+ };
290
+ type primitiveRequiredBooleanResult = PlainFieldContribution<{
291
+ key: 'primitive_required_boolean';
292
+ type: 'boolean';
293
+ required: true;
294
+ }>;
295
+ expectType<primitiveRequiredBooleanResult>(expectedPrimitiveRequiredBoolean);
296
+
297
+ // Optional primitive boolean field.
298
+ type primitiveOptionalBooleanResult = PlainFieldContribution<{
299
+ key: 'primitive_optional_boolean';
300
+ type: 'boolean';
301
+ }>;
302
+ expectAssignable<primitiveOptionalBooleanResult>({
303
+ primitive_optional_boolean: true,
304
+ });
305
+ expectAssignable<primitiveOptionalBooleanResult>({
306
+ primitive_optional_boolean: undefined,
307
+ });
308
+ expectAssignable<primitiveOptionalBooleanResult>({});
309
+
310
+ // Required primitive datetime field.
311
+ const expectedPrimitiveRequiredDatetime = {
312
+ primitive_required_datetime: '2021-01-01T00:00:00Z',
313
+ };
314
+
315
+ type primitiveRequiredDatetimeResult = PlainFieldContribution<{
316
+ key: 'primitive_required_datetime';
317
+ type: 'datetime';
318
+ required: true;
319
+ }>;
320
+ expectType<primitiveRequiredDatetimeResult>(expectedPrimitiveRequiredDatetime);
321
+
322
+ // Optional primitive datetime field.
323
+ type primitiveOptionalDatetimeResult = PlainFieldContribution<{
324
+ key: 'primitive_optional_datetime';
325
+ type: 'datetime';
326
+ }>;
327
+ expectAssignable<primitiveOptionalDatetimeResult>({
328
+ primitive_optional_datetime: '2021-01-01T00:00:00Z',
329
+ });
330
+ expectAssignable<primitiveOptionalDatetimeResult>({
331
+ primitive_optional_datetime: undefined,
332
+ });
333
+ expectAssignable<primitiveOptionalDatetimeResult>({});
334
+
335
+ // Optional primitive copy field.
336
+ type primitiveOptionalCopyResult = PlainFieldContribution<{
337
+ key: 'primitive_optional_copy';
338
+ type: 'copy';
339
+ }>;
340
+ expectAssignable<primitiveOptionalCopyResult>({
341
+ primitive_optional_copy: undefined,
342
+ });
343
+ expectAssignable<primitiveOptionalCopyResult>({});
344
+
345
+ //
346
+ // Choices auto-complete unions.
347
+ //
348
+ // Required object choices auto-complete unions.
349
+ type requiredObjectChoicesAutoCompleteUnions = PlainFieldContribution<{
350
+ key: 'required_object_choices_auto_complete_unions';
351
+ type: 'string';
352
+ required: true;
353
+ choices: {
354
+ alpha: 'Alpha';
355
+ beta: 'Beta';
356
+ };
357
+ }>;
358
+ expectType<requiredObjectChoicesAutoCompleteUnions>(
359
+ {} as {
360
+ required_object_choices_auto_complete_unions:
361
+ | 'alpha'
362
+ | 'beta'
363
+ | (string & {});
364
+ },
365
+ );
366
+ expectAssignable<requiredObjectChoicesAutoCompleteUnions>({
367
+ required_object_choices_auto_complete_unions: 'alpha',
368
+ });
369
+
370
+ // Optional object choices auto-complete unions.
371
+ type optionalObjectChoicesAutoCompleteUnions = PlainFieldContribution<{
372
+ key: 'optional_object_choices_auto_complete_unions';
373
+ type: 'string';
374
+ required: false;
375
+ choices: {
376
+ alpha: 'Alpha';
377
+ beta: 'Beta';
378
+ };
379
+ }>;
380
+ expectType<optionalObjectChoicesAutoCompleteUnions>(
381
+ {} as {
382
+ optional_object_choices_auto_complete_unions?:
383
+ | 'alpha'
384
+ | 'beta'
385
+ | (string & {});
386
+ },
387
+ );
388
+ expectAssignable<optionalObjectChoicesAutoCompleteUnions>({
389
+ optional_object_choices_auto_complete_unions: 'alpha',
390
+ });
391
+ expectAssignable<optionalObjectChoicesAutoCompleteUnions>({
392
+ optional_object_choices_auto_complete_unions: undefined,
393
+ });
394
+ expectAssignable<optionalObjectChoicesAutoCompleteUnions>({});
395
+
396
+ // Required array choices auto-complete unions.
397
+ type requiredFieldArrayChoicesAutoCompleteUnions = PlainFieldContribution<{
398
+ key: 'required_field_array_choices_auto_complete_unions';
399
+ type: 'string';
400
+ required: true;
401
+ choices: [
402
+ { label: 'Alpha'; value: 'alpha'; sample: 'alpha' },
403
+ { label: 'Beta'; value: 'beta'; sample: 'beta' },
404
+ ];
405
+ }>;
406
+ expectType<requiredFieldArrayChoicesAutoCompleteUnions>(
407
+ {} as {
408
+ required_field_array_choices_auto_complete_unions:
409
+ | 'alpha'
410
+ | 'beta'
411
+ | (string & {});
412
+ },
413
+ );
414
+ expectAssignable<requiredFieldArrayChoicesAutoCompleteUnions>({
415
+ required_field_array_choices_auto_complete_unions: 'alpha',
416
+ });
417
+ expectAssignable<requiredFieldArrayChoicesAutoCompleteUnions>({
418
+ required_field_array_choices_auto_complete_unions: 'something_else',
419
+ });
420
+
421
+ // Optional array choices auto-complete unions.
422
+ type optionalFieldArrayChoicesAutoCompleteUnions = PlainFieldContribution<{
423
+ key: 'optional_field_array_choices_auto_complete_unions';
424
+ type: 'string';
425
+ required: false;
426
+ choices: [
427
+ { label: 'Alpha'; value: 'alpha'; sample: 'alpha' },
428
+ { label: 'Beta'; value: 'beta'; sample: 'beta' },
429
+ ];
430
+ }>;
431
+ expectType<optionalFieldArrayChoicesAutoCompleteUnions>(
432
+ {} as {
433
+ optional_field_array_choices_auto_complete_unions?:
434
+ | 'alpha'
435
+ | 'beta'
436
+ | (string & {});
437
+ },
438
+ );
439
+ expectAssignable<optionalFieldArrayChoicesAutoCompleteUnions>({
440
+ optional_field_array_choices_auto_complete_unions: 'alpha',
441
+ });
442
+ expectAssignable<optionalFieldArrayChoicesAutoCompleteUnions>({});
443
+
444
+ //
445
+ // Required string array choices auto-complete unions.
446
+ type requiredStringArrayChoicesAutoCompleteUnions = PlainFieldContribution<{
447
+ key: 'required_string_array_choices_auto_complete_unions';
448
+ type: 'string';
449
+ required: true;
450
+ choices: ['alpha', 'beta'];
451
+ }>;
452
+ expectType<requiredStringArrayChoicesAutoCompleteUnions>(
453
+ {} as {
454
+ required_string_array_choices_auto_complete_unions:
455
+ | 'alpha'
456
+ | 'beta'
457
+ | (string & {});
458
+ },
459
+ );
460
+ expectAssignable<requiredStringArrayChoicesAutoCompleteUnions>({
461
+ required_string_array_choices_auto_complete_unions: 'alpha',
462
+ });
463
+ expectAssignable<requiredStringArrayChoicesAutoCompleteUnions>({
464
+ required_string_array_choices_auto_complete_unions: 'something_else',
465
+ });
466
+
467
+ type optionalStringArrayChoicesAutoCompleteUnions = PlainFieldContribution<{
468
+ key: 'optional_string_array_choices_auto_complete_unions';
469
+ type: 'string';
470
+ required: false;
471
+ choices: ['alpha', 'beta'];
472
+ }>;
473
+ expectType<optionalStringArrayChoicesAutoCompleteUnions>(
474
+ {} as {
475
+ optional_string_array_choices_auto_complete_unions?:
476
+ | 'alpha'
477
+ | 'beta'
478
+ | (string & {});
479
+ },
480
+ );
481
+ expectAssignable<optionalStringArrayChoicesAutoCompleteUnions>({
482
+ optional_string_array_choices_auto_complete_unions: 'alpha',
483
+ });
484
+ expectAssignable<optionalStringArrayChoicesAutoCompleteUnions>({});
@@ -9,7 +9,7 @@
9
9
  import type {
10
10
  InferInputData,
11
11
  InputFieldFunctionWithInputs,
12
- InputFields,
12
+ StringHints,
13
13
  } from './inputs';
14
14
  import { defineInputFields } from '.';
15
15
  import type { PlainInputField } from './schemas.generated';
@@ -18,9 +18,7 @@ import { expectAssignable, expectType } from 'tsd';
18
18
 
19
19
  //
20
20
  // Test for when `type` is not set, the field defaults to `string`.
21
- const defaultStringInputs = [
22
- { key: 'default_string' },
23
- ] as const satisfies InputFields;
21
+ const defaultStringInputs = defineInputFields([{ key: 'default_string' }]);
24
22
  const defaultStringResult1: InferInputData<typeof defaultStringInputs> = {
25
23
  default_string: 'a',
26
24
  };
@@ -32,11 +30,11 @@ expectAssignable<{ default_string?: string }>(defaultStringResult2);
32
30
 
33
31
  //
34
32
  // Tests for `required` combinations.
35
- const requiredComboInputs = [
33
+ const requiredComboInputs = defineInputFields([
36
34
  { key: 'required_true', required: true },
37
35
  { key: 'required_false', required: false },
38
36
  { key: 'required_omitted' }, // Will also be optional.
39
- ] as const satisfies InputFields;
37
+ ]);
40
38
 
41
39
  const requiredComboResult1: InferInputData<typeof requiredComboInputs> = {
42
40
  required_true: 'a',
@@ -50,7 +48,7 @@ expectAssignable<{
50
48
 
51
49
  //
52
50
  // Test available types.
53
- const typeComboInputs = [
51
+ const typeComboInputs = defineInputFields([
54
52
  { key: 'string_type', type: 'string', required: true },
55
53
  { key: 'text_type', type: 'text', required: true },
56
54
  { key: 'password_type', type: 'password', required: true },
@@ -60,7 +58,7 @@ const typeComboInputs = [
60
58
  { key: 'boolean_type', type: 'boolean', required: true },
61
59
  { key: 'datetime_type', type: 'datetime', required: true },
62
60
  { key: 'file_type', type: 'file', required: true },
63
- ] as const satisfies InputFields;
61
+ ]);
64
62
  const typeComboResult: InferInputData<typeof typeComboInputs> = {
65
63
  string_type: 'a',
66
64
  text_type: 'b',
@@ -86,11 +84,11 @@ expectType<{
86
84
 
87
85
  //
88
86
  // Test that copy fields are never appear in the bundle.
89
- const copyComboInputs = [
87
+ const copyComboInputs = defineInputFields([
90
88
  { key: 'copy_type', type: 'copy' },
91
89
  { key: 'copy_type_required', type: 'copy', required: true },
92
90
  { key: 'copy_type_not_required', type: 'copy', required: false },
93
- ] as const satisfies InputFields;
91
+ ]);
94
92
  const copyComboResult: InferInputData<typeof copyComboInputs> = {};
95
93
  expectType<{}>(copyComboResult);
96
94
 
@@ -100,14 +98,14 @@ expectType<{}>(copyComboResult);
100
98
  // the return type is a constant array.
101
99
  // - Even if the possible result fields are known, they will all be
102
100
  // considered optional.
103
- const knownFieldFunctionInputs = [
101
+ const knownFieldFunctionInputs = defineInputFields([
104
102
  () =>
105
- [
103
+ defineInputFields([
106
104
  { key: 'ff_required', type: 'string', required: true },
107
105
  { key: 'ff_optional', type: 'string', required: false },
108
106
  { key: 'ff_omitted', type: 'string' },
109
- ] as const satisfies InputFields,
110
- ] as const satisfies InputFields;
107
+ ]),
108
+ ]);
111
109
  const fieldFunctionResult: InferInputData<typeof knownFieldFunctionInputs> = {
112
110
  ff_required: 'a',
113
111
  ff_optional: 'b',
@@ -121,14 +119,14 @@ expectType<{
121
119
 
122
120
  //
123
121
  // Same but Async.
124
- const knownFieldFunctionAsyncInputs = [
122
+ const knownFieldFunctionAsyncInputs = defineInputFields([
125
123
  async () =>
126
- [
124
+ defineInputFields([
127
125
  { key: 'ff_required', type: 'string', required: true },
128
126
  { key: 'ff_optional', type: 'string', required: false },
129
127
  { key: 'ff_omitted', type: 'string' },
130
- ] as const satisfies InputFields,
131
- ] as const satisfies InputFields;
128
+ ]),
129
+ ]);
132
130
  const knownFieldFunctionAsyncResult: InferInputData<
133
131
  typeof knownFieldFunctionAsyncInputs
134
132
  > = {
@@ -145,18 +143,18 @@ expectType<{
145
143
  //
146
144
  // Test that all possible inputs a field function could return are
147
145
  // combined into a flat object as optional fields.
148
- const unionOfFunctionResultInputs = [
146
+ const unionOfFunctionResultInputs = defineInputFields([
149
147
  () => {
150
148
  if (Math.random() > 0.5) {
151
- return [
149
+ return defineInputFields([
152
150
  { key: 'ff_a', type: 'string', required: true },
153
- ] as const satisfies InputFields;
151
+ ]);
154
152
  }
155
- return [
153
+ return defineInputFields([
156
154
  { key: 'ff_b', type: 'string', required: false },
157
- ] as const satisfies InputFields;
155
+ ]);
158
156
  },
159
- ] as const satisfies InputFields;
157
+ ]);
160
158
  const unionOfFunctionResultInputsResult: InferInputData<
161
159
  typeof unionOfFunctionResultInputs
162
160
  > = {
@@ -170,18 +168,18 @@ expectType<{
170
168
 
171
169
  //
172
170
  // Same but Async.
173
- const unionOfFunctionResultAsyncInputs = [
171
+ const unionOfFunctionResultAsyncInputs = defineInputFields([
174
172
  async (z, bundle) => {
175
173
  if (Math.random() > 0.5) {
176
- return [
174
+ return defineInputFields([
177
175
  { key: 'ff_a', type: 'string', required: true },
178
- ] as const satisfies InputFields;
176
+ ]);
179
177
  }
180
- return [
178
+ return defineInputFields([
181
179
  { key: 'ff_b', type: 'string', required: false },
182
- ] as const satisfies InputFields;
180
+ ]);
183
181
  },
184
- ] as const satisfies InputFields;
182
+ ]);
185
183
  const unionOfFunctionResultAsyncResult: InferInputData<
186
184
  typeof unionOfFunctionResultAsyncInputs
187
185
  > = {
@@ -196,12 +194,12 @@ expectType<{
196
194
  //
197
195
  // Test that inputFieldFunctions with unknown fields results produce
198
196
  // Record<string, unknown>.
199
- const unknownFieldFunctionInputs = [
197
+ const unknownFieldFunctionInputs = defineInputFields([
200
198
  () => {
201
199
  // E.g. Fetch fields from an API
202
- return [] as PlainInputField[];
200
+ return [];
203
201
  },
204
- ] as const satisfies InputFields;
202
+ ]);
205
203
  const unknownFieldFunctionResult: InferInputData<
206
204
  typeof unknownFieldFunctionInputs
207
205
  > = {};
@@ -209,12 +207,12 @@ expectType<Record<string, unknown>>(unknownFieldFunctionResult);
209
207
 
210
208
  //
211
209
  // Same but Async.
212
- const unknownFieldFunctionAsyncInputs = [
210
+ const unknownFieldFunctionAsyncInputs = defineInputFields([
213
211
  async () => {
214
212
  // E.g. Fetch fields from an API
215
213
  return [] as PlainInputField[];
216
214
  },
217
- ] as const satisfies InputFields;
215
+ ]);
218
216
  const unknownFieldFunctionAsyncResult: InferInputData<
219
217
  typeof unknownFieldFunctionAsyncInputs
220
218
  > = {};
@@ -225,13 +223,13 @@ expectType<Record<string, unknown>>(unknownFieldFunctionAsyncResult);
225
223
  // function inputs, and then testing the result of all of the inputs
226
224
  // combined.
227
225
 
228
- const basicFields = [
226
+ const basicFields = defineInputFields([
229
227
  { key: 'string_field', type: 'string', required: true },
230
228
  { key: 'number_field', type: 'number', required: true },
231
229
  { key: 'boolean_field', type: 'boolean', required: true },
232
230
  { key: 'optional_field', type: 'string', required: false },
233
231
  { key: 'omitted_field', type: 'string' },
234
- ] as const satisfies InputFields;
232
+ ]);
235
233
 
236
234
  const dynamicField = ((z, bundle) => {
237
235
  expectType<{
@@ -241,9 +239,9 @@ const dynamicField = ((z, bundle) => {
241
239
  optional_field?: string;
242
240
  omitted_field?: string;
243
241
  }>(bundle.inputData);
244
- return [
242
+ return defineInputFields([
245
243
  { key: 'dynamic_field', type: 'string', required: true },
246
- ] as const satisfies InputFields;
244
+ ]);
247
245
  }) satisfies InputFieldFunctionWithInputs<typeof basicFields>;
248
246
 
249
247
  const allFields = defineInputFields([...basicFields, dynamicField]);
@@ -264,3 +262,69 @@ expectType<{
264
262
  omitted_field?: string;
265
263
  dynamic_field?: string; // Becomes optional.
266
264
  }>(allFieldsResult);
265
+
266
+ // Choices
267
+ const choicesInputs = defineInputFields([
268
+ {
269
+ key: 'choices_string_array',
270
+ type: 'string',
271
+ required: true,
272
+ choices: ['c1', 'c2'],
273
+ },
274
+ {
275
+ key: 'choices_object',
276
+ type: 'string',
277
+ required: true,
278
+ choices: { c3: 'C3', c4: 'C4' },
279
+ },
280
+ {
281
+ key: 'choices_field_array',
282
+ type: 'string',
283
+ required: true,
284
+ choices: [
285
+ { label: 'C5', value: 'c5', sample: 'c5' },
286
+ { label: 'C6', value: 'c6', sample: 'c6' },
287
+ ],
288
+ },
289
+ {
290
+ key: 'choices_list',
291
+ type: 'string',
292
+ required: true,
293
+ list: true,
294
+ choices: ['c7', 'c8'],
295
+ },
296
+ {
297
+ key: 'ignored_parent',
298
+ children: [
299
+ {
300
+ key: 'child_choice',
301
+ type: 'string',
302
+ required: true,
303
+ choices: { c9: 'C9', c10: 'C10' },
304
+ },
305
+ {
306
+ key: 'child_choice_list',
307
+ type: 'string',
308
+ required: true,
309
+ list: true,
310
+ choices: ['c11', 'c12'],
311
+ },
312
+ ],
313
+ },
314
+ ]);
315
+ const choicesResult: InferInputData<typeof choicesInputs> = {
316
+ choices_string_array: 'c1',
317
+ choices_object: 'c3',
318
+ choices_field_array: 'c5',
319
+ choices_list: ['c7'],
320
+ child_choice: 'c9',
321
+ child_choice_list: ['c11'],
322
+ };
323
+ expectType<{
324
+ choices_string_array: StringHints<'c1' | 'c2'>;
325
+ choices_object: StringHints<'c3' | 'c4'>;
326
+ choices_field_array: StringHints<'c5' | 'c6'>;
327
+ choices_list: StringHints<'c7' | 'c8'>[];
328
+ child_choice: StringHints<'c9' | 'c10'>;
329
+ child_choice_list: StringHints<'c11' | 'c12'>[];
330
+ }>(choicesResult);
@@ -4,7 +4,7 @@
4
4
  * files, and/or the schema-to-ts tool and run its CLI to regenerate
5
5
  * these typings.
6
6
  *
7
- * zapier-platform-schema version: 17.7.1
7
+ * zapier-platform-schema version: 17.7.2
8
8
  * schema-to-ts compiler version: 0.1.0
9
9
  */
10
10
  import type {