ngx-t-forms-types 0.0.30 → 0.0.34
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/dist/interfaces/Form/formSubmissionHandleInterface.d.ts +6 -0
- package/dist/interfaces/FormBuilder/DefaultEelement.js +76 -0
- package/dist/interfaces/FormBuilder/DefaultInputConfigInterface.d.ts +13 -0
- package/dist/interfaces/FormBuilder/FormInputKeys.d.ts +6 -0
- package/dist/interfaces/FormBuilder/FormInputKeys.js +6 -0
- package/dist/interfaces/FormBuilder/inputConfig/ElementEditConfig.js +188 -3
- package/dist/interfaces/Import/ImportIdentity.d.ts +32 -0
- package/dist/interfaces/Import/ImportIdentity.js +1 -0
- package/dist/interfaces/Import/ImportProgress.d.ts +12 -1
- package/dist/interfaces/Import/ImportRowState.d.ts +52 -1
- package/dist/interfaces/Import/index.d.ts +2 -1
- package/dist/interfaces/formInput/APIDataFetchingConfigurationInterface.d.ts +34 -0
- package/dist/interfaces/formInput/BasicFormInputInterface.d.ts +1 -0
- package/dist/interfaces/formInput/BasicFormInputInterface.js +1 -0
- package/dist/interfaces/formInput/IMscoaAccount.d.ts +19 -3
- package/dist/interfaces/formInput/ISelectInputInterface.d.ts +12 -0
- package/dist/interfaces/formInput/MultipleInterface.d.ts +10 -0
- package/dist/interfaces/formInput/WorkflowDocumentPicker.d.ts +2 -0
- package/dist/schemas/FormInputSchema.js +41 -2
- package/dist/schemas/MatOptionsSchema.js +7 -0
- package/dist/schemas/MscoaConfigSchema.js +1 -0
- package/dist/schemas/index.d.ts +2 -1
- package/dist/schemas/index.js +2 -1
- package/dist/skillet/authoring-rules.d.ts +41 -0
- package/dist/skillet/authoring-rules.js +61 -0
- package/dist/skillet/extra-members.d.ts +143 -0
- package/dist/skillet/extra-members.js +79 -0
- package/dist/skillet/form.d.ts +170 -0
- package/dist/skillet/form.js +139 -0
- package/dist/skillet/index.d.ts +43 -0
- package/dist/skillet/index.js +46 -0
- package/dist/skillet/input-members.d.ts +375 -0
- package/dist/skillet/input-members.js +186 -0
- package/dist/skillet/internal/coupling.d.ts +63 -0
- package/dist/skillet/internal/coupling.js +69 -0
- package/dist/skillet/internal/editor-guidance.d.ts +64 -0
- package/dist/skillet/internal/editor-guidance.js +291 -0
- package/dist/skillet/members/calculated-field.d.ts +155 -0
- package/dist/skillet/members/calculated-field.js +105 -0
- package/dist/skillet/members/conditional.d.ts +69 -0
- package/dist/skillet/members/conditional.js +16 -0
- package/dist/skillet/members/document-picker.d.ts +182 -0
- package/dist/skillet/members/document-picker.js +111 -0
- package/dist/skillet/members/mat-options.d.ts +187 -0
- package/dist/skillet/members/mat-options.js +92 -0
- package/dist/skillet/members/mscoa.d.ts +182 -0
- package/dist/skillet/members/mscoa.js +129 -0
- package/dist/skillet/members/pagination.d.ts +59 -0
- package/dist/skillet/members/pagination.js +16 -0
- package/dist/skillet/members/table.d.ts +178 -0
- package/dist/skillet/members/table.js +105 -0
- package/dist/skillet/members/validators.d.ts +197 -0
- package/dist/skillet/members/validators.js +74 -0
- package/dist/skillet/members/value.d.ts +154 -0
- package/dist/skillet/members/value.js +97 -0
- package/dist/skillet/shared-types.d.ts +57 -0
- package/dist/skillet/shared-types.js +69 -0
- package/dist/skillet/tests/house-rules.spec.d.ts +1 -0
- package/dist/skillet/tests/house-rules.spec.js +162 -0
- package/dist/skillet/tests/skillet-coupling.spec.d.ts +1 -0
- package/dist/skillet/tests/skillet-coupling.spec.js +191 -0
- package/dist/skillet/tests/variant-assembly.spec.d.ts +1 -0
- package/dist/skillet/tests/variant-assembly.spec.js +643 -0
- package/dist/skillet/variants.d.ts +138 -0
- package/dist/skillet/variants.js +536 -0
- package/dist/skillet/workflow-context.d.ts +95 -0
- package/dist/skillet/workflow-context.js +128 -0
- package/package.json +78 -60
|
@@ -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 {};
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { s } from '@hashbrownai/core';
|
|
2
|
+
import { ElementTypes } from '../interfaces/formInput/index.js';
|
|
3
|
+
import { describeAuthoringRules } from './authoring-rules.js';
|
|
4
|
+
import { optional } from './internal/coupling.js';
|
|
5
|
+
import { CALCULATED_FIELD_DRAFT_COMPLETION } from './members/calculated-field.js';
|
|
6
|
+
import { CONDITIONAL_DRAFT_COMPLETION } from './members/conditional.js';
|
|
7
|
+
import { WORKFLOW_PICKER_DRAFT_COMPLETION } from './members/document-picker.js';
|
|
8
|
+
import { MAT_OPTIONS_DRAFT_COMPLETION, } from './members/mat-options.js';
|
|
9
|
+
import { MSCOA_DRAFT_COMPLETION } from './members/mscoa.js';
|
|
10
|
+
import { PAGINATION_DRAFT_COMPLETION } from './members/pagination.js';
|
|
11
|
+
import { TABLE_DRAFT_COMPLETION } from './members/table.js';
|
|
12
|
+
import { VALIDATOR_DRAFT_COMPLETION } from './members/validators.js';
|
|
13
|
+
import { CALCULATE_LIST_DRAFT_COMPLETION } from './members/value.js';
|
|
14
|
+
import { createColumnSchema } from './variants.js';
|
|
15
|
+
import { describeWorkflowStep, } from './workflow-context.js';
|
|
16
|
+
function submissionHandleSchema(endpoints, canSubmitEndpoints) {
|
|
17
|
+
const endpointNode = endpoints.length
|
|
18
|
+
? s.enumeration(`Which configured endpoint the completed form is submitted to. Choose by meaning: ${endpoints
|
|
19
|
+
.map((e) => `${e.id} (${e.name})`)
|
|
20
|
+
.join('; ')}.`, endpoints.map((e) => e.id))
|
|
21
|
+
: s.string('Leave this list empty. No submission endpoints were offered, so one cannot be chosen and must not be invented.');
|
|
22
|
+
const submissionAPI = s.array(endpoints.length
|
|
23
|
+
? 'The endpoint the form submits to. Choose exactly one.'
|
|
24
|
+
: 'Leave empty — the application supplies the submission endpoint.', endpointNode, endpoints.length ? { minItems: 1, maxItems: 1 } : { maxItems: 0 });
|
|
25
|
+
// `innerComponentShowSubmitButton` is deliberately absent: it is deprecated,
|
|
26
|
+
// and a deprecated property left in a generation schema comes back on every
|
|
27
|
+
// form the model writes.
|
|
28
|
+
const submissionMessage = optional(s.string("Message shown to the user after a successful submission. One sentence, past tense, saying what happened and what happens next: 'Your requisition has been submitted and sent to your line manager for approval'."));
|
|
29
|
+
const description = 'How the completed form is submitted.';
|
|
30
|
+
// Two whole object nodes rather than one with a conditionally spread key:
|
|
31
|
+
// an optional key in a Skillet shape infers as `unknown`, which would leave
|
|
32
|
+
// the assertion at the foot of this file passing while proving nothing.
|
|
33
|
+
return canSubmitEndpoints.length
|
|
34
|
+
? s.object(description, {
|
|
35
|
+
submissionAPI,
|
|
36
|
+
canSubmitAPI: s.array('An optional check run before the form is submitted: the endpoint is called with the form data and must approve before the submission proceeds. Leave this empty unless the form genuinely needs a gate — most do not. Choose at most one.', s.enumeration(`Which configured endpoint decides whether the form may be submitted. Choose by meaning: ${canSubmitEndpoints
|
|
37
|
+
.map((e) => `${e.id} (${e.name})`)
|
|
38
|
+
.join('; ')}.`, canSubmitEndpoints.map((e) => e.id)), { maxItems: 1 }),
|
|
39
|
+
submissionMessage,
|
|
40
|
+
})
|
|
41
|
+
: s.object(description, {
|
|
42
|
+
submissionAPI,
|
|
43
|
+
submissionMessage,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Builds the form-draft schema.
|
|
48
|
+
*
|
|
49
|
+
* @param options which elements and data sources to offer, which endpoints the
|
|
50
|
+
* form may submit to and which may gate that submission, and whether to
|
|
51
|
+
* stream.
|
|
52
|
+
*/
|
|
53
|
+
export function createFormDraftSchema(options = {}) {
|
|
54
|
+
const column = createColumnSchema(options);
|
|
55
|
+
const array = options.streaming ? s.streaming.array : s.array;
|
|
56
|
+
const object = options.streaming ? s.streaming.object : s.object;
|
|
57
|
+
// The guide's grouping rule names section titles, so it is only stated when
|
|
58
|
+
// that element is actually on offer — a sentence pointing a model at an
|
|
59
|
+
// element it cannot choose is an invitation to invent one.
|
|
60
|
+
const offersHeadings = (options.elements ?? Object.values(ElementTypes)).includes(ElementTypes.SectionTitle);
|
|
61
|
+
const slide = object('A page of the form: one topic, with five to seven fields, an item list counting as one. Over eight, split it. Its label becomes a section heading when the transaction is read back.', {
|
|
62
|
+
label: s.string("The heading for this page: a short statement of what it holds, in sentence case — 'Requester details', 'Items required' — never a question, a verb, or a number such as 'Section 3'."),
|
|
63
|
+
columns: array([
|
|
64
|
+
'The fields on this page, in the order they are shown: identifiers and choices first, free text, uploads, calculations and signatures last.',
|
|
65
|
+
offersHeadings
|
|
66
|
+
? 'Start each group of three to five related fields with a sectionTitle whose hintLabel carries the guidance for the group.'
|
|
67
|
+
: null,
|
|
68
|
+
'Fields that belong together share one row by sharing out the 12 grid columns between them, and a field revealed by a condition sits immediately after the field that reveals it.',
|
|
69
|
+
]
|
|
70
|
+
.filter((part) => part !== null)
|
|
71
|
+
.join(' '), column, { minItems: 1 }),
|
|
72
|
+
});
|
|
73
|
+
// The root is emitted exactly once, so it is where the form-wide rules go;
|
|
74
|
+
// see `authoring-rules.ts` for why they are not on the members themselves.
|
|
75
|
+
const formDescription = [
|
|
76
|
+
'A complete dynamic form. Group related fields onto slides rather than one long page; a form of fewer than about seven fields fits on one slide. Make the system do everything it can: prefill what it knows, calculate what it can derive, and let the user pick rather than type.',
|
|
77
|
+
describeAuthoringRules(),
|
|
78
|
+
options.step ? describeWorkflowStep(options.step) : null,
|
|
79
|
+
]
|
|
80
|
+
.filter((part) => part !== null)
|
|
81
|
+
.join(' ');
|
|
82
|
+
return object(formDescription, {
|
|
83
|
+
formTitle: s.string('The title of the form, in sentence case. Name what the form is for.'),
|
|
84
|
+
slides: array('The pages of the form, in order.', slide, { minItems: 1 }),
|
|
85
|
+
submissionHandle: submissionHandleSchema(options.submissionEndpoints ?? [], options.canSubmitEndpoints ?? []),
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Members of a generated draft the application must supply before the form is
|
|
90
|
+
* valid. Listed so the expansion step has something to check itself against.
|
|
91
|
+
*
|
|
92
|
+
* The per-member lists are pulled in rather than restated, so a module that
|
|
93
|
+
* takes on a new obligation adds it here by existing. Each entry is prefixed
|
|
94
|
+
* with the column path it hangs off, since the modules describe their own
|
|
95
|
+
* shape and do not know where in a form they sit.
|
|
96
|
+
*
|
|
97
|
+
* A module's own entries must therefore start at the MEMBER it owns —
|
|
98
|
+
* `validators[].id`, not `id` — because everything before that is added here
|
|
99
|
+
* and everything after is the module's to state. A list that skips its member
|
|
100
|
+
* name yields a path with a hole in it, which is worse than no list: it reads
|
|
101
|
+
* as authoritative and points nowhere.
|
|
102
|
+
*
|
|
103
|
+
* Three entries are not from any module and are worth reading twice:
|
|
104
|
+
*
|
|
105
|
+
* - `isCalculatedField` is derived, not authored — see `calculatedFieldSplit`
|
|
106
|
+
* in `variants.ts`. It is required by the interface on EVERY column, so
|
|
107
|
+
* expansion must set it on plain columns too, not only calculated ones.
|
|
108
|
+
* - `onlySetTempErrorOnTouch` is required by the interface but optional in the
|
|
109
|
+
* schema (offered on every value-capturing element through the always-shown
|
|
110
|
+
* editor rows), so a model may leave it null. Expansion then sets it, and the
|
|
111
|
+
* guide's house rule says what to: true, so errors appear only after the
|
|
112
|
+
* user leaves a field. The builder's own element templates default it to
|
|
113
|
+
* false; the guide is explicit that this is the wrong default for nearly
|
|
114
|
+
* every field.
|
|
115
|
+
* - the nulls. Skillet has no optional, so every unset member arrives as an
|
|
116
|
+
* explicit `null`, and Joi rejects `null` for a typed optional key. Stripping
|
|
117
|
+
* them is not tidying; a draft that keeps them fails validation.
|
|
118
|
+
*/
|
|
119
|
+
export const DRAFT_COMPLETION_REQUIRED = [
|
|
120
|
+
'slides[].sectionId',
|
|
121
|
+
'slides[].columns[].id',
|
|
122
|
+
'slides[].columns[].sectionId',
|
|
123
|
+
'slides[].columns[].isCalculatedField (derived: calculatedFieldRules != null)',
|
|
124
|
+
'slides[].columns[].onlySetTempErrorOnTouch (required by the interface and offered as optional; when the model leaves it null the application sets true)',
|
|
125
|
+
'submissionHandle.submissionAPI[] (endpoint id expanded to its configuration)',
|
|
126
|
+
'submissionHandle.canSubmitAPI[] (endpoint id expanded to its configuration; the key is present only when canSubmitEndpoints were offered, and an empty array is dropped)',
|
|
127
|
+
...[
|
|
128
|
+
...CALCULATED_FIELD_DRAFT_COMPLETION,
|
|
129
|
+
...VALIDATOR_DRAFT_COMPLETION,
|
|
130
|
+
...CONDITIONAL_DRAFT_COMPLETION,
|
|
131
|
+
...PAGINATION_DRAFT_COMPLETION,
|
|
132
|
+
...MSCOA_DRAFT_COMPLETION,
|
|
133
|
+
...WORKFLOW_PICKER_DRAFT_COMPLETION,
|
|
134
|
+
...MAT_OPTIONS_DRAFT_COMPLETION,
|
|
135
|
+
...CALCULATE_LIST_DRAFT_COMPLETION,
|
|
136
|
+
...TABLE_DRAFT_COMPLETION,
|
|
137
|
+
].map((path) => `slides[].columns[].${path}`),
|
|
138
|
+
'every member emitted as null is stripped before validation',
|
|
139
|
+
];
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skillet schemas for LLM-driven form authoring.
|
|
3
|
+
*
|
|
4
|
+
* Published as the `ngx-t-forms-types/skillet` subpath, NOT from the package
|
|
5
|
+
* root, because it is the only part of these typings that needs
|
|
6
|
+
* `@hashbrownai/core`. That dependency is an optional peer: consumers who never
|
|
7
|
+
* generate forms — the Node API, existing Angular apps — resolve the root entry
|
|
8
|
+
* and never load it.
|
|
9
|
+
*
|
|
10
|
+
* ## What this is for
|
|
11
|
+
*
|
|
12
|
+
* These schemas describe form structure to a model so it can author one. They
|
|
13
|
+
* are a GENERATION contract, not a validation contract. The Joi schemas under
|
|
14
|
+
* `src/schemas` remain the source of truth: a generated form is validated with
|
|
15
|
+
* `validateForm()` exactly like a hand-built one, and failures are fed back to
|
|
16
|
+
* the model as a repair turn. Where the two disagree, Joi wins.
|
|
17
|
+
*
|
|
18
|
+
* ## How drift is prevented
|
|
19
|
+
*
|
|
20
|
+
* Enum-backed nodes read their entries from the live enums at evaluation, so
|
|
21
|
+
* they cannot fall behind. Everything else is checked at compile time: see the
|
|
22
|
+
* assertions at the foot of `input-members.ts`, which fail the build — by
|
|
23
|
+
* name — when a key is added to `AllFormInputPrimaryKeys`, when a member is
|
|
24
|
+
* left unclassified, or when a node starts producing a value its interface
|
|
25
|
+
* cannot hold.
|
|
26
|
+
*/
|
|
27
|
+
export { enumValues, exhaustive, matches, optional, type AssertNever, } from './internal/coupling.js';
|
|
28
|
+
export * from './shared-types.js';
|
|
29
|
+
export * from './input-members.js';
|
|
30
|
+
export * from './extra-members.js';
|
|
31
|
+
export * from './members/mat-options.js';
|
|
32
|
+
export * from './members/calculated-field.js';
|
|
33
|
+
export * from './members/validators.js';
|
|
34
|
+
export * from './members/conditional.js';
|
|
35
|
+
export * from './members/document-picker.js';
|
|
36
|
+
export * from './members/mscoa.js';
|
|
37
|
+
export * from './members/pagination.js';
|
|
38
|
+
export * from './members/table.js';
|
|
39
|
+
export * from './members/value.js';
|
|
40
|
+
export * from './variants.js';
|
|
41
|
+
export * from './form.js';
|
|
42
|
+
export * from './workflow-context.js';
|
|
43
|
+
export * from './authoring-rules.js';
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skillet schemas for LLM-driven form authoring.
|
|
3
|
+
*
|
|
4
|
+
* Published as the `ngx-t-forms-types/skillet` subpath, NOT from the package
|
|
5
|
+
* root, because it is the only part of these typings that needs
|
|
6
|
+
* `@hashbrownai/core`. That dependency is an optional peer: consumers who never
|
|
7
|
+
* generate forms — the Node API, existing Angular apps — resolve the root entry
|
|
8
|
+
* and never load it.
|
|
9
|
+
*
|
|
10
|
+
* ## What this is for
|
|
11
|
+
*
|
|
12
|
+
* These schemas describe form structure to a model so it can author one. They
|
|
13
|
+
* are a GENERATION contract, not a validation contract. The Joi schemas under
|
|
14
|
+
* `src/schemas` remain the source of truth: a generated form is validated with
|
|
15
|
+
* `validateForm()` exactly like a hand-built one, and failures are fed back to
|
|
16
|
+
* the model as a repair turn. Where the two disagree, Joi wins.
|
|
17
|
+
*
|
|
18
|
+
* ## How drift is prevented
|
|
19
|
+
*
|
|
20
|
+
* Enum-backed nodes read their entries from the live enums at evaluation, so
|
|
21
|
+
* they cannot fall behind. Everything else is checked at compile time: see the
|
|
22
|
+
* assertions at the foot of `input-members.ts`, which fail the build — by
|
|
23
|
+
* name — when a key is added to `AllFormInputPrimaryKeys`, when a member is
|
|
24
|
+
* left unclassified, or when a node starts producing a value its interface
|
|
25
|
+
* cannot hold.
|
|
26
|
+
*/
|
|
27
|
+
export { enumValues, exhaustive, matches, optional, } from './internal/coupling.js';
|
|
28
|
+
export * from './shared-types.js';
|
|
29
|
+
export * from './input-members.js';
|
|
30
|
+
export * from './extra-members.js';
|
|
31
|
+
// Per-member modules. Each owns one nested configuration object, states why it
|
|
32
|
+
// produces a draft where it does, and lists what the application must supply
|
|
33
|
+
// before that draft is valid.
|
|
34
|
+
export * from './members/mat-options.js';
|
|
35
|
+
export * from './members/calculated-field.js';
|
|
36
|
+
export * from './members/validators.js';
|
|
37
|
+
export * from './members/conditional.js';
|
|
38
|
+
export * from './members/document-picker.js';
|
|
39
|
+
export * from './members/mscoa.js';
|
|
40
|
+
export * from './members/pagination.js';
|
|
41
|
+
export * from './members/table.js';
|
|
42
|
+
export * from './members/value.js';
|
|
43
|
+
export * from './variants.js';
|
|
44
|
+
export * from './form.js';
|
|
45
|
+
export * from './workflow-context.js';
|
|
46
|
+
export * from './authoring-rules.js';
|