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 +2 -2
- package/types/custom.d.ts +13 -2
- package/types/functions.d.ts +84 -29
- package/types/functions.test-d.ts +47 -1
- package/types/inputs.d.ts +142 -11
- package/types/inputs.plainfields.test-d.ts +484 -0
- package/types/inputs.test-d.ts +103 -39
- package/types/schemas.generated.d.ts +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zapier-platform-core",
|
|
3
|
-
"version": "17.7.
|
|
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.
|
|
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 (
|
|
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;
|
package/types/functions.d.ts
CHANGED
|
@@ -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
|
-
$
|
|
26
|
+
$InputDataOrFields extends DefaultInputData | InputField[] = DefaultInputData,
|
|
14
27
|
$Return extends {} = { id: string },
|
|
15
|
-
> = (
|
|
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
|
-
$
|
|
40
|
+
$InputDataOrFields extends DefaultInputData | InputField[] = DefaultInputData,
|
|
25
41
|
$Return extends {} = {},
|
|
26
|
-
> = (
|
|
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
|
-
$
|
|
52
|
+
$InputDataOrFields extends DefaultInputData | InputField[] = DefaultInputData,
|
|
34
53
|
$Return extends {} = {},
|
|
35
|
-
> = (
|
|
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
|
-
$
|
|
64
|
+
$InputDataOrFields extends DefaultInputData | InputField[] = DefaultInputData,
|
|
43
65
|
$Return extends {} = {},
|
|
44
|
-
> = (
|
|
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
|
-
$
|
|
76
|
+
$InputDataOrFields extends DefaultInputData | InputField[] = DefaultInputData,
|
|
52
77
|
$Return extends {} = {},
|
|
53
|
-
> = (
|
|
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
|
-
$
|
|
87
|
+
$InputDataOrFields extends DefaultInputData | InputField[] = DefaultInputData,
|
|
60
88
|
$Return extends {} = {},
|
|
61
|
-
> = (
|
|
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
|
-
$
|
|
99
|
+
$InputDataOrFields extends DefaultInputData | InputField[] = DefaultInputData,
|
|
69
100
|
$Return extends {} = {},
|
|
70
|
-
> = (
|
|
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
|
-
$
|
|
111
|
+
$InputDataOrFields extends DefaultInputData | InputField[] = DefaultInputData,
|
|
78
112
|
$Return extends {} = {},
|
|
79
|
-
> = (
|
|
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
|
-
$
|
|
125
|
+
$InputDataOrFields extends DefaultInputData | InputField[] = DefaultInputData,
|
|
89
126
|
$Return extends {} = {},
|
|
90
|
-
> = (
|
|
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
|
-
$
|
|
147
|
+
$InputDataOrFields extends DefaultInputData | InputField[] = DefaultInputData,
|
|
108
148
|
// TODO: Type cleanedRequest & outputData on Bundle interface
|
|
109
149
|
$Return extends {} = {},
|
|
110
|
-
> = (
|
|
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
|
-
$
|
|
159
|
+
$InputDataOrFields extends DefaultInputData | InputField[] = DefaultInputData,
|
|
117
160
|
$Return extends {} = {},
|
|
118
|
-
> = (
|
|
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[]
|
|
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
|
-
$
|
|
185
|
+
$InputDataOrFields extends DefaultInputData | InputField[] = DefaultInputData,
|
|
140
186
|
$Return extends {} = {},
|
|
141
|
-
> = (
|
|
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
|
-
$
|
|
200
|
+
$InputDataOrFields extends DefaultInputData | InputField[] = DefaultInputData,
|
|
152
201
|
$Return extends {} = {},
|
|
153
|
-
> = (
|
|
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
|
-
$
|
|
211
|
+
$InputDataOrFields extends DefaultInputData | InputField[] = DefaultInputData,
|
|
160
212
|
$Return extends {} = {},
|
|
161
|
-
> = (
|
|
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 {
|
|
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
|
|
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> =
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
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
|
-
:
|
|
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>({});
|
package/types/inputs.test-d.ts
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
import type {
|
|
10
10
|
InferInputData,
|
|
11
11
|
InputFieldFunctionWithInputs,
|
|
12
|
-
|
|
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
|
-
]
|
|
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
|
-
]
|
|
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
|
-
]
|
|
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
|
-
]
|
|
110
|
-
]
|
|
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
|
-
]
|
|
131
|
-
]
|
|
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
|
-
]
|
|
151
|
+
]);
|
|
154
152
|
}
|
|
155
|
-
return [
|
|
153
|
+
return defineInputFields([
|
|
156
154
|
{ key: 'ff_b', type: 'string', required: false },
|
|
157
|
-
]
|
|
155
|
+
]);
|
|
158
156
|
},
|
|
159
|
-
]
|
|
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
|
-
]
|
|
176
|
+
]);
|
|
179
177
|
}
|
|
180
|
-
return [
|
|
178
|
+
return defineInputFields([
|
|
181
179
|
{ key: 'ff_b', type: 'string', required: false },
|
|
182
|
-
]
|
|
180
|
+
]);
|
|
183
181
|
},
|
|
184
|
-
]
|
|
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 []
|
|
200
|
+
return [];
|
|
203
201
|
},
|
|
204
|
-
]
|
|
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
|
-
]
|
|
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
|
-
]
|
|
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
|
-
]
|
|
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);
|