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
|
@@ -199,6 +199,40 @@ export interface APIDataFetchingConfigurationInterface extends DataFetchingBaseC
|
|
|
199
199
|
* interpreted — mirrors the other `captured*` seeds.
|
|
200
200
|
*/
|
|
201
201
|
capturedDocs?: string;
|
|
202
|
+
/**
|
|
203
|
+
* Opts this value out of the automatic read-only lock, so a user may supply
|
|
204
|
+
* what the tower's own value leaves out.
|
|
205
|
+
*
|
|
206
|
+
* An input whose value the tower owns is rendered read-only by default — a
|
|
207
|
+
* typed-over value would only be overwritten on the derived signal's next
|
|
208
|
+
* evaluation. This flag lifts that lock, and what it then means depends on
|
|
209
|
+
* the SHAPE the input declares in its `dataType`:
|
|
210
|
+
*
|
|
211
|
+
* **Scalar** (`string`, `number`, `boolean`, `date`, …) — the editor's *Allow
|
|
212
|
+
* manual entry when the API returns nothing* toggle, offered only on an `api`
|
|
213
|
+
* value source. The manually entered value stands **whenever the fetch
|
|
214
|
+
* contributes nothing** — no response yet, a `null` / empty response, or a
|
|
215
|
+
* failed request. A non-empty response always wins. A scalar that is
|
|
216
|
+
* calculated (`calculatedFieldRules`) or inherited from another input
|
|
217
|
+
* (`source: 'local'`) is read-only unconditionally and ignores this flag,
|
|
218
|
+
* because its derived signal recomputes synchronously from inputs the user
|
|
219
|
+
* can already edit.
|
|
220
|
+
*
|
|
221
|
+
* **Complex** (`dataType: 'object' | 'array'` — mSCOA, MultipleInput) — the
|
|
222
|
+
* editor's *Allow the user to complete this value* toggle, offered on a
|
|
223
|
+
* `local` value source as well as an `api` one. A multi-dimensional value can
|
|
224
|
+
* arrive partially populated (an mSCOA that inherits two of its segments,
|
|
225
|
+
* rows that come back missing a column), so the field stays editable and the
|
|
226
|
+
* tower **re-merges** rather than replacing: every change in the derived value
|
|
227
|
+
* is applied over the live value as a delta — what the tower supplies updates,
|
|
228
|
+
* what the user added survives. The first value the tower produces is taken
|
|
229
|
+
* whole; there is no earlier value to diff it against.
|
|
230
|
+
*
|
|
231
|
+
* Absent / `false` ⇒ the historical behaviour: the field is locked.
|
|
232
|
+
*
|
|
233
|
+
* @defaultValue false
|
|
234
|
+
*/
|
|
235
|
+
allowManualValueEntry?: boolean;
|
|
202
236
|
backEndConfig: {
|
|
203
237
|
/**
|
|
204
238
|
* The default/mapTo mapping that shapes the POST body in `'mappedInputs'` mode.
|
|
@@ -8,6 +8,7 @@ export var ElementTypes;
|
|
|
8
8
|
ElementTypes["IconSelect"] = "iconSelect";
|
|
9
9
|
ElementTypes["Textarea"] = "textarea";
|
|
10
10
|
ElementTypes["DatePicker"] = "datePicker";
|
|
11
|
+
ElementTypes["DateTimePicker"] = "dateTimePicker";
|
|
11
12
|
ElementTypes["DateRangePicker"] = "dateRangePicker";
|
|
12
13
|
ElementTypes["FileUpload"] = "fileUpload";
|
|
13
14
|
ElementTypes["Signature"] = "signature";
|
|
@@ -133,9 +133,11 @@ export type DualCashExclusionMatchMode = 'any' | 'all';
|
|
|
133
133
|
* one selected accrual account value in its segment scope.
|
|
134
134
|
*
|
|
135
135
|
* The pattern is tested against the account's `SCOAAccount` value AND the value
|
|
136
|
-
* of
|
|
137
|
-
* user sees selected in the
|
|
138
|
-
*
|
|
136
|
+
* of ONE labelled field: by default the field named by
|
|
137
|
+
* {@link IScoaInputConfig.accountValueLabel} (what the user sees selected in the
|
|
138
|
+
* chart), or — when the rule sets one — the field named by
|
|
139
|
+
* {@link IDualCashExclusionRule.matchField}. An invalid pattern never matches, so
|
|
140
|
+
* it can never suppress the cash requirement by accident.
|
|
139
141
|
*/
|
|
140
142
|
export interface IDualCashExclusionRule {
|
|
141
143
|
/** Stable record id (stamped by the builder's record-list editor). */
|
|
@@ -144,6 +146,20 @@ export interface IDualCashExclusionRule {
|
|
|
144
146
|
pattern: string;
|
|
145
147
|
/** Optional regex flags (e.g. `i`). Invalid flags make the rule evaluate as not matched. */
|
|
146
148
|
flags?: string;
|
|
149
|
+
/**
|
|
150
|
+
* Optional per-rule override of WHICH labelled account field the pattern is
|
|
151
|
+
* tested against, named exactly as the account carries it — the same pool the
|
|
152
|
+
* `accountValueLabel` picker offers (e.g. `ShortDescription`).
|
|
153
|
+
*
|
|
154
|
+
* Empty or absent means the input's configured
|
|
155
|
+
* {@link IScoaInputConfig.accountValueLabel}, which is the default and leaves
|
|
156
|
+
* every rule saved before this member existed evaluating exactly as it did.
|
|
157
|
+
* The account's `SCOAAccount` value is always tested as well, whatever this
|
|
158
|
+
* holds — the override replaces the labelled field only. A field the selected
|
|
159
|
+
* account does not carry contributes no candidate, so such a rule falls back to
|
|
160
|
+
* testing `SCOAAccount` alone rather than matching everything.
|
|
161
|
+
*/
|
|
162
|
+
matchField?: string;
|
|
147
163
|
/**
|
|
148
164
|
* Optional segment scope (matched case-insensitively against the accrual
|
|
149
165
|
* segment key, e.g. `ITEM`). Empty/absent = every accrual segment.
|
|
@@ -4,9 +4,21 @@ import { IBasicFormInput, OptionSelectTypes } from "./BasicFormInputInterface.js
|
|
|
4
4
|
export interface ISelectInputInterface extends IBasicFormInput {
|
|
5
5
|
[AllFormInputPrimaryKeys.OptionSelectType]: OptionSelectTypes;
|
|
6
6
|
[AllFormInputPrimaryKeys.AllowMultipleSelection]: boolean;
|
|
7
|
+
/**
|
|
8
|
+
* The most options a user may choose at once.
|
|
9
|
+
*
|
|
10
|
+
* Only meaningful alongside {@link ISelectInputInterface.allowMultipleSelection};
|
|
11
|
+
* a single-selection control is already capped at one. Declared on each
|
|
12
|
+
* multi-select interface rather than on `IBasicFormInput`, the same way
|
|
13
|
+
* `allowMultipleSelection` itself is, so a control that cannot select
|
|
14
|
+
* several things does not appear to offer a limit on how many.
|
|
15
|
+
*/
|
|
16
|
+
selectUpto?: number;
|
|
7
17
|
}
|
|
8
18
|
export interface IPaginatedSelectionTableInputInterface extends IBasicFormInput {
|
|
9
19
|
[AllFormInputPrimaryKeys.AllowMultipleSelection]: boolean;
|
|
20
|
+
/** @see ISelectInputInterface.selectUpto */
|
|
21
|
+
selectUpto?: number;
|
|
10
22
|
[AllFormInputPrimaryKeys.PaginationSelectionConfig]: {
|
|
11
23
|
useLocalPagination: boolean;
|
|
12
24
|
primaryIdentifierKey?: TreeNode[];
|
|
@@ -15,6 +15,16 @@ export interface IMultiple extends IBasicFormInput {
|
|
|
15
15
|
multipleInputAvailableOperations?: Array<MultipleInputAvailableOperations>;
|
|
16
16
|
calculateListFunctions: Array<IMultipleInputCal>;
|
|
17
17
|
groupBy?: string[];
|
|
18
|
+
/**
|
|
19
|
+
* The `formControlName`s of columns inside this group whose values are
|
|
20
|
+
* summed and shown as a total beneath the rows.
|
|
21
|
+
*
|
|
22
|
+
* Belongs here rather than on `IBasicFormInput` because a total only means
|
|
23
|
+
* something over a set of rows: each name must be a field declared in
|
|
24
|
+
* {@link IMultiple.formInputs}. The legacy `init-form` shape grouped it with
|
|
25
|
+
* `formInputs` and `groupBy` for the same reason.
|
|
26
|
+
*/
|
|
27
|
+
showTotalsOf?: string[];
|
|
18
28
|
}
|
|
19
29
|
export interface IMultipleInputCal {
|
|
20
30
|
id: string;
|
|
@@ -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
|
});
|
package/dist/schemas/index.d.ts
CHANGED
|
@@ -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
|
-
|
|
4
|
+
import { MscoaInputConfigSchema, validateMscoaInputConfig } from "./MscoaConfigSchema.js";
|
|
5
|
+
export { FormSchema, DatabaseFormSchema, formColumnInputsSchema, validateCalculatedFieldRules, validateFormColumnInputs, validateFormSlide, validateFormColumnInputsWithRequired, validateForm, validateApiDataFetchingConfiguration, MscoaInputConfigSchema, validateMscoaInputConfig };
|
package/dist/schemas/index.js
CHANGED
|
@@ -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
|
-
|
|
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);
|