@prismatic-io/spectral 10.18.6 → 10.18.7-preview.1

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.
@@ -3,13 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.INPUT_TYPE_MAP = exports.getInputs = void 0;
4
4
  const escapeSpecialCharacters_1 = require("../utils/escapeSpecialCharacters");
5
5
  const docBlock_1 = require("./docBlock");
6
- const getDefaultValue = (value, isCollection) => {
7
- if (value === undefined || value === "") {
8
- return isCollection ? [] : value;
9
- }
10
- const stringValue = typeof value === "string" ? value : JSON.stringify(value);
11
- return (0, escapeSpecialCharacters_1.escapeSpecialCharacters)(stringValue);
12
- };
13
6
  const getInputs = ({ inputs, docBlock = docBlock_1.DOC_BLOCK_DEFAULT }) => {
14
7
  return inputs.reduce((acc, input) => {
15
8
  if ((typeof input.shown === "boolean" && input.shown === false) ||
@@ -68,8 +61,23 @@ exports.INPUT_TYPE_MAP = {
68
61
  timestamp: "string",
69
62
  flow: "string",
70
63
  template: "string",
64
+ structuredObject: {
65
+ module: "@prismatic-io/spectral/dist/types",
66
+ type: "StructuredObject",
67
+ },
68
+ dynamicObject: {
69
+ module: "@prismatic-io/spectral/dist/types",
70
+ type: "DynamicObject",
71
+ },
71
72
  };
72
73
  const getInputValueType = (input) => {
74
+ var _a, _b;
75
+ if (input.type === "structuredObject") {
76
+ return structuredObjectTypeString((_a = input.inputs) !== null && _a !== void 0 ? _a : []);
77
+ }
78
+ if (input.type === "dynamicObject") {
79
+ return dynamicObjectTypeString((_b = input.inputs) !== null && _b !== void 0 ? _b : []);
80
+ }
73
81
  const inputType = exports.INPUT_TYPE_MAP[input.type];
74
82
  const valueType = input.model
75
83
  ? input.model
@@ -94,3 +102,70 @@ const getInputValueType = (input) => {
94
102
  }
95
103
  return valueType;
96
104
  };
105
+ const getDefaultValue = (value, isCollection) => {
106
+ if (value === undefined || value === "") {
107
+ return isCollection ? [] : value;
108
+ }
109
+ const stringValue = typeof value === "string" ? value : JSON.stringify(value);
110
+ return (0, escapeSpecialCharacters_1.escapeSpecialCharacters)(stringValue);
111
+ };
112
+ const isValidIdentifier = (key) => /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(key);
113
+ const wrapCollection = (valueType, collection) => {
114
+ if (collection === "valuelist") {
115
+ return `Array<${valueType}>`;
116
+ }
117
+ if (collection === "keyvaluelist") {
118
+ return `Record<string, ${valueType}> | Array<{key: string, value: ${valueType}}>`;
119
+ }
120
+ return valueType;
121
+ };
122
+ const getLeafBaseType = (child) => {
123
+ var _a;
124
+ if ((_a = child.model) === null || _a === void 0 ? void 0 : _a.length) {
125
+ return child.model
126
+ .map(({ value }) => `\`${value.replaceAll("\r", "\\r").replaceAll("\n", "\\n")}\``)
127
+ .join(" | ");
128
+ }
129
+ const mapped = exports.INPUT_TYPE_MAP[child.type];
130
+ if (!mapped) {
131
+ return "unknown";
132
+ }
133
+ if (typeof mapped === "string") {
134
+ return mapped;
135
+ }
136
+ return `import("${mapped.module}").${mapped.type}`;
137
+ };
138
+ const getLeafTypeString = (child) => {
139
+ var _a;
140
+ if (child.type === "structuredObject") {
141
+ return structuredObjectTypeString((_a = child.inputs) !== null && _a !== void 0 ? _a : []);
142
+ }
143
+ return wrapCollection(getLeafBaseType(child), child.collection);
144
+ };
145
+ const SPECTRAL_TYPES_MODULE = "@prismatic-io/spectral/dist/types";
146
+ const structuredObjectTypeString = (inputs) => {
147
+ if (!inputs.length) {
148
+ return `import("${SPECTRAL_TYPES_MODULE}").StructuredObject`;
149
+ }
150
+ const fields = inputs
151
+ .map((child) => {
152
+ const key = isValidIdentifier(child.key) ? child.key : JSON.stringify(child.key);
153
+ return `${key}: ${getLeafTypeString(child)}`;
154
+ })
155
+ .join("; ");
156
+ return `{ ${fields} }`;
157
+ };
158
+ const dynamicObjectTypeString = (configurations) => {
159
+ if (!configurations.length) {
160
+ return `import("${SPECTRAL_TYPES_MODULE}").DynamicObject`;
161
+ }
162
+ return configurations
163
+ .map((config) => {
164
+ var _a;
165
+ const valuesType = ((_a = config.inputs) === null || _a === void 0 ? void 0 : _a.length)
166
+ ? structuredObjectTypeString(config.inputs)
167
+ : `import("${SPECTRAL_TYPES_MODULE}").StructuredObject`;
168
+ return `{ configuration: ${JSON.stringify(config.key)}; values: ${valuesType} }`;
169
+ })
170
+ .join(" | ");
171
+ };
package/dist/index.d.ts CHANGED
@@ -5,7 +5,7 @@
5
5
  */
6
6
  import { convertComponent } from "./serverTypes/convertComponent";
7
7
  import { convertIntegration } from "./serverTypes/convertIntegration";
8
- import type { ActionDefinition, ActionPerformReturn, ComponentDefinition, ComponentManifest, ConfigPage, ConfigVarResultCollection, ConnectionConfigVar, CustomerActivatedConnectionConfigVar, DataSourceConfigVar, DataSourceDefinition, DataSourceType, DefaultConnectionDefinition, Flow, InputFieldDefinition, Inputs, IntegrationDefinition, OAuth2ConnectionDefinition, OnPremConnectionDefinition, OrganizationActivatedConnectionConfigVar, StandardConfigVar, TriggerDefinition, TriggerPayload, TriggerResult } from "./types";
8
+ import type { ActionDefinition, ActionPerformReturn, ComponentDefinition, ComponentManifest, ConfigPage, ConfigVarResultCollection, ConnectionConfigVar, CustomerActivatedConnectionConfigVar, DataSourceConfigVar, DataSourceDefinition, DataSourceType, DefaultConnectionDefinition, DynamicObjectInputField, Flow, InputFieldDefinition, Inputs, IntegrationDefinition, OAuth2ConnectionDefinition, OnPremConnectionDefinition, OrganizationActivatedConnectionConfigVar, StandardConfigVar, StructuredObjectInputField, TriggerDefinition, TriggerPayload, TriggerResult } from "./types";
9
9
  import type { PollingTriggerDefinition } from "./types/PollingTriggerDefinition";
10
10
  /**
11
11
  * This function creates a code-native integration object that can be
@@ -512,6 +512,69 @@ export declare const dataSource: <TInputs extends Inputs, TConfigVars extends Co
512
512
  * });
513
513
  */
514
514
  export declare const input: <T extends InputFieldDefinition>(definition: T) => T;
515
+ /**
516
+ * Groups related primitive inputs under a single named container. Children
517
+ * may not themselves be structuredObject inputs (the type signature enforces
518
+ * this at compile time).
519
+ *
520
+ * @example
521
+ * import { input, structuredObjectInput } from "@prismatic-io/spectral";
522
+ *
523
+ * const name = structuredObjectInput({
524
+ * label: "Name",
525
+ * inputs: {
526
+ * first: input({ type: "string", label: "First Name", required: true }),
527
+ * last: input({ type: "string", label: "Last Name", required: true }),
528
+ * },
529
+ * });
530
+ */
531
+ export declare const structuredObjectInput: <T extends Omit<StructuredObjectInputField, "type"> & {
532
+ type?: never;
533
+ }>(definition: T) => T & {
534
+ type: "structuredObject";
535
+ };
536
+ /**
537
+ * Presents a discriminated set of input configurations; the integration builder
538
+ * picks a configuration and its inputs become available. Configurations may
539
+ * contain leaf inputs and structuredObject inputs but not nested dynamicObjects
540
+ * (the type signature enforces this at compile time).
541
+ *
542
+ * @example
543
+ * import { input, structuredObjectInput, dynamicObjectInput } from "@prismatic-io/spectral";
544
+ *
545
+ * const recordData = dynamicObjectInput({
546
+ * label: "Record Data",
547
+ * required: true,
548
+ * configurations: {
549
+ * contact: {
550
+ * label: "Contact",
551
+ * comments: "Create a new contact",
552
+ * inputs: {
553
+ * name: structuredObjectInput({
554
+ * label: "Name",
555
+ * inputs: {
556
+ * first: input({ type: "string", label: "First Name", required: true }),
557
+ * last: input({ type: "string", label: "Last Name", required: true }),
558
+ * },
559
+ * }),
560
+ * email: input({ type: "string", label: "Email", required: true }),
561
+ * },
562
+ * },
563
+ * account: {
564
+ * label: "Account",
565
+ * comments: "Create a new account",
566
+ * inputs: {
567
+ * companyName: input({ type: "string", label: "Company Name", required: true }),
568
+ * },
569
+ * },
570
+ * },
571
+ * });
572
+ */
573
+ export declare const dynamicObjectInput: <T extends Omit<DynamicObjectInputField, "type"> & {
574
+ type?: never;
575
+ }>(definition: T) => T & {
576
+ type: "dynamicObject";
577
+ };
515
578
  /**
516
579
  * This function creates a connection that can be used by a code-native integration
517
580
  * or custom component. Connections define the fields (API keys, tokens, etc.) needed
package/dist/index.js CHANGED
@@ -22,7 +22,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
22
22
  return (mod && mod.__esModule) ? mod : { "default": mod };
23
23
  };
24
24
  Object.defineProperty(exports, "__esModule", { value: true });
25
- exports.util = exports.testing = exports.componentManifests = exports.oauth2Connection = exports.onPremConnection = exports.connection = exports.input = exports.dataSource = exports.pollingTrigger = exports.trigger = exports.action = exports.component = exports.componentManifest = exports.organizationActivatedConnection = exports.customerActivatedConnection = exports.connectionConfigVar = exports.dataSourceConfigVar = exports.configVar = exports.configPage = exports.flow = exports.integration = void 0;
25
+ exports.util = exports.testing = exports.componentManifests = exports.oauth2Connection = exports.onPremConnection = exports.connection = exports.dynamicObjectInput = exports.structuredObjectInput = exports.input = exports.dataSource = exports.pollingTrigger = exports.trigger = exports.action = exports.component = exports.componentManifest = exports.organizationActivatedConnection = exports.customerActivatedConnection = exports.connectionConfigVar = exports.dataSourceConfigVar = exports.configVar = exports.configPage = exports.flow = exports.integration = void 0;
26
26
  const serverTypes_1 = require("./serverTypes");
27
27
  const convertComponent_1 = require("./serverTypes/convertComponent");
28
28
  const convertIntegration_1 = require("./serverTypes/convertIntegration");
@@ -557,6 +557,63 @@ exports.dataSource = dataSource;
557
557
  */
558
558
  const input = (definition) => definition;
559
559
  exports.input = input;
560
+ /**
561
+ * Groups related primitive inputs under a single named container. Children
562
+ * may not themselves be structuredObject inputs (the type signature enforces
563
+ * this at compile time).
564
+ *
565
+ * @example
566
+ * import { input, structuredObjectInput } from "@prismatic-io/spectral";
567
+ *
568
+ * const name = structuredObjectInput({
569
+ * label: "Name",
570
+ * inputs: {
571
+ * first: input({ type: "string", label: "First Name", required: true }),
572
+ * last: input({ type: "string", label: "Last Name", required: true }),
573
+ * },
574
+ * });
575
+ */
576
+ const structuredObjectInput = (definition) => (Object.assign(Object.assign({}, definition), { type: "structuredObject" }));
577
+ exports.structuredObjectInput = structuredObjectInput;
578
+ /**
579
+ * Presents a discriminated set of input configurations; the integration builder
580
+ * picks a configuration and its inputs become available. Configurations may
581
+ * contain leaf inputs and structuredObject inputs but not nested dynamicObjects
582
+ * (the type signature enforces this at compile time).
583
+ *
584
+ * @example
585
+ * import { input, structuredObjectInput, dynamicObjectInput } from "@prismatic-io/spectral";
586
+ *
587
+ * const recordData = dynamicObjectInput({
588
+ * label: "Record Data",
589
+ * required: true,
590
+ * configurations: {
591
+ * contact: {
592
+ * label: "Contact",
593
+ * comments: "Create a new contact",
594
+ * inputs: {
595
+ * name: structuredObjectInput({
596
+ * label: "Name",
597
+ * inputs: {
598
+ * first: input({ type: "string", label: "First Name", required: true }),
599
+ * last: input({ type: "string", label: "Last Name", required: true }),
600
+ * },
601
+ * }),
602
+ * email: input({ type: "string", label: "Email", required: true }),
603
+ * },
604
+ * },
605
+ * account: {
606
+ * label: "Account",
607
+ * comments: "Create a new account",
608
+ * inputs: {
609
+ * companyName: input({ type: "string", label: "Company Name", required: true }),
610
+ * },
611
+ * },
612
+ * },
613
+ * });
614
+ */
615
+ const dynamicObjectInput = (definition) => (Object.assign(Object.assign({}, definition), { type: "dynamicObject" }));
616
+ exports.dynamicObjectInput = dynamicObjectInput;
560
617
  /**
561
618
  * This function creates a connection that can be used by a code-native integration
562
619
  * or custom component. Connections define the fields (API keys, tokens, etc.) needed
@@ -1,7 +1,7 @@
1
1
  import { type ComponentDefinition, type ComponentHooks, type ConfigVarResultCollection, type ConnectionDefinition, type ConnectionInput, type ConnectionTemplateInputField, type InputFieldDefinition, type Inputs, type OnPremConnectionInput, type TriggerDefinition, type TriggerPayload, type TriggerResult } from "../types";
2
2
  import { type PollingTriggerDefinition } from "../types/PollingTriggerDefinition";
3
3
  import type { Component as ServerComponent, Connection as ServerConnection, Input as ServerInput, Trigger as ServerTrigger } from ".";
4
- export declare const convertInput: (key: string, { default: defaultValue, type, label, collection, ...rest }: InputFieldDefinition | OnPremConnectionInput | ConnectionInput) => ServerInput;
4
+ export declare const convertInput: (key: string, definition: InputFieldDefinition | OnPremConnectionInput | ConnectionInput) => ServerInput;
5
5
  export declare const _isValidTemplateValue: (template: string, inputs: {
6
6
  [key: string]: ConnectionInput | ConnectionTemplateInputField;
7
7
  }) => {
@@ -19,16 +19,29 @@ const omit_1 = __importDefault(require("lodash/omit"));
19
19
  const types_1 = require("../types");
20
20
  const PollingTriggerDefinition_1 = require("../types/PollingTriggerDefinition");
21
21
  const perform_1 = require("./perform");
22
- const convertInput = (key, _a) => {
23
- var { default: defaultValue, type, label, collection } = _a, rest = __rest(_a, ["default", "type", "label", "collection"]);
22
+ const cleanerFor = (input) => "clean" in input ? input.clean : undefined;
23
+ const convertInput = (key, definition) => {
24
+ // Cast: the field union is wider than any single member; runtime guards below handle it.
25
+ const _a = definition, { default: defaultValue, type, label, collection, inputs: childInputs, configurations } = _a, rest = __rest(_a, ["default", "type", "label", "collection", "inputs", "configurations"]);
24
26
  const keyLabel = collection === "keyvaluelist" && typeof label === "object" ? label.key : undefined;
27
+ const nestedInputs = type === "structuredObject" && childInputs
28
+ ? Object.entries(childInputs).map(([childKey, childDef]) => (0, exports.convertInput)(childKey, childDef))
29
+ : type === "dynamicObject" && configurations
30
+ ? Object.entries(configurations).map(([configKey, configDef]) => ({
31
+ key: configKey,
32
+ type: "structuredObject",
33
+ label: typeof configDef.label === "string" ? configDef.label : configDef.label.value,
34
+ comments: configDef.comments,
35
+ inputs: Object.entries(configDef.inputs).map(([childKey, childDef]) => (0, exports.convertInput)(childKey, childDef)),
36
+ }))
37
+ : undefined;
25
38
  return Object.assign(Object.assign({}, (0, omit_1.default)(rest, [
26
39
  "onPremControlled",
27
40
  "permissionAndVisibilityType",
28
41
  "visibleToOrgDeployer",
29
42
  "writeOnly",
30
43
  ])), { key,
31
- type, default: defaultValue !== null && defaultValue !== void 0 ? defaultValue : types_1.InputFieldDefaultMap[type], collection, label: typeof label === "string" ? label : label.value, keyLabel, onPremiseControlled: ("onPremControlled" in rest && rest.onPremControlled) || undefined });
44
+ type, default: defaultValue !== null && defaultValue !== void 0 ? defaultValue : types_1.InputFieldDefaultMap[type], collection, label: typeof label === "string" ? label : label.value, keyLabel, onPremiseControlled: rest.onPremControlled === true ? true : undefined, inputs: nestedInputs });
32
45
  };
33
46
  exports.convertInput = convertInput;
34
47
  const TEMPLATE_VALUE_REGEX = /{{#(\w+)}}/g;
@@ -73,7 +86,7 @@ exports.convertTemplateInput = convertTemplateInput;
73
86
  const convertAction = (actionKey, _a, hooks) => {
74
87
  var { inputs = {}, perform } = _a, action = __rest(_a, ["inputs", "perform"]);
75
88
  const convertedInputs = Object.entries(inputs).map(([key, value]) => (0, exports.convertInput)(key, value));
76
- const inputCleaners = Object.entries(inputs).reduce((result, [key, { clean }]) => (Object.assign(Object.assign({}, result), { [key]: clean })), {});
89
+ const inputCleaners = Object.entries(inputs).reduce((result, [key, value]) => (Object.assign(Object.assign({}, result), { [key]: cleanerFor(value) })), {});
77
90
  return Object.assign(Object.assign({}, action), { key: actionKey, inputs: convertedInputs, perform: (0, perform_1.createPerform)(perform, {
78
91
  inputCleaners,
79
92
  errorHandler: hooks === null || hooks === void 0 ? void 0 : hooks.error,
@@ -84,17 +97,15 @@ const convertTrigger = (triggerKey, trigger, hooks) => {
84
97
  const { onInstanceDeploy, onInstanceDelete } = trigger;
85
98
  const webhookLifecycleHandlers = "webhookLifecycleHandlers" in trigger ? trigger.webhookLifecycleHandlers : undefined;
86
99
  const inputs = (_a = trigger.inputs) !== null && _a !== void 0 ? _a : {};
87
- const isPollingTrigger = (0, PollingTriggerDefinition_1.isPollingTriggerDefinition)(trigger);
88
100
  const triggerInputKeys = Object.keys(inputs);
89
101
  const convertedTriggerInputs = Object.entries(inputs).map(([key, value]) => {
90
102
  return (0, exports.convertInput)(key, value);
91
103
  });
92
- const triggerInputCleaners = Object.entries(inputs).reduce((result, [key, { clean }]) => (Object.assign(Object.assign({}, result), { [key]: clean })), {});
104
+ const triggerInputCleaners = Object.entries(inputs).reduce((result, [key, value]) => (Object.assign(Object.assign({}, result), { [key]: cleanerFor(value) })), {});
93
105
  let scheduleSupport = "scheduleSupport" in trigger ? trigger.scheduleSupport : "invalid";
94
106
  let convertedActionInputs = [];
95
107
  let performToUse;
96
- if (isPollingTrigger) {
97
- // Pull inputs up from the action and make them available on the trigger
108
+ if ((0, PollingTriggerDefinition_1.isPollingTriggerDefinition)(trigger)) {
98
109
  const { pollAction: action } = trigger;
99
110
  let actionInputCleaners = {};
100
111
  scheduleSupport = "required";
@@ -106,7 +117,7 @@ const convertTrigger = (triggerKey, trigger, hooks) => {
106
117
  accum.push((0, exports.convertInput)(key, value));
107
118
  return accum;
108
119
  }, []);
109
- actionInputCleaners = Object.entries(action.inputs).reduce((result, [key, { clean }]) => (Object.assign(Object.assign({}, result), { [key]: clean })), {});
120
+ actionInputCleaners = Object.entries(action.inputs).reduce((result, [key, value]) => (Object.assign(Object.assign({}, result), { [key]: cleanerFor(value) })), {});
110
121
  }
111
122
  const combinedCleaners = Object.assign({}, actionInputCleaners, triggerInputCleaners);
112
123
  performToUse = (0, perform_1.createPollingPerform)(trigger, {
@@ -124,7 +135,7 @@ const convertTrigger = (triggerKey, trigger, hooks) => {
124
135
  ? trigger.synchronousResponseSupport
125
136
  : scheduleSupport === "invalid"
126
137
  ? "valid"
127
- : "invalid" }), (isPollingTrigger ? { isPollingTrigger: true } : {}));
138
+ : "invalid" }), ((0, PollingTriggerDefinition_1.isPollingTriggerDefinition)(trigger) ? { isPollingTrigger: true } : {}));
128
139
  if (onInstanceDeploy) {
129
140
  result.onInstanceDeploy = (0, perform_1.createPerform)(onInstanceDeploy, {
130
141
  inputCleaners: triggerInputCleaners,
@@ -158,7 +169,7 @@ exports.convertTrigger = convertTrigger;
158
169
  const convertDataSource = (dataSourceKey, _a, hooks) => {
159
170
  var { inputs = {}, perform } = _a, dataSource = __rest(_a, ["inputs", "perform"]);
160
171
  const convertedInputs = Object.entries(inputs).map(([key, value]) => (0, exports.convertInput)(key, value));
161
- const inputCleaners = Object.entries(inputs).reduce((result, [key, { clean }]) => (Object.assign(Object.assign({}, result), { [key]: clean })), {});
172
+ const inputCleaners = Object.entries(inputs).reduce((result, [key, value]) => (Object.assign(Object.assign({}, result), { [key]: cleanerFor(value) })), {});
162
173
  return Object.assign(Object.assign({}, dataSource), { key: dataSourceKey, inputs: convertedInputs, perform: (0, perform_1.createPerform)(perform, {
163
174
  inputCleaners,
164
175
  errorHandler: hooks === null || hooks === void 0 ? void 0 : hooks.error,
@@ -262,5 +262,8 @@ export interface Input {
262
262
  onPremiseControlled?: boolean;
263
263
  dataSource?: string;
264
264
  shown?: boolean;
265
+ /** Nested children. For `structuredObject`, the declared inputs; for
266
+ * `dynamicObject`, one `structuredObject` per configuration. */
267
+ inputs?: Input[];
265
268
  }
266
269
  export * from "./asyncContext";
@@ -1,11 +1,40 @@
1
1
  import type { ConditionalExpression } from "./conditional-logic";
2
- import type { Connection, InputCleanFunction, InputFieldCollection, Inputs, KeyValuePair } from "./Inputs";
2
+ import type { Connection, DynamicObjectInputField, InputCleanFunction, InputFieldCollection, Inputs, KeyValuePair, StructuredObjectInputField } from "./Inputs";
3
+ /** Resolves a single InputFieldDefinition's runtime value type.
4
+ * - structuredObject: record of declared children's resolved value types.
5
+ * - dynamicObject: discriminated union keyed by the selected configuration,
6
+ * with the configuration's resolved inputs nested under `values` to avoid
7
+ * collisions with the `configuration` discriminant key.
8
+ * The depth caps (`LeafInputFieldDefinition`, `StructuredOrLeafInputFieldDefinition`)
9
+ * prevent unbounded recursion. */
10
+ type InputValue<T> = T extends StructuredObjectInputField ? {
11
+ [K in keyof T["inputs"]]: InputValue<T["inputs"][K]>;
12
+ } : T extends DynamicObjectInputField ? {
13
+ [C in keyof T["configurations"]]: {
14
+ configuration: C;
15
+ values: {
16
+ [K in keyof T["configurations"][C]["inputs"]]: InputValue<T["configurations"][C]["inputs"][K]>;
17
+ };
18
+ };
19
+ }[keyof T["configurations"]] : T extends {
20
+ clean: InputCleanFunction<any>;
21
+ } ? ReturnType<T["clean"]> : T extends {
22
+ type: "connection";
23
+ collection?: InputFieldCollection;
24
+ } ? ExtractValue<Connection, T["collection"]> : T extends {
25
+ type: "conditional";
26
+ collection?: InputFieldCollection;
27
+ } ? ExtractValue<ConditionalExpression, T["collection"]> : T extends {
28
+ default?: unknown;
29
+ collection?: InputFieldCollection;
30
+ } ? ExtractValue<T["default"], T["collection"]> : unknown;
3
31
  /**
4
32
  * Collection of input parameters.
5
33
  * Inputs can be static values, references to config variables, or
6
34
  * references to previous steps' outputs.
7
35
  */
8
36
  export type ActionInputParameters<TInputs extends Inputs> = {
9
- [Property in keyof TInputs]: TInputs[Property]["clean"] extends InputCleanFunction<any> ? ReturnType<TInputs[Property]["clean"]> : TInputs[Property]["type"] extends "connection" ? ExtractValue<Connection, TInputs[Property]["collection"]> : TInputs[Property]["type"] extends "conditional" ? ExtractValue<ConditionalExpression, TInputs[Property]["collection"]> : ExtractValue<TInputs[Property]["default"], TInputs[Property]["collection"]>;
37
+ [Property in keyof TInputs]: InputValue<TInputs[Property]>;
10
38
  };
11
39
  export type ExtractValue<TType, TCollection extends InputFieldCollection | undefined> = TCollection extends "keyvaluelist" ? KeyValuePair<TType>[] : TCollection extends "valuelist" ? TType[] : TType;
40
+ export {};
@@ -63,6 +63,8 @@ export type JSONForm = {
63
63
  };
64
64
  export type DynamicObjectSelection = string;
65
65
  export type DynamicFieldSelection = string;
66
+ export type StructuredObject = Record<string, unknown>;
67
+ export type DynamicObject = Record<string, unknown>;
66
68
  /** InputField type enumeration. */
67
69
  export type InputFieldType = InputFieldDefinition["type"];
68
70
  export declare const InputFieldDefaultMap: Record<InputFieldType, string | undefined>;
@@ -83,7 +85,7 @@ export type OnPremConnectionInput = {
83
85
  */
84
86
  onPremControlled: true;
85
87
  } & ConnectionInput;
86
- export type InputFieldDefinition = StringInputField | DataInputField | TextInputField | PasswordInputField | BooleanInputField | CodeInputField | ConditionalInputField | ConnectionInputField | ConnectionTemplateInputField | ObjectSelectionInputField | ObjectFieldMapInputField | JSONFormInputField | DynamicObjectSelectionInputField | DynamicFieldSelectionInputField | DateInputField | DateTimeInputField | FlowInputField;
88
+ export type InputFieldDefinition = StringInputField | DataInputField | TextInputField | PasswordInputField | BooleanInputField | CodeInputField | ConditionalInputField | ConnectionInputField | ConnectionTemplateInputField | ObjectSelectionInputField | ObjectFieldMapInputField | JSONFormInputField | DynamicObjectSelectionInputField | DynamicFieldSelectionInputField | DateInputField | DateTimeInputField | FlowInputField | StructuredObjectInputField | DynamicObjectInputField;
87
89
  export type InputCleanFunction<TValue, TResult = TValue> = (value: TValue) => TResult;
88
90
  interface BaseInputField {
89
91
  /** Name of this field to present in the UI. */
@@ -289,6 +291,48 @@ export type DateTimeInputField = BaseInputField & {
289
291
  /** Clean function. */
290
292
  clean?: InputCleanFunction<unknown>;
291
293
  } & CollectionOptions<string>;
294
+ /** `InputFieldDefinition` minus container input types; used to cap
295
+ * structuredObject nesting at one level and to enforce leaf-only positions. */
296
+ export type LeafInputFieldDefinition = Exclude<InputFieldDefinition, StructuredObjectInputField | DynamicObjectInputField>;
297
+ /** `InputFieldDefinition` minus `DynamicObjectInputField`; used inside a
298
+ * dynamicObject's `configurations.<key>.inputs` to allow leaves *and*
299
+ * structuredObject children while still rejecting nested dynamicObjects. */
300
+ export type StructuredOrLeafInputFieldDefinition = Exclude<InputFieldDefinition, DynamicObjectInputField>;
301
+ /** Groups related primitive inputs under a single named container.
302
+ * Nesting is capped at one level. */
303
+ export type StructuredObjectInputField = Omit<BaseInputField, "dataSource"> & {
304
+ /** Data type the input will collect. */
305
+ type: "structuredObject";
306
+ /** Nested input fields keyed by their local key. */
307
+ inputs: Record<string, LeafInputFieldDefinition>;
308
+ };
309
+ /** A single configuration within a dynamicObject. Each configuration declares
310
+ * a labeled set of inputs that become available when this configuration is
311
+ * selected at runtime. */
312
+ export interface DynamicObjectConfiguration {
313
+ /** Name of this configuration to present in the UI. */
314
+ label: {
315
+ key: string;
316
+ value: string;
317
+ } | string;
318
+ /** Additional text to give guidance to the user when this configuration is selected. */
319
+ comments?: string;
320
+ /** Inputs that become available when this configuration is selected. May
321
+ * include leaf inputs and structuredObject inputs; nested dynamicObjects
322
+ * are rejected at the type level. */
323
+ inputs: Record<string, StructuredOrLeafInputFieldDefinition>;
324
+ }
325
+ /** Presents a discriminated set of input groups; the user picks a configuration
326
+ * at integration-build time and that configuration's inputs become available.
327
+ * Nesting is capped: configurations may contain structuredObject children
328
+ * (depth-1) but never another dynamicObject. */
329
+ export type DynamicObjectInputField = Omit<BaseInputField, "dataSource"> & {
330
+ /** Data type the input will collect. */
331
+ type: "dynamicObject";
332
+ /** Available configurations keyed by their local key (used as the
333
+ * runtime discriminant). */
334
+ configurations: Record<string, DynamicObjectConfiguration>;
335
+ };
292
336
  /** Defines a single Choice option for a InputField. */
293
337
  export interface InputFieldChoice {
294
338
  /** Label to display for this Choice. */
@@ -19,4 +19,6 @@ exports.InputFieldDefaultMap = {
19
19
  timestamp: "",
20
20
  flow: "",
21
21
  template: "",
22
+ structuredObject: undefined,
23
+ dynamicObject: undefined,
22
24
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prismatic-io/spectral",
3
- "version": "10.18.6",
3
+ "version": "10.18.7-preview.1",
4
4
  "description": "Utility library for building Prismatic connectors and code-native integrations",
5
5
  "keywords": [
6
6
  "prismatic"