@prismatic-io/spectral 10.18.5 → 10.18.6-preview.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -68,6 +68,9 @@ exports.INPUT_TYPE_MAP = {
68
68
  timestamp: "string",
69
69
  flow: "string",
70
70
  template: "string",
71
+ // TODO: emit a typed record matching the declared children once the
72
+ // code-native action-calling type generator handles structuredObject.
73
+ structuredObject: "unknown",
71
74
  };
72
75
  const getInputValueType = (input) => {
73
76
  const inputType = exports.INPUT_TYPE_MAP[input.type];
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 { 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 { ActionDefinition, ActionPerformReturn, ComponentDefinition, ComponentManifest, ConfigPage, ConfigVarResultCollection, ConnectionConfigVar, CustomerActivatedConnectionConfigVar, DataSourceConfigVar, DataSourceDefinition, DataSourceType, DefaultConnectionDefinition, 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,27 @@ 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
+ };
515
536
  /**
516
537
  * This function creates a connection that can be used by a code-native integration
517
538
  * 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.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,24 @@ 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;
560
578
  /**
561
579
  * This function creates a connection that can be used by a code-native integration
562
580
  * or custom component. Connections define the fields (API keys, tokens, etc.) needed
@@ -1,7 +1,7 @@
1
1
  import { ComponentDefinition, ComponentHooks, ConfigVarResultCollection, ConnectionDefinition, ConnectionInput, ConnectionTemplateInputField, InputFieldDefinition, Inputs, OnPremConnectionInput, TriggerDefinition, TriggerPayload, TriggerResult } from "../types";
2
2
  import { PollingTriggerDefinition } from "../types/PollingTriggerDefinition";
3
3
  import { 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,22 @@ 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: union members don't all carry `default`/`collection`/`inputs`;
25
+ // runtime guards below handle the differences.
26
+ const _a = definition, { default: defaultValue, type, label, collection, inputs: childInputs } = _a, rest = __rest(_a, ["default", "type", "label", "collection", "inputs"]);
24
27
  const keyLabel = collection === "keyvaluelist" && typeof label === "object" ? label.key : undefined;
28
+ const nestedInputs = type === "structuredObject" && childInputs
29
+ ? Object.entries(childInputs).map(([childKey, childDef]) => (0, exports.convertInput)(childKey, childDef))
30
+ : undefined;
25
31
  return Object.assign(Object.assign({}, (0, omit_1.default)(rest, [
26
32
  "onPremControlled",
27
33
  "permissionAndVisibilityType",
28
34
  "visibleToOrgDeployer",
29
35
  "writeOnly",
30
36
  ])), { 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 });
37
+ 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
38
  };
33
39
  exports.convertInput = convertInput;
34
40
  const TEMPLATE_VALUE_REGEX = /{{#(\w+)}}/g;
@@ -73,7 +79,7 @@ exports.convertTemplateInput = convertTemplateInput;
73
79
  const convertAction = (actionKey, _a, hooks) => {
74
80
  var { inputs = {}, perform } = _a, action = __rest(_a, ["inputs", "perform"]);
75
81
  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 })), {});
82
+ const inputCleaners = Object.entries(inputs).reduce((result, [key, value]) => (Object.assign(Object.assign({}, result), { [key]: cleanerFor(value) })), {});
77
83
  return Object.assign(Object.assign({}, action), { key: actionKey, inputs: convertedInputs, perform: (0, perform_1.createPerform)(perform, {
78
84
  inputCleaners,
79
85
  errorHandler: hooks === null || hooks === void 0 ? void 0 : hooks.error,
@@ -84,17 +90,15 @@ const convertTrigger = (triggerKey, trigger, hooks) => {
84
90
  const { onInstanceDeploy, onInstanceDelete } = trigger;
85
91
  const webhookLifecycleHandlers = "webhookLifecycleHandlers" in trigger ? trigger.webhookLifecycleHandlers : undefined;
86
92
  const inputs = (_a = trigger.inputs) !== null && _a !== void 0 ? _a : {};
87
- const isPollingTrigger = (0, PollingTriggerDefinition_1.isPollingTriggerDefinition)(trigger);
88
93
  const triggerInputKeys = Object.keys(inputs);
89
94
  const convertedTriggerInputs = Object.entries(inputs).map(([key, value]) => {
90
95
  return (0, exports.convertInput)(key, value);
91
96
  });
92
- const triggerInputCleaners = Object.entries(inputs).reduce((result, [key, { clean }]) => (Object.assign(Object.assign({}, result), { [key]: clean })), {});
97
+ const triggerInputCleaners = Object.entries(inputs).reduce((result, [key, value]) => (Object.assign(Object.assign({}, result), { [key]: cleanerFor(value) })), {});
93
98
  let scheduleSupport = "scheduleSupport" in trigger ? trigger.scheduleSupport : "invalid";
94
99
  let convertedActionInputs = [];
95
100
  let performToUse;
96
- if (isPollingTrigger) {
97
- // Pull inputs up from the action and make them available on the trigger
101
+ if ((0, PollingTriggerDefinition_1.isPollingTriggerDefinition)(trigger)) {
98
102
  const { pollAction: action } = trigger;
99
103
  let actionInputCleaners = {};
100
104
  scheduleSupport = "required";
@@ -106,7 +110,7 @@ const convertTrigger = (triggerKey, trigger, hooks) => {
106
110
  accum.push((0, exports.convertInput)(key, value));
107
111
  return accum;
108
112
  }, []);
109
- actionInputCleaners = Object.entries(action.inputs).reduce((result, [key, { clean }]) => (Object.assign(Object.assign({}, result), { [key]: clean })), {});
113
+ actionInputCleaners = Object.entries(action.inputs).reduce((result, [key, value]) => (Object.assign(Object.assign({}, result), { [key]: cleanerFor(value) })), {});
110
114
  }
111
115
  const combinedCleaners = Object.assign({}, actionInputCleaners, triggerInputCleaners);
112
116
  performToUse = (0, perform_1.createPollingPerform)(trigger, {
@@ -124,7 +128,7 @@ const convertTrigger = (triggerKey, trigger, hooks) => {
124
128
  ? trigger.synchronousResponseSupport
125
129
  : scheduleSupport === "invalid"
126
130
  ? "valid"
127
- : "invalid" }), (isPollingTrigger ? { isPollingTrigger: true } : {}));
131
+ : "invalid" }), ((0, PollingTriggerDefinition_1.isPollingTriggerDefinition)(trigger) ? { isPollingTrigger: true } : {}));
128
132
  if (onInstanceDeploy) {
129
133
  result.onInstanceDeploy = (0, perform_1.createPerform)(onInstanceDeploy, {
130
134
  inputCleaners: triggerInputCleaners,
@@ -158,7 +162,7 @@ exports.convertTrigger = convertTrigger;
158
162
  const convertDataSource = (dataSourceKey, _a, hooks) => {
159
163
  var { inputs = {}, perform } = _a, dataSource = __rest(_a, ["inputs", "perform"]);
160
164
  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 })), {});
165
+ const inputCleaners = Object.entries(inputs).reduce((result, [key, value]) => (Object.assign(Object.assign({}, result), { [key]: cleanerFor(value) })), {});
162
166
  return Object.assign(Object.assign({}, dataSource), { key: dataSourceKey, inputs: convertedInputs, perform: (0, perform_1.createPerform)(perform, {
163
167
  inputCleaners,
164
168
  errorHandler: hooks === null || hooks === void 0 ? void 0 : hooks.error,
@@ -262,5 +262,7 @@ export interface Input {
262
262
  onPremiseControlled?: boolean;
263
263
  dataSource?: string;
264
264
  shown?: boolean;
265
+ /** Nested child inputs; populated only when `type === "structuredObject"`. */
266
+ inputs?: Input[];
265
267
  }
266
268
  export * from "./asyncContext";
@@ -1,11 +1,26 @@
1
1
  import type { ConditionalExpression } from "./conditional-logic";
2
- import type { Connection, InputCleanFunction, InputFieldCollection, Inputs, KeyValuePair } from "./Inputs";
2
+ import type { Connection, InputCleanFunction, InputFieldCollection, Inputs, KeyValuePair, StructuredObjectInputField } from "./Inputs";
3
+ /** Resolves a single InputFieldDefinition's runtime value type. structuredObject
4
+ * resolves to `unknown` until the per-field record-type recursion lands. */
5
+ type InputValue<T> = T extends StructuredObjectInputField ? unknown : T extends {
6
+ clean: InputCleanFunction<any>;
7
+ } ? ReturnType<T["clean"]> : T extends {
8
+ type: "connection";
9
+ collection?: InputFieldCollection;
10
+ } ? ExtractValue<Connection, T["collection"]> : T extends {
11
+ type: "conditional";
12
+ collection?: InputFieldCollection;
13
+ } ? ExtractValue<ConditionalExpression, T["collection"]> : T extends {
14
+ default?: unknown;
15
+ collection?: InputFieldCollection;
16
+ } ? ExtractValue<T["default"], T["collection"]> : unknown;
3
17
  /**
4
18
  * Collection of input parameters.
5
19
  * Inputs can be static values, references to config variables, or
6
20
  * references to previous steps' outputs.
7
21
  */
8
22
  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"]>;
23
+ [Property in keyof TInputs]: InputValue<TInputs[Property]>;
10
24
  };
