ngx-t-forms-types 0.0.30 → 0.0.33

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/dist/interfaces/Form/formSubmissionHandleInterface.d.ts +6 -0
  2. package/dist/interfaces/FormBuilder/DefaultEelement.js +76 -0
  3. package/dist/interfaces/FormBuilder/DefaultInputConfigInterface.d.ts +13 -0
  4. package/dist/interfaces/FormBuilder/FormInputKeys.d.ts +6 -0
  5. package/dist/interfaces/FormBuilder/FormInputKeys.js +6 -0
  6. package/dist/interfaces/FormBuilder/inputConfig/ElementEditConfig.js +188 -3
  7. package/dist/interfaces/formInput/APIDataFetchingConfigurationInterface.d.ts +34 -0
  8. package/dist/interfaces/formInput/BasicFormInputInterface.d.ts +1 -0
  9. package/dist/interfaces/formInput/BasicFormInputInterface.js +1 -0
  10. package/dist/interfaces/formInput/IMscoaAccount.d.ts +19 -3
  11. package/dist/interfaces/formInput/ISelectInputInterface.d.ts +12 -0
  12. package/dist/interfaces/formInput/MultipleInterface.d.ts +10 -0
  13. package/dist/interfaces/formInput/WorkflowDocumentPicker.d.ts +2 -0
  14. package/dist/schemas/FormInputSchema.js +41 -2
  15. package/dist/schemas/MatOptionsSchema.js +7 -0
  16. package/dist/schemas/MscoaConfigSchema.js +1 -0
  17. package/dist/schemas/index.d.ts +2 -1
  18. package/dist/schemas/index.js +2 -1
  19. package/dist/skillet/authoring-rules.d.ts +41 -0
  20. package/dist/skillet/authoring-rules.js +61 -0
  21. package/dist/skillet/extra-members.d.ts +143 -0
  22. package/dist/skillet/extra-members.js +79 -0
  23. package/dist/skillet/form.d.ts +170 -0
  24. package/dist/skillet/form.js +139 -0
  25. package/dist/skillet/index.d.ts +43 -0
  26. package/dist/skillet/index.js +46 -0
  27. package/dist/skillet/input-members.d.ts +375 -0
  28. package/dist/skillet/input-members.js +186 -0
  29. package/dist/skillet/internal/coupling.d.ts +63 -0
  30. package/dist/skillet/internal/coupling.js +69 -0
  31. package/dist/skillet/internal/editor-guidance.d.ts +64 -0
  32. package/dist/skillet/internal/editor-guidance.js +291 -0
  33. package/dist/skillet/members/calculated-field.d.ts +155 -0
  34. package/dist/skillet/members/calculated-field.js +105 -0
  35. package/dist/skillet/members/conditional.d.ts +69 -0
  36. package/dist/skillet/members/conditional.js +16 -0
  37. package/dist/skillet/members/document-picker.d.ts +182 -0
  38. package/dist/skillet/members/document-picker.js +111 -0
  39. package/dist/skillet/members/mat-options.d.ts +187 -0
  40. package/dist/skillet/members/mat-options.js +92 -0
  41. package/dist/skillet/members/mscoa.d.ts +182 -0
  42. package/dist/skillet/members/mscoa.js +129 -0
  43. package/dist/skillet/members/pagination.d.ts +59 -0
  44. package/dist/skillet/members/pagination.js +16 -0
  45. package/dist/skillet/members/table.d.ts +178 -0
  46. package/dist/skillet/members/table.js +105 -0
  47. package/dist/skillet/members/validators.d.ts +197 -0
  48. package/dist/skillet/members/validators.js +74 -0
  49. package/dist/skillet/members/value.d.ts +154 -0
  50. package/dist/skillet/members/value.js +97 -0
  51. package/dist/skillet/shared-types.d.ts +57 -0
  52. package/dist/skillet/shared-types.js +69 -0
  53. package/dist/skillet/tests/house-rules.spec.d.ts +1 -0
  54. package/dist/skillet/tests/house-rules.spec.js +162 -0
  55. package/dist/skillet/tests/skillet-coupling.spec.d.ts +1 -0
  56. package/dist/skillet/tests/skillet-coupling.spec.js +191 -0
  57. package/dist/skillet/tests/variant-assembly.spec.d.ts +1 -0
  58. package/dist/skillet/tests/variant-assembly.spec.js +643 -0
  59. package/dist/skillet/variants.d.ts +138 -0
  60. package/dist/skillet/variants.js +536 -0
  61. package/dist/skillet/workflow-context.d.ts +95 -0
  62. package/dist/skillet/workflow-context.js +128 -0
  63. package/package.json +78 -60
@@ -5,6 +5,8 @@ import { IBasicFormInput } from "./BasicFormInputInterface.js";
5
5
  export interface IWorkflowDocumentPicker extends IBasicFormInput {
6
6
  workflowPickerConfig: IWorkflowDocumentPickerConfig;
7
7
  [AllFormInputPrimaryKeys.AllowMultipleSelection]: boolean;
8
+ /** @see ISelectInputInterface.selectUpto */
9
+ selectUpto?: number;
8
10
  }
9
11
  /**
10
12
  * Document-picker configuration.
@@ -1,6 +1,6 @@
1
1
  import Joi from 'joi';
2
- import { AllFormInputPrimaryKeys, SpecialElementKeys } from '../interfaces/FormBuilder/index.js';
3
- import { AdjudicationSteps, AutocapitalizeOptions, ElementTypes, InputDataTypes, InputPipeTypes, InputTypes } from '../interfaces/formInput/index.js';
2
+ import { AllFormInputPrimaryKeys, FormInputKeys, SpecialElementKeys } from '../interfaces/FormBuilder/index.js';
3
+ import { AdjudicationSteps, AutocapitalizeOptions, AutocompleteOptions, ElementTypes, InputDataTypes, InputPipeTypes, InputTypes } from '../interfaces/formInput/index.js';
4
4
  // import { InputFileType } from '../interfaces/formInput/FileUploadInputInterface.js';
5
5
  // import { LabelPosition } from '../interfaces/formInput/ToggleInputInterface.js';
6
6
  // import { MscoaInputConfigSchema } from './MscoaConfigSchema.js';
@@ -49,6 +49,45 @@ export const baseFormColumnInputsSchema = Joi.object({
49
49
  [AllFormInputPrimaryKeys.Max]: Joi.alternatives().try(Joi.number(), Joi.string(), Joi.date()).optional(),
50
50
  [AllFormInputPrimaryKeys.MinLength]: Joi.alternatives().try(Joi.number(), Joi.string()).optional(),
51
51
  [AllFormInputPrimaryKeys.MaxLength]: Joi.alternatives().try(Joi.number(), Joi.string()).optional(),
52
+ [FormInputKeys.Pattern]: Joi.string().allow('').optional(),
53
+ // --- presentation members declared on IBasicFormInput ----------------------
54
+ //
55
+ // These were declared on the interfaces and listed in DefaultInputConfig, but
56
+ // never here — and because Joi rejects unknown keys, a column carrying one
57
+ // failed the WHOLE form with '"Slides > Columns > Placeholder" is not
58
+ // allowed'. Empty strings are allowed throughout: the settings panel writes
59
+ // '' when an author clears a text row, and rejecting that made clearing a
60
+ // prefix a validation error.
61
+ [FormInputKeys.Placeholder]: Joi.string().allow('').optional(),
62
+ [FormInputKeys.Autocomplete]: Joi.string().valid(...Object.values(AutocompleteOptions)).optional(),
63
+ [FormInputKeys.Disabled]: Joi.boolean().optional(),
64
+ [FormInputKeys.PrefixText]: Joi.string().allow('').optional(),
65
+ [FormInputKeys.SuffixText]: Joi.string().allow('').optional(),
66
+ [FormInputKeys.PrefixIcon]: Joi.string().allow('').optional(),
67
+ [FormInputKeys.SuffixIcon]: Joi.string().allow('').optional(),
68
+ // Only meaningful alongside allowMultipleSelection; a single-selection
69
+ // control is already capped at one. `min(1)` because "select up to zero" is
70
+ // not a limit, it is a disabled control.
71
+ [FormInputKeys.SelectUpto]: Joi.number().integer().min(1).optional(),
72
+ // formControlNames of columns inside a multipleInput group to total.
73
+ [FormInputKeys.ShowTotalsOf]: Joi.array().items(Joi.string()).optional(),
74
+ // --- matrix table ---------------------------------------------------------
75
+ //
76
+ // Declared by IMatrixInput and accepted here so a stored form carrying either
77
+ // still validates. No element offers them: ElementTypes.MatrixTable is
78
+ // commented out of the enum, so nothing can currently be built with one.
79
+ //
80
+ // `columnsConfig` is keyed by column name and typed
81
+ // `TableColumnConfigInterface | any`, so its values are only checked to be
82
+ // objects — constraining them further here would reject the `any` half the
83
+ // interface explicitly permits.
84
+ [FormInputKeys.MatrixTableConfig]: Joi.object({
85
+ dataSource: Joi.string().required()
86
+ }).optional(),
87
+ [FormInputKeys.TableConfig]: Joi.object({
88
+ displayedColumnsInOrder: Joi.array().items(Joi.string()).required(),
89
+ columnsConfig: Joi.object().pattern(Joi.string(), Joi.object()).required()
90
+ }).optional(),
52
91
  [AllFormInputPrimaryKeys.LinkedSegmentId]: Joi.string().optional(),
53
92
  [AllFormInputPrimaryKeys.MscoaConfig]: MscoaInputConfigSchema.optional(),
54
93
  [AllFormInputPrimaryKeys.SystemDefault]: Joi.boolean().optional(),
@@ -59,6 +59,13 @@ const APIDataFetchingConfigurationSchema = Joi.object({
59
59
  capturedQuery: queryTemplateSchema.optional(),
60
60
  // The endpoint's Postman description, verbatim; display-only (Docs tab).
61
61
  capturedDocs: Joi.string().allow('').optional(),
62
+ // Opt-out of the automatic read-only lock on a value the tower owns. On a
63
+ // SCALAR it is gap-filling on an 'api' slot: a manually entered value stands
64
+ // whenever the fetch contributes nothing. On a COMPLEX value (the input
65
+ // declares dataType 'object' or 'array') it is also offered on a 'local'
66
+ // slot, and the tower re-merges each new derived value over the live one as a
67
+ // delta instead of replacing it. Only meaningful on a value slot.
68
+ allowManualValueEntry: Joi.boolean().optional(),
62
69
  backEndConfig: Joi.object({
63
70
  // Optional: a 'template'-mode fetch shapes its body from payloadTemplate and
64
71
  // carries no mapping; GET fetches never had one. Readers default it to [].
@@ -16,6 +16,7 @@ export const DualCashExclusionRuleSchema = Joi.object({
16
16
  id: Joi.string().optional(),
17
17
  pattern: Joi.string().required(),
18
18
  flags: Joi.string().allow('').optional(),
19
+ matchField: Joi.string().allow('').optional(),
19
20
  segment: Joi.string().allow('').optional(),
20
21
  description: Joi.string().allow('').optional()
21
22
  });
@@ -1,4 +1,5 @@
1
1
  import { validateCalculatedFieldRules } from "./CalculatedFieldRulesSchema.js";
2
2
  import { formColumnInputsSchema, validateFormColumnInputs, validateFormColumnInputsWithRequired } from "./FormInputSchema.js";
3
3
  import { DatabaseFormSchema, FormSchema, validateApiDataFetchingConfiguration, validateForm, validateFormSlide } from "./FormSchema.js";
4
- export { FormSchema, DatabaseFormSchema, formColumnInputsSchema, validateCalculatedFieldRules, validateFormColumnInputs, validateFormSlide, validateFormColumnInputsWithRequired, validateForm, validateApiDataFetchingConfiguration };
4
+ import { MscoaInputConfigSchema, validateMscoaInputConfig } from "./MscoaConfigSchema.js";
5
+ export { FormSchema, DatabaseFormSchema, formColumnInputsSchema, validateCalculatedFieldRules, validateFormColumnInputs, validateFormSlide, validateFormColumnInputsWithRequired, validateForm, validateApiDataFetchingConfiguration, MscoaInputConfigSchema, validateMscoaInputConfig };
@@ -1,4 +1,5 @@
1
1
  import { validateCalculatedFieldRules } from "./CalculatedFieldRulesSchema.js";
2
2
  import { formColumnInputsSchema, validateFormColumnInputs, validateFormColumnInputsWithRequired } from "./FormInputSchema.js";
3
3
  import { DatabaseFormSchema, FormSchema, validateApiDataFetchingConfiguration, validateForm, validateFormSlide } from "./FormSchema.js";
4
- export { FormSchema, DatabaseFormSchema, formColumnInputsSchema, validateCalculatedFieldRules, validateFormColumnInputs, validateFormSlide, validateFormColumnInputsWithRequired, validateForm, validateApiDataFetchingConfiguration };
4
+ import { MscoaInputConfigSchema, validateMscoaInputConfig } from "./MscoaConfigSchema.js";
5
+ export { FormSchema, DatabaseFormSchema, formColumnInputsSchema, validateCalculatedFieldRules, validateFormColumnInputs, validateFormSlide, validateFormColumnInputsWithRequired, validateForm, validateApiDataFetchingConfiguration, MscoaInputConfigSchema, validateMscoaInputConfig };
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Form-wide authoring rules from the Form Creation Guide, stated once.
3
+ *
4
+ * ## Why these are not on the members they concern
5
+ *
6
+ * Hashbrown names every hoisted `$defs` entry by camel-casing the node's
7
+ * DESCRIPTION, and every `$ref` repeats that name in full. A member shared by
8
+ * every element — `label`, `formControlName`, `colSize` — is referenced once
9
+ * per element per nesting level, so each character of its description is paid
10
+ * around forty times in the full column schema. Measured before this split,
11
+ * `$ref` names were 58% of the full schema and 44% of the common one, and the
12
+ * seven most-shared members accounted for most of that.
13
+ *
14
+ * So a shared member's description carries its definition and the one rule
15
+ * that has to be read at that member, and the guidance that applies across the
16
+ * form is stated here, on the root, which is emitted exactly once. The
17
+ * sentences are the guide's — see `doc/features/skillet-internals.md`, "Where
18
+ * the prose comes from" — and they are the ones a model needs before it writes
19
+ * any field rather than while it writes one.
20
+ *
21
+ * `createFormDraftSchema()` composes these into the form's description. A
22
+ * caller using `createColumnSchema()` on its own has no root to carry them and
23
+ * should put {@link describeAuthoringRules} in the system prompt instead.
24
+ */
25
+ /**
26
+ * The shape of a control name: lowerCamelCase, letters and digits only.
27
+ *
28
+ * Narrower than the engine, which also allows underscores — narrower is the
29
+ * permitted direction, and one convention is easier to follow than two.
30
+ * Exported so a test can hold the reserved-names rule to it: a reserved name
31
+ * the pattern would accept must be named in the rules, and one it rejects
32
+ * need not be.
33
+ */
34
+ export declare const CONTROL_NAME_PATTERN = "^[a-z][a-zA-Z0-9]*$";
35
+ /**
36
+ * The rules, one sentence group each, in the order the guide states them:
37
+ * naming, words, types, what the engine reads, layout, error timing.
38
+ */
39
+ export declare const AUTHORING_RULES: readonly string[];
40
+ /** The rules as one paragraph, for a form description or a system prompt. */
41
+ export declare function describeAuthoringRules(): string;
@@ -0,0 +1,61 @@
1
+ import { RESERVED_CONTROL_NAMES } from './workflow-context.js';
2
+ /**
3
+ * Form-wide authoring rules from the Form Creation Guide, stated once.
4
+ *
5
+ * ## Why these are not on the members they concern
6
+ *
7
+ * Hashbrown names every hoisted `$defs` entry by camel-casing the node's
8
+ * DESCRIPTION, and every `$ref` repeats that name in full. A member shared by
9
+ * every element — `label`, `formControlName`, `colSize` — is referenced once
10
+ * per element per nesting level, so each character of its description is paid
11
+ * around forty times in the full column schema. Measured before this split,
12
+ * `$ref` names were 58% of the full schema and 44% of the common one, and the
13
+ * seven most-shared members accounted for most of that.
14
+ *
15
+ * So a shared member's description carries its definition and the one rule
16
+ * that has to be read at that member, and the guidance that applies across the
17
+ * form is stated here, on the root, which is emitted exactly once. The
18
+ * sentences are the guide's — see `doc/features/skillet-internals.md`, "Where
19
+ * the prose comes from" — and they are the ones a model needs before it writes
20
+ * any field rather than while it writes one.
21
+ *
22
+ * `createFormDraftSchema()` composes these into the form's description. A
23
+ * caller using `createColumnSchema()` on its own has no root to carry them and
24
+ * should put {@link describeAuthoringRules} in the system prompt instead.
25
+ */
26
+ /**
27
+ * The shape of a control name: lowerCamelCase, letters and digits only.
28
+ *
29
+ * Narrower than the engine, which also allows underscores — narrower is the
30
+ * permitted direction, and one convention is easier to follow than two.
31
+ * Exported so a test can hold the reserved-names rule to it: a reserved name
32
+ * the pattern would accept must be named in the rules, and one it rejects
33
+ * need not be.
34
+ */
35
+ export const CONTROL_NAME_PATTERN = '^[a-z][a-zA-Z0-9]*$';
36
+ /**
37
+ * The reserved names the pattern alone does not stop.
38
+ *
39
+ * `_id` and the `SYSTEM_*` inputs fail the pattern and need no mention;
40
+ * `reference`, `status` and `data` pass it, so the rule has to carry them.
41
+ * Filtered at evaluation rather than listed by hand, so the sentence says
42
+ * exactly what the pattern leaves open — no more, which would be noise, and no
43
+ * less, which would be a hole.
44
+ */
45
+ const RESERVED_WELL_FORMED_NAMES = RESERVED_CONTROL_NAMES.filter((name) => new RegExp(CONTROL_NAME_PATTERN).test(name));
46
+ /**
47
+ * The rules, one sentence group each, in the order the guide states them:
48
+ * naming, words, types, what the engine reads, layout, error timing.
49
+ */
50
+ export const AUTHORING_RULES = [
51
+ `Control names are unique across the whole form and across every other form of the same workflow unless the same answer is deliberately carried forward, never change once the form is live, and are never one of the names the transaction document already owns: ${RESERVED_WELL_FORMED_NAMES.join(', ')}.`,
52
+ "A label never explains — that is the hint's job. Required fields are marked automatically, so add '(optional)' to the label of a field that is not required. A hint gives the format ('As it appears on your ID document, 13 digits'), the source ('Top right of the invoice, starts with INV') or the reason for asking something sensitive ('Used only to send delivery updates by SMS'); every field that could be misunderstood gets one.",
53
+ 'Set type and dataType to the data. A number is never left as text: the engine compares strictly, so a number stored as text never equals a number. A phone number is type tel with dataType string.',
54
+ 'A review decision toggle, a date the engine schedules on and any value a decision gate reads are always required and never conditionally hidden.',
55
+ 'Related short values share one row (start and end as 6 and 6; quantity, unit price and line total as 4, 4 and 4); a textarea, an item list, a picker, an uploader or a signature never shares a row; the same kind of field keeps the same width all the way down a slide.',
56
+ 'Errors are shown only after the user has left a field, so onlySetTempErrorOnTouch is true on nearly every field.',
57
+ ];
58
+ /** The rules as one paragraph, for a form description or a system prompt. */
59
+ export function describeAuthoringRules() {
60
+ return AUTHORING_RULES.join(' ');
61
+ }
@@ -0,0 +1,143 @@
1
+ import { s } from '@hashbrownai/core';
2
+ import type { FormColumnInputs } from '../interfaces/Form/index.js';
3
+ import { FormInputKeys, SpecialElementKeys } from '../interfaces/FormBuilder/FormInputKeys.js';
4
+ import { AssertNever } from './internal/coupling.js';
5
+ import { type TableConfigDraft } from './members/table.js';
6
+ /**
7
+ * The members an element can carry that `AllFormInputPrimaryKeys` does not
8
+ * declare.
9
+ *
10
+ * `DefaultInputConfig[element].properties` is typed
11
+ * `Array<FormInputKeys | SpecialElementKeys | AllFormInputPrimaryKeys>`, and it
12
+ * uses all three. Keying the main registry on `AllFormInputPrimaryKeys` alone
13
+ * left fourteen keys unresolvable at assembly time, including `pattern` and
14
+ * `placeholder` — properties too ordinary for a form generator to do without.
15
+ *
16
+ * ## `properties` is not a property list
17
+ *
18
+ * It is the list of ROWS the settings panel shows for that element, which is a
19
+ * superset of what the input stores. `matOptionsApiCall` and
20
+ * `showAllMcoaSegments` open editors; they are not keys on a form input and no
21
+ * interface declares them. Those are recorded in {@link EDITOR_ONLY_KEYS} and
22
+ * skipped during assembly — absent by intent, not by oversight.
23
+ *
24
+ * Enum membership does not decide this, which is worth stating because it looks
25
+ * like it should: `multipleInputAvailableOperations` sits in
26
+ * `SpecialElementKeys` beside the editor directives, yet `IMultiple` really
27
+ * does declare it. The test that settles it is whether an interface declares
28
+ * the key, so that is the test used.
29
+ */
30
+ /** The type an extra member must produce, read off the real interface. */
31
+ type MemberValue<K extends string> = K extends keyof FormColumnInputs ? NonNullable<FormColumnInputs[K]> : unknown;
32
+ /**
33
+ * Keys that open an editor rather than store a value. They appear in
34
+ * `properties` and must never appear in a generation schema.
35
+ */
36
+ export declare const EDITOR_ONLY_KEYS: readonly [SpecialElementKeys.FormValueFromInputSelector, SpecialElementKeys.FormInputSelector, SpecialElementKeys.MatOptionsApiCall, SpecialElementKeys.MatOptionsRequiredInputs, SpecialElementKeys.MatOptionsApiValueAccessRules, SpecialElementKeys.DefaultCalculatedFieldRules, SpecialElementKeys.MatOptionsItemType, SpecialElementKeys.MatOptionsSelectionOptions, SpecialElementKeys.DefaultValuePipe, SpecialElementKeys.DefaultCurrencySelect, SpecialElementKeys.DefaultDecimalNumberInput, SpecialElementKeys.Default, SpecialElementKeys.ShowAllMcoaSegments];
37
+ /**
38
+ * Extra members still to be modelled.
39
+ *
40
+ * The four date bounds are all typed `Date`. A model emits JSON, so the best it
41
+ * can produce is an ISO string, which is not assignable to `Date` — they need
42
+ * the same draft-and-expand treatment as `matOptions` rather than a quiet
43
+ * mistyping. `tableConfig` and `matrixTableConfig` are nested configuration
44
+ * objects awaiting their own modules.
45
+ */
46
+ export declare const PENDING_EXTRA_MEMBERS: readonly [FormInputKeys.StartMinDate, FormInputKeys.StartMaxDate, FormInputKeys.EndMinDate, FormInputKeys.EndMaxDate];
47
+ /**
48
+ * Extra members whose schema produces an AUTHORING DRAFT rather than the stored
49
+ * shape — the same category `DRAFT_INPUT_MEMBERS` defines in
50
+ * `input-members.ts`, for keys that live in the other two enums.
51
+ *
52
+ * `tableConfig` is the only one. Its `columnsConfig` is keyed by column name —
53
+ * an index signature, which Skillet has no node for — so the model emits an
54
+ * ARRAY of columns each carrying its own key, and the application folds that
55
+ * into the record. See `members/table.ts`.
56
+ */
57
+ export declare const DRAFT_EXTRA_MEMBERS: readonly [FormInputKeys.TableConfig];
58
+ /** The draft each drafted extra member is held to. */
59
+ interface ExtraMemberDrafts {
60
+ [FormInputKeys.TableConfig]: TableConfigDraft;
61
+ }
62
+ export declare const extraDraftMemberSchemas: {
63
+ tableConfig: s.ObjectType<{
64
+ displayedColumnsInOrder: s.ArrayType<s.StringType>;
65
+ columns: s.ArrayType<s.ObjectType<{
66
+ key: s.StringType;
67
+ type: s.EnumType<["caluculated", "property", "checkBox", "primaryKey"]>;
68
+ property: s.StringType;
69
+ label: s.StringType;
70
+ inEdit: s.BooleanType;
71
+ checkUpto: s.StringType;
72
+ calculatedFieldRules: s.ObjectType<{
73
+ formula: s.StringType;
74
+ variables: s.ArrayType<import("@hashbrownai/core/src/schema/base").SchemaForUnion<{
75
+ bindingType: "field";
76
+ variable: string;
77
+ label: string;
78
+ formControlName: string;
79
+ } | {
80
+ bindingType: "listAggregate";
81
+ variable: string;
82
+ label: string;
83
+ formControlName: string;
84
+ parentInputFormControl: string;
85
+ function: import("..").CalculationFunctions;
86
+ applyFunctionToCol: string;
87
+ applyFunctionToLabel: string | null;
88
+ filterValuesByCol: string | null;
89
+ filterValuesByThisColLabel: string | null;
90
+ tableCell: boolean | null;
91
+ }>>;
92
+ decimalPlaces: import("@hashbrownai/core/src/schema/base").SchemaForUnion<number | null>;
93
+ roundingMode: import("@hashbrownai/core/src/schema/base").SchemaForUnion<"FLOOR" | "CEIL" | "ROUND" | null>;
94
+ getFormulaFromAFormInput: import("@hashbrownai/core/src/schema/base").SchemaForUnion<boolean | null>;
95
+ formControlWithFormula: import("@hashbrownai/core/src/schema/base").SchemaForUnion<string | null>;
96
+ }>;
97
+ reductionFunction: import("@hashbrownai/core/src/schema/base").SchemaForUnion<"sum" | null>;
98
+ colorScale: import("@hashbrownai/core/src/schema/base").SchemaForUnion<string | null>;
99
+ }>>;
100
+ }>;
101
+ };
102
+ export declare const extraInputMemberSchemas: {
103
+ pattern: s.StringType;
104
+ placeholder: s.StringType;
105
+ autocomplete: s.EnumType<import("..").AutocompleteOptions[]>;
106
+ disabled: s.BooleanType;
107
+ prefixText: s.StringType;
108
+ suffixText: s.StringType;
109
+ prefixIcon: s.StringType;
110
+ suffixIcon: s.StringType;
111
+ selectUpto: s.IntegerType;
112
+ showTotalsOf: s.ArrayType<s.StringType>;
113
+ multipleInputAvailableOperations: s.ArrayType<s.EnumType<import("..").MultipleInputAvailableOperations[]>>;
114
+ matrixTableConfig: s.ObjectType<{
115
+ dataSource: s.StringType;
116
+ }>;
117
+ };
118
+ export type ExtraMemberKey = keyof typeof extraInputMemberSchemas;
119
+ type EditorOnlyKey = (typeof EDITOR_ONLY_KEYS)[number];
120
+ type PendingExtraKey = (typeof PENDING_EXTRA_MEMBERS)[number];
121
+ type DraftExtraKey = (typeof DRAFT_EXTRA_MEMBERS)[number];
122
+ /**
123
+ * Every `FormInputKeys` and `SpecialElementKeys` member is accounted for —
124
+ * modelled, deferred, declared editor-only, or already covered by the primary
125
+ * registry because both enums spell the same key.
126
+ */
127
+ export type _EveryExtraKeyClassified = AssertNever<Exclude<FormInputKeys | SpecialElementKeys, ExtraMemberKey | EditorOnlyKey | PendingExtraKey | DraftExtraKey | FormInputKeys.Accept | FormInputKeys.ConditionalInputConfig | FormInputKeys.GroupBy>>;
128
+ /** Every extra node produces a value its interface member can hold. */
129
+ export type _NoExtraValueDrift = AssertNever<{
130
+ [K in ExtraMemberKey]: [
131
+ s.Infer<(typeof extraInputMemberSchemas)[K]>
132
+ ] extends [MemberValue<K>] ? never : K;
133
+ }[ExtraMemberKey]>;
134
+ /** Every drafted extra node produces the draft it declares. */
135
+ export type _NoExtraDraftDrift = AssertNever<{
136
+ [K in DraftExtraKey]: [
137
+ s.Infer<(typeof extraDraftMemberSchemas)[K]>
138
+ ] extends [ExtraMemberDrafts[K]] ? never : K;
139
+ }[DraftExtraKey]>;
140
+ /** Runtime key lists, derived from the enums. */
141
+ export declare const ALL_FORM_INPUT_KEYS: FormInputKeys[];
142
+ export declare const ALL_SPECIAL_ELEMENT_KEYS: SpecialElementKeys[];
143
+ export {};
@@ -0,0 +1,79 @@
1
+ import { s } from '@hashbrownai/core';
2
+ import { FormInputKeys, SpecialElementKeys, } from '../interfaces/FormBuilder/FormInputKeys.js';
3
+ import { enumValues } from './internal/coupling.js';
4
+ import { describe } from './internal/editor-guidance.js';
5
+ import { autocompleteSchema, multipleInputOperationSchema } from './shared-types.js';
6
+ import { matrixTableConfigSchema, tableConfigSchema, } from './members/table.js';
7
+ /**
8
+ * Keys that open an editor rather than store a value. They appear in
9
+ * `properties` and must never appear in a generation schema.
10
+ */
11
+ export const EDITOR_ONLY_KEYS = [
12
+ SpecialElementKeys.FormValueFromInputSelector,
13
+ SpecialElementKeys.FormInputSelector,
14
+ SpecialElementKeys.MatOptionsApiCall,
15
+ SpecialElementKeys.MatOptionsRequiredInputs,
16
+ SpecialElementKeys.MatOptionsApiValueAccessRules,
17
+ SpecialElementKeys.DefaultCalculatedFieldRules,
18
+ SpecialElementKeys.MatOptionsItemType,
19
+ SpecialElementKeys.MatOptionsSelectionOptions,
20
+ SpecialElementKeys.DefaultValuePipe,
21
+ SpecialElementKeys.DefaultCurrencySelect,
22
+ SpecialElementKeys.DefaultDecimalNumberInput,
23
+ SpecialElementKeys.Default,
24
+ SpecialElementKeys.ShowAllMcoaSegments,
25
+ ];
26
+ /**
27
+ * Extra members still to be modelled.
28
+ *
29
+ * The four date bounds are all typed `Date`. A model emits JSON, so the best it
30
+ * can produce is an ISO string, which is not assignable to `Date` — they need
31
+ * the same draft-and-expand treatment as `matOptions` rather than a quiet
32
+ * mistyping. `tableConfig` and `matrixTableConfig` are nested configuration
33
+ * objects awaiting their own modules.
34
+ */
35
+ export const PENDING_EXTRA_MEMBERS = [
36
+ FormInputKeys.StartMinDate,
37
+ FormInputKeys.StartMaxDate,
38
+ FormInputKeys.EndMinDate,
39
+ FormInputKeys.EndMaxDate,
40
+ ];
41
+ /**
42
+ * Extra members whose schema produces an AUTHORING DRAFT rather than the stored
43
+ * shape — the same category `DRAFT_INPUT_MEMBERS` defines in
44
+ * `input-members.ts`, for keys that live in the other two enums.
45
+ *
46
+ * `tableConfig` is the only one. Its `columnsConfig` is keyed by column name —
47
+ * an index signature, which Skillet has no node for — so the model emits an
48
+ * ARRAY of columns each carrying its own key, and the application folds that
49
+ * into the record. See `members/table.ts`.
50
+ */
51
+ export const DRAFT_EXTRA_MEMBERS = [FormInputKeys.TableConfig];
52
+ export const extraDraftMemberSchemas = {
53
+ [FormInputKeys.TableConfig]: tableConfigSchema,
54
+ };
55
+ export const extraInputMemberSchemas = {
56
+ [FormInputKeys.Pattern]: s.string(describe("A regular expression the typed value must match, as a JavaScript pattern without delimiters. Only for a code with a fixed shape that nothing looks up, such as an ID number or an order reference; never on a lookup key such as a supplier number, where the endpoint's error is the check.", FormInputKeys.Pattern)),
57
+ // Each authored sentence below is the DEFINITION only. The advice that goes
58
+ // with it — give an example, turn autofill off for one-time values, when a
59
+ // selection cap applies at all — is written once, on the editor row, and
60
+ // composed in by `describe()`. Saying it in both places produced descriptions
61
+ // that made the same point twice in slightly different words.
62
+ [FormInputKeys.Placeholder]: s.string(describe('Ghost text shown inside the field while it is empty. Prefer none: it disappears as the user types and screen readers may skip it, so anything that matters belongs in the hint.', FormInputKeys.Placeholder)),
63
+ [FormInputKeys.Autocomplete]: autocompleteSchema,
64
+ [FormInputKeys.Disabled]: s.boolean(describe('Whether the control is rendered but cannot be interacted with.', FormInputKeys.Disabled)),
65
+ [FormInputKeys.PrefixText]: s.string(describe('Short static text shown before the field, for example a currency symbol. It stops the user typing the unit into the box.', FormInputKeys.PrefixText)),
66
+ [FormInputKeys.SuffixText]: s.string(describe('Short static text shown after the field, for example a unit such as kg or %. It stops the user typing the unit into the box.', FormInputKeys.SuffixText)),
67
+ [FormInputKeys.PrefixIcon]: s.string(describe('Name of the Material icon shown before the field.', FormInputKeys.PrefixIcon)),
68
+ [FormInputKeys.SuffixIcon]: s.string(describe('Name of the Material icon shown after the field.', FormInputKeys.SuffixIcon)),
69
+ // The applicability rule is the valuable half here: the editor row declares
70
+ // `allowMultipleSelection === true`, and Skillet cannot express that
71
+ // structurally, so it arrives as the sentence a model actually needs.
72
+ [FormInputKeys.SelectUpto]: s.integer(describe('The most options the user may choose at once.', FormInputKeys.SelectUpto), { minimum: 1 }),
73
+ [FormInputKeys.ShowTotalsOf]: s.array(describe("The formControlNames of columns inside this list whose values are summed and shown as a total. For the user's eyes only: a total used anywhere else must also be a calculated field on the form itself.", FormInputKeys.ShowTotalsOf), s.string('A formControlName inside this list to total.')),
74
+ [SpecialElementKeys.MultipleInputAvailableOperations]: s.array(describe("Which operations the user may perform on the rows of this repeatable group: usually 'add', 'remove' and 'update'; add 'lockEditOnFormSubmit' when rows must not change once submitted.", SpecialElementKeys.MultipleInputAvailableOperations), multipleInputOperationSchema),
75
+ [FormInputKeys.MatrixTableConfig]: matrixTableConfigSchema,
76
+ };
77
+ /** Runtime key lists, derived from the enums. */
78
+ export const ALL_FORM_INPUT_KEYS = enumValues(FormInputKeys);
79
+ export const ALL_SPECIAL_ELEMENT_KEYS = enumValues(SpecialElementKeys);
@@ -0,0 +1,170 @@
1
+ import { s } from '@hashbrownai/core';
2
+ import { type AssertNever } from './internal/coupling.js';
3
+ import { type AvailableApiEndpoint } from './members/mat-options.js';
4
+ import { type ColumnSchemaOptions } from './variants.js';
5
+ import { type WorkflowStepContext } from './workflow-context.js';
6
+ /**
7
+ * The whole-form schema: slides of columns, plus how the form submits.
8
+ *
9
+ * ## This produces a draft, and it cannot not
10
+ *
11
+ * `FormSchema` requires `submissionHandle.submissionAPI` — an array of at least
12
+ * one full `APIDataFetchingConfiguration`, complete with `_id`, `httpEndPoint`
13
+ * and `httpMethod`. It is the same problem `matOptions` has, except mandatory:
14
+ * there is no valid form without it, and no model can author it from a prompt.
15
+ * `FormSlide.sectionId` is the same story on a smaller scale — an identifier
16
+ * the builder assigns, which a model can only fabricate.
17
+ *
18
+ * So a generated form is a {@link FormDraft}. The application supplies section
19
+ * ids and expands the chosen endpoint ids into stored configurations, and only
20
+ * then does `validateForm()` have something it can pass. Any pipeline built on
21
+ * this needs that expansion step; there is no arrangement of the schema that
22
+ * removes it.
23
+ *
24
+ * ## Streaming
25
+ *
26
+ * `streaming: true` switches the slide and column arrays to their streaming
27
+ * variants, so a client parses each slide as it arrives instead of waiting for
28
+ * the closing brace of a large form. It changes nothing about the data — only
29
+ * when a consumer can first see it.
30
+ */
31
+ export interface SubmissionHandleDraft {
32
+ submissionAPI: string[];
33
+ /**
34
+ * The pre-submit gate, as an endpoint id, expanded into
35
+ * `FormSubmissionHandleInterface.canSubmitAPI`.
36
+ *
37
+ * Absent — not empty — on most drafts, and on every draft generated without
38
+ * `FormSchemaOptions.canSubmitEndpoints`: the key is only put to the model
39
+ * when the caller has gate endpoints to offer, and a hand-built form carries
40
+ * no `canSubmitAPI` key either, so a schema that always emitted one would
41
+ * make every generated form differ from an authored one over a member the
42
+ * form does not use.
43
+ */
44
+ canSubmitAPI?: string[];
45
+ submissionMessage: string | null;
46
+ }
47
+ export interface FormDraft {
48
+ formTitle: string;
49
+ /**
50
+ * Columns are typed loosely on purpose. The per-element variants are
51
+ * assembled at runtime from `DefaultInputConfig`, whose property arrays are
52
+ * `string[]` rather than const tuples, so there is no literal type for
53
+ * `s.Infer` to reconstruct. The compiler cannot describe these; the schema
54
+ * and `validateForm()` still constrain them.
55
+ */
56
+ slides: {
57
+ label: string;
58
+ columns: unknown[];
59
+ }[];
60
+ submissionHandle: SubmissionHandleDraft;
61
+ }
62
+ export interface FormSchemaOptions extends ColumnSchemaOptions {
63
+ /**
64
+ * Endpoints the form may submit to. As with `matOptions`, an empty list means
65
+ * the model is not asked to choose one — it emits an empty `submissionAPI`
66
+ * and the application fills it in.
67
+ */
68
+ submissionEndpoints?: readonly AvailableApiEndpoint[];
69
+ /**
70
+ * Endpoints that may gate submission — called with the form data, and their
71
+ * answer decides whether the submission proceeds.
72
+ *
73
+ * Unlike {@link submissionEndpoints} this one is genuinely optional at the
74
+ * schema level: `canSubmitAPI` is optional on
75
+ * `FormSubmissionHandleInterface` and most forms have no pre-submit check, so
76
+ * an empty list here removes the key from the schema entirely rather than
77
+ * degrading it to an empty array. That follows `matOptions`, where a source
78
+ * with no candidates is not offered at all — the alternative is asking a
79
+ * model to pick an endpoint out of an empty list, which it answers by
80
+ * inventing one.
81
+ */
82
+ canSubmitEndpoints?: readonly AvailableApiEndpoint[];
83
+ /**
84
+ * The workflow step this form serves, and the control names the workflow
85
+ * already fixes. See {@link WorkflowStepContext}: none of it is knowable
86
+ * from a prompt, and all of it decides what the form must contain.
87
+ */
88
+ step?: WorkflowStepContext;
89
+ /** Parse slides and columns incrementally as they stream in. */
90
+ streaming?: boolean;
91
+ }
92
+ declare function submissionHandleSchema(endpoints: readonly AvailableApiEndpoint[], canSubmitEndpoints: readonly AvailableApiEndpoint[]): s.ObjectType<{
93
+ submissionAPI: s.ArrayType<s.StringType | s.EnumType<string[]>>;
94
+ canSubmitAPI: s.ArrayType<s.EnumType<string[]>>;
95
+ submissionMessage: import("@hashbrownai/core/src/schema/base").SchemaForUnion<string | null>;
96
+ }> | s.ObjectType<{
97
+ submissionAPI: s.ArrayType<s.StringType | s.EnumType<string[]>>;
98
+ submissionMessage: import("@hashbrownai/core/src/schema/base").SchemaForUnion<string | null>;
99
+ }>;
100
+ /** The submission-handle node, whichever endpoints the factory was given. */
101
+ type SubmissionHandleSchema = ReturnType<typeof submissionHandleSchema>;
102
+ /**
103
+ * The submission handle produces the draft it declares.
104
+ *
105
+ * The same check the per-member modules run on themselves, applied to the one
106
+ * nested object this file owns. It earns its keep on the `canSubmitAPI` branch
107
+ * in particular: that key exists only when the caller supplies
108
+ * `canSubmitEndpoints`, so the node's inferred type is a UNION of the two
109
+ * shapes, and a member added to either branch without a matching member on
110
+ * {@link SubmissionHandleDraft} fails here rather than at the application's
111
+ * expansion step.
112
+ */
113
+ export type _NoSubmissionHandleDraftDrift = AssertNever<[
114
+ s.Infer<SubmissionHandleSchema>
115
+ ] extends [SubmissionHandleDraft] ? never : 'submissionHandle'>;
116
+ /**
117
+ * Builds the form-draft schema.
118
+ *
119
+ * @param options which elements and data sources to offer, which endpoints the
120
+ * form may submit to and which may gate that submission, and whether to
121
+ * stream.
122
+ */
123
+ export declare function createFormDraftSchema(options?: FormSchemaOptions): s.ObjectType<{
124
+ formTitle: s.StringType;
125
+ slides: s.ArrayType<s.ObjectType<{
126
+ label: s.StringType;
127
+ columns: s.ArrayType<s.HashbrownType<unknown>>;
128
+ }>>;
129
+ submissionHandle: s.ObjectType<{
130
+ submissionAPI: s.ArrayType<s.StringType | s.EnumType<string[]>>;
131
+ canSubmitAPI: s.ArrayType<s.EnumType<string[]>>;
132
+ submissionMessage: import("@hashbrownai/core/src/schema/base").SchemaForUnion<string | null>;
133
+ }> | s.ObjectType<{
134
+ submissionAPI: s.ArrayType<s.StringType | s.EnumType<string[]>>;
135
+ submissionMessage: import("@hashbrownai/core/src/schema/base").SchemaForUnion<string | null>;
136
+ }>;
137
+ }>;
138
+ /**
139
+ * Members of a generated draft the application must supply before the form is
140
+ * valid. Listed so the expansion step has something to check itself against.
141
+ *
142
+ * The per-member lists are pulled in rather than restated, so a module that
143
+ * takes on a new obligation adds it here by existing. Each entry is prefixed
144
+ * with the column path it hangs off, since the modules describe their own
145
+ * shape and do not know where in a form they sit.
146
+ *
147
+ * A module's own entries must therefore start at the MEMBER it owns —
148
+ * `validators[].id`, not `id` — because everything before that is added here
149
+ * and everything after is the module's to state. A list that skips its member
150
+ * name yields a path with a hole in it, which is worse than no list: it reads
151
+ * as authoritative and points nowhere.
152
+ *
153
+ * Three entries are not from any module and are worth reading twice:
154
+ *
155
+ * - `isCalculatedField` is derived, not authored — see `calculatedFieldSplit`
156
+ * in `variants.ts`. It is required by the interface on EVERY column, so
157
+ * expansion must set it on plain columns too, not only calculated ones.
158
+ * - `onlySetTempErrorOnTouch` is required by the interface but optional in the
159
+ * schema (offered on every value-capturing element through the always-shown
160
+ * editor rows), so a model may leave it null. Expansion then sets it, and the
161
+ * guide's house rule says what to: true, so errors appear only after the
162
+ * user leaves a field. The builder's own element templates default it to
163
+ * false; the guide is explicit that this is the wrong default for nearly
164
+ * every field.
165
+ * - the nulls. Skillet has no optional, so every unset member arrives as an
166
+ * explicit `null`, and Joi rejects `null` for a typed optional key. Stripping
167
+ * them is not tidying; a draft that keeps them fails validation.
168
+ */
169
+ export declare const DRAFT_COMPLETION_REQUIRED: readonly ["slides[].sectionId", "slides[].columns[].id", "slides[].columns[].sectionId", "slides[].columns[].isCalculatedField (derived: calculatedFieldRules != null)", "slides[].columns[].onlySetTempErrorOnTouch (required by the interface and offered as optional; when the model leaves it null the application sets true)", "submissionHandle.submissionAPI[] (endpoint id expanded to its configuration)", "submissionHandle.canSubmitAPI[] (endpoint id expanded to its configuration; the key is present only when canSubmitEndpoints were offered, and an empty array is dropped)", ...string[], "every member emitted as null is stripped before validation"];
170
+ export {};