11
25
  export type ExtractValue<TType, TCollection extends InputFieldCollection | undefined> = TCollection extends "keyvaluelist" ? KeyValuePair<TType>[] : TCollection extends "valuelist" ? TType[] : TType;
26
+ export {};
@@ -83,7 +83,7 @@ export type OnPremConnectionInput = {
83
83
  */
84
84
  onPremControlled: true;
85
85
  } & ConnectionInput;
86
- export type InputFieldDefinition = StringInputField | DataInputField | TextInputField | PasswordInputField | BooleanInputField | CodeInputField | ConditionalInputField | ConnectionInputField | ConnectionTemplateInputField | ObjectSelectionInputField | ObjectFieldMapInputField | JSONFormInputField | DynamicObjectSelectionInputField | DynamicFieldSelectionInputField | DateInputField | DateTimeInputField | FlowInputField;
86
+ export type InputFieldDefinition = StringInputField | DataInputField | TextInputField | PasswordInputField | BooleanInputField | CodeInputField | ConditionalInputField | ConnectionInputField | ConnectionTemplateInputField | ObjectSelectionInputField | ObjectFieldMapInputField | JSONFormInputField | DynamicObjectSelectionInputField | DynamicFieldSelectionInputField | DateInputField | DateTimeInputField | FlowInputField | StructuredObjectInputField;
87
87
  export type InputCleanFunction<TValue, TResult = TValue> = (value: TValue) => TResult;
88
88
  interface BaseInputField {
89
89
  /** Name of this field to present in the UI. */
@@ -289,6 +289,17 @@ export type DateTimeInputField = BaseInputField & {
289
289
  /** Clean function. */
290
290
  clean?: InputCleanFunction<unknown>;
291
291
  } & CollectionOptions<string>;
292
+ /** `InputFieldDefinition` minus `StructuredObjectInputField`; used to cap
293
+ * structuredObject nesting at one level. */
294
+ export type LeafInputFieldDefinition = Exclude<InputFieldDefinition, StructuredObjectInputField>;
295
+ /** Groups related primitive inputs under a single named container.
296
+ * Nesting is capped at one level. */
297
+ export type StructuredObjectInputField = Omit<BaseInputField, "dataSource"> & {
298
+ /** Data type the input will collect. */
299
+ type: "structuredObject";
300
+ /** Nested input fields keyed by their local key. */
301
+ inputs: Record<string, LeafInputFieldDefinition>;
302
+ };
292
303
  /** Defines a single Choice option for a InputField. */
293
304
  export interface InputFieldChoice {
294
305
  /** Label to display for this Choice. */
@@ -19,4 +19,5 @@ exports.InputFieldDefaultMap = {
19
19
  timestamp: "",
20
20
  flow: "",
21
21
  template: "",
22
+ structuredObject: undefined,
22
23
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prismatic-io/spectral",
3
- "version": "10.18.5",
3
+ "version": "10.18.6-preview.0",
4
4
  "description": "Utility library for building Prismatic connectors and code-native integrations",
5
5
  "keywords": [
6
6
  "prismatic"