@rytass/bpm-core-nestjs-module 0.6.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +133 -0
- package/README.md +60 -1
- package/package.json +17 -3
- package/src/index.d.ts +2 -0
- package/src/index.js +2 -0
- package/src/index.js.map +1 -1
- package/src/lib/bpm/bpm-root.module.d.ts +33 -0
- package/src/lib/bpm/bpm-root.module.js +20 -0
- package/src/lib/bpm/bpm-root.module.js.map +1 -1
- package/src/lib/calendar/business-calendar.provider.d.ts +11 -0
- package/src/lib/calendar/business-calendar.provider.js +20 -0
- package/src/lib/calendar/business-calendar.provider.js.map +1 -0
- package/src/lib/calendar/business-calendar.token.d.ts +38 -0
- package/src/lib/calendar/business-calendar.token.js +5 -0
- package/src/lib/calendar/business-calendar.token.js.map +1 -0
- package/src/lib/calendar/calendar.module.d.ts +22 -0
- package/src/lib/calendar/calendar.module.js +33 -0
- package/src/lib/calendar/calendar.module.js.map +1 -0
- package/src/lib/calendar/index.d.ts +5 -0
- package/src/lib/calendar/index.js +9 -0
- package/src/lib/calendar/index.js.map +1 -0
- package/src/lib/calendar/sla-schedule.service.d.ts +33 -0
- package/src/lib/calendar/sla-schedule.service.js +94 -0
- package/src/lib/calendar/sla-schedule.service.js.map +1 -0
- package/src/lib/calendar/weekday-business-calendar.d.ts +15 -0
- package/src/lib/calendar/weekday-business-calendar.js +28 -0
- package/src/lib/calendar/weekday-business-calendar.js.map +1 -0
- package/src/lib/common/iso-duration.d.ts +11 -0
- package/src/lib/common/iso-duration.js +13 -4
- package/src/lib/common/iso-duration.js.map +1 -1
- package/src/lib/form/form-schema.validator.js +177 -10
- package/src/lib/form/form-schema.validator.js.map +1 -1
- package/src/lib/form/form.service.d.ts +19 -1
- package/src/lib/form/form.service.js +56 -6
- package/src/lib/form/form.service.js.map +1 -1
- package/src/lib/form-data-source/form-data-source-value-resolver.service.d.ts +16 -0
- package/src/lib/form-data-source/form-data-source-value-resolver.service.js +401 -0
- package/src/lib/form-data-source/form-data-source-value-resolver.service.js.map +1 -0
- package/src/lib/form-data-source/form-data-source.errors.d.ts +34 -0
- package/src/lib/form-data-source/form-data-source.errors.js +43 -0
- package/src/lib/form-data-source/form-data-source.errors.js.map +1 -0
- package/src/lib/form-data-source/form-data-source.module.d.ts +9 -0
- package/src/lib/form-data-source/form-data-source.module.js +55 -0
- package/src/lib/form-data-source/form-data-source.module.js.map +1 -0
- package/src/lib/form-data-source/form-data-source.queries.d.ts +57 -0
- package/src/lib/form-data-source/form-data-source.queries.js +293 -0
- package/src/lib/form-data-source/form-data-source.queries.js.map +1 -0
- package/src/lib/form-data-source/form-data-source.service.d.ts +72 -0
- package/src/lib/form-data-source/form-data-source.service.js +646 -0
- package/src/lib/form-data-source/form-data-source.service.js.map +1 -0
- package/src/lib/form-data-source/form-data-source.types.d.ts +88 -0
- package/src/lib/form-data-source/form-data-source.types.js +29 -0
- package/src/lib/form-data-source/form-data-source.types.js.map +1 -0
- package/src/lib/form-data-source/index.d.ts +5 -0
- package/src/lib/form-data-source/index.js +9 -0
- package/src/lib/form-data-source/index.js.map +1 -0
- package/src/lib/migrations/0000000018000-notification-archive.d.ts +6 -0
- package/src/lib/migrations/0000000018000-notification-archive.js +28 -0
- package/src/lib/migrations/0000000018000-notification-archive.js.map +1 -0
- package/src/lib/migrations/0000000019000-approval-template-activation.d.ts +6 -0
- package/src/lib/migrations/0000000019000-approval-template-activation.js +29 -0
- package/src/lib/migrations/0000000019000-approval-template-activation.js.map +1 -0
- package/src/lib/migrations/0000000020000-form-data-option-snapshots.d.ts +6 -0
- package/src/lib/migrations/0000000020000-form-data-option-snapshots.js +22 -0
- package/src/lib/migrations/0000000020000-form-data-option-snapshots.js.map +1 -0
- package/src/lib/migrations/index.d.ts +3 -0
- package/src/lib/migrations/index.js +9 -0
- package/src/lib/migrations/index.js.map +1 -1
- package/src/lib/notification/index.d.ts +3 -0
- package/src/lib/notification/index.js +3 -0
- package/src/lib/notification/index.js.map +1 -1
- package/src/lib/notification/notification-observer.token.d.ts +52 -0
- package/src/lib/notification/notification-observer.token.js +5 -0
- package/src/lib/notification/notification-observer.token.js.map +1 -0
- package/src/lib/notification/notification-options.d.ts +10 -0
- package/src/lib/notification/notification-options.js +19 -0
- package/src/lib/notification/notification-options.js.map +1 -1
- package/src/lib/notification/notification.entity.d.ts +11 -0
- package/src/lib/notification/notification.entity.js +17 -0
- package/src/lib/notification/notification.entity.js.map +1 -1
- package/src/lib/notification/notification.enums.d.ts +13 -0
- package/src/lib/notification/notification.enums.js +14 -1
- package/src/lib/notification/notification.enums.js.map +1 -1
- package/src/lib/notification/notification.mutations.d.ts +2 -0
- package/src/lib/notification/notification.mutations.js +28 -0
- package/src/lib/notification/notification.mutations.js.map +1 -1
- package/src/lib/notification/notification.queries.d.ts +2 -2
- package/src/lib/notification/notification.queries.js +12 -8
- package/src/lib/notification/notification.queries.js.map +1 -1
- package/src/lib/notification/notification.service.d.ts +42 -2
- package/src/lib/notification/notification.service.js +135 -4
- package/src/lib/notification/notification.service.js.map +1 -1
- package/src/lib/template/approval-template.entity.d.ts +13 -0
- package/src/lib/template/approval-template.entity.js +12 -1
- package/src/lib/template/approval-template.entity.js.map +1 -1
- package/src/lib/template/template.enums.d.ts +5 -0
- package/src/lib/template/template.enums.js +10 -1
- package/src/lib/template/template.enums.js.map +1 -1
- package/src/lib/template/template.mutations.d.ts +2 -0
- package/src/lib/template/template.mutations.js +20 -0
- package/src/lib/template/template.mutations.js.map +1 -1
- package/src/lib/template/template.queries.d.ts +3 -3
- package/src/lib/template/template.queries.js +14 -4
- package/src/lib/template/template.queries.js.map +1 -1
- package/src/lib/template/template.service.d.ts +7 -2
- package/src/lib/template/template.service.js +56 -11
- package/src/lib/template/template.service.js.map +1 -1
- package/src/lib/template/workflow-definition.validator.js +86 -1
- package/src/lib/template/workflow-definition.validator.js.map +1 -1
- package/src/lib/workflow-engine/approval-instance.entity.d.ts +3 -0
- package/src/lib/workflow-engine/approval-instance.entity.js +15 -0
- package/src/lib/workflow-engine/approval-instance.entity.js.map +1 -1
- package/src/lib/workflow-engine/dto/resubmit-approval-instance.input.d.ts +5 -1
- package/src/lib/workflow-engine/dto/resubmit-approval-instance.input.js +6 -2
- package/src/lib/workflow-engine/dto/resubmit-approval-instance.input.js.map +1 -1
- package/src/lib/workflow-engine/dto/submit-approval-instance.input.d.ts +5 -1
- package/src/lib/workflow-engine/dto/submit-approval-instance.input.js +6 -2
- package/src/lib/workflow-engine/dto/submit-approval-instance.input.js.map +1 -1
- package/src/lib/workflow-engine/workflow-engine.mutations.d.ts +3 -2
- package/src/lib/workflow-engine/workflow-engine.mutations.js +8 -6
- package/src/lib/workflow-engine/workflow-engine.mutations.js.map +1 -1
- package/src/lib/workflow-engine/workflow-engine.service.d.ts +37 -4
- package/src/lib/workflow-engine/workflow-engine.service.js +245 -15
- package/src/lib/workflow-engine/workflow-engine.service.js.map +1 -1
- package/src/lib/workflow-engine/workflow-engine.tokens.d.ts +2 -1
- package/src/lib/workflow-engine/workflow-engine.tokens.js.map +1 -1
|
@@ -0,0 +1,646 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var FormDataSourceService_1;
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.FormDataSourceService = void 0;
|
|
5
|
+
const tslib_1 = require("tslib");
|
|
6
|
+
const common_1 = require("@nestjs/common");
|
|
7
|
+
const typeorm_1 = require("@nestjs/typeorm");
|
|
8
|
+
const form_1 = require("@rytass/bpm-core-shared/form");
|
|
9
|
+
const typeorm_2 = require("typeorm");
|
|
10
|
+
const approval_template_version_entity_1 = require("../template/approval-template-version.entity");
|
|
11
|
+
const template_enums_1 = require("../template/template.enums");
|
|
12
|
+
const form_definition_version_entity_1 = require("../form/form-definition-version.entity");
|
|
13
|
+
const form_enums_1 = require("../form/form.enums");
|
|
14
|
+
const form_schema_validator_1 = require("../form/form-schema.validator");
|
|
15
|
+
const workflow_engine_enums_1 = require("../workflow-engine/workflow-engine.enums");
|
|
16
|
+
const workflow_engine_service_1 = require("../workflow-engine/workflow-engine.service");
|
|
17
|
+
const form_data_source_errors_1 = require("./form-data-source.errors");
|
|
18
|
+
const form_data_source_types_1 = require("./form-data-source.types");
|
|
19
|
+
const MAX_PARAMETER_BYTES = 16_384;
|
|
20
|
+
const PROVIDER_TIMEOUT_MS = 5_000;
|
|
21
|
+
const SOURCE_CONTROLS = [
|
|
22
|
+
'autocomplete',
|
|
23
|
+
'checkbox',
|
|
24
|
+
'radio',
|
|
25
|
+
'select',
|
|
26
|
+
];
|
|
27
|
+
const PARAMETER_TYPES = [
|
|
28
|
+
'BOOLEAN',
|
|
29
|
+
'NUMBER',
|
|
30
|
+
'STRING',
|
|
31
|
+
'STRING_ARRAY',
|
|
32
|
+
];
|
|
33
|
+
let FormDataSourceService = FormDataSourceService_1 = class FormDataSourceService {
|
|
34
|
+
constructor(registry, approvalTemplateVersionRepository, formDefinitionVersionRepository, workflowEngineService) {
|
|
35
|
+
this.registry = registry;
|
|
36
|
+
this.approvalTemplateVersionRepository = approvalTemplateVersionRepository;
|
|
37
|
+
this.formDefinitionVersionRepository = formDefinitionVersionRepository;
|
|
38
|
+
this.workflowEngineService = workflowEngineService;
|
|
39
|
+
this.logger = new common_1.Logger(FormDataSourceService_1.name);
|
|
40
|
+
}
|
|
41
|
+
listDescriptors() {
|
|
42
|
+
return this.registry.list().flatMap((source) => this.readDescriptorErrors(source.descriptor).length === 0
|
|
43
|
+
? [source.descriptor]
|
|
44
|
+
: []);
|
|
45
|
+
}
|
|
46
|
+
lintDefinitionSchemaEnvironment(schema) {
|
|
47
|
+
return schema.fields.flatMap((field, index) => {
|
|
48
|
+
if (!(0, form_1.isFormDataSourceFieldDefinition)(field)) {
|
|
49
|
+
return [];
|
|
50
|
+
}
|
|
51
|
+
const path = `schema.fields[${index}].dataSource`;
|
|
52
|
+
const source = this.registry.get(field.dataSource.key, field.dataSource.version);
|
|
53
|
+
if (!source) {
|
|
54
|
+
return [`${path} ${this.readMissingSourceCode(field.dataSource.key)}`];
|
|
55
|
+
}
|
|
56
|
+
const descriptorErrors = this.readDescriptorErrors(source.descriptor);
|
|
57
|
+
const controlErrors = this.readControlErrors(field, source.descriptor, path);
|
|
58
|
+
const bindingErrors = this.readBindingEnvironmentErrors(field.dataSource, source.descriptor, path);
|
|
59
|
+
return [...descriptorErrors, ...controlErrors, ...bindingErrors];
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
async previewFormFieldOptions(input, authContext) {
|
|
63
|
+
const { schema } = this.parseSchema(input.schemaJson, input.uiSchemaJson);
|
|
64
|
+
this.assertEnvironmentSchema(schema);
|
|
65
|
+
const field = this.readOptionField(schema, input.fieldKey);
|
|
66
|
+
const formData = this.parseFormData(input.formDataJson);
|
|
67
|
+
return this.searchFormFieldOptions({
|
|
68
|
+
authContext,
|
|
69
|
+
cursor: input.cursor ?? null,
|
|
70
|
+
field,
|
|
71
|
+
formData,
|
|
72
|
+
searchText: input.searchText ?? '',
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
async formFieldOptions(input, authContext) {
|
|
76
|
+
const context = await this.readRuntimeSchema(input, authContext);
|
|
77
|
+
const field = this.readOptionField(context.schema, input.fieldKey);
|
|
78
|
+
const formData = this.parseFormData(input.formDataJson);
|
|
79
|
+
return this.searchFormFieldOptions({
|
|
80
|
+
authContext,
|
|
81
|
+
cursor: input.cursor ?? null,
|
|
82
|
+
field,
|
|
83
|
+
formData,
|
|
84
|
+
searchText: input.searchText ?? '',
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
async searchFormFieldOptions(input) {
|
|
88
|
+
const field = this.readDynamicOptionField(input.field);
|
|
89
|
+
const source = this.readSourceOrThrow(field.dataSource);
|
|
90
|
+
this.assertControlSupported(field, source.descriptor);
|
|
91
|
+
const bindings = this.readBindingValues(field, source.descriptor, input.formData);
|
|
92
|
+
if (bindings.missingParameters.length > 0) {
|
|
93
|
+
throw new form_data_source_errors_1.BPMFormDataSourceException(form_data_source_errors_1.BPM_FORM_DATA_SOURCE_ERROR_CODES.WAITING_FOR_DEPENDENCIES);
|
|
94
|
+
}
|
|
95
|
+
const searchText = input.searchText.trim();
|
|
96
|
+
this.assertSearchRequest(source.descriptor, searchText, input.cursor);
|
|
97
|
+
const result = await this.callProvider(source, 'search', (signal) => source.search({
|
|
98
|
+
authContext: input.authContext,
|
|
99
|
+
bindings: bindings.values,
|
|
100
|
+
cursor: input.cursor,
|
|
101
|
+
searchText,
|
|
102
|
+
signal,
|
|
103
|
+
}));
|
|
104
|
+
const options = this.validateSearchResult(result, source.descriptor);
|
|
105
|
+
return {
|
|
106
|
+
dataSourceKey: source.descriptor.key,
|
|
107
|
+
dataSourceVersion: source.descriptor.version,
|
|
108
|
+
nextCursor: this.readNextCursor(result, source.descriptor),
|
|
109
|
+
options,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
async resolveFormFieldOptions(input) {
|
|
113
|
+
const field = this.readDynamicOptionField(input.field);
|
|
114
|
+
const source = this.readSourceOrThrow(field.dataSource);
|
|
115
|
+
this.assertControlSupported(field, source.descriptor);
|
|
116
|
+
const values = this.validateRequestedValues(input.values, source.descriptor.maximumResultCount);
|
|
117
|
+
const bindings = this.readBindingValues(field, source.descriptor, input.formData);
|
|
118
|
+
if (bindings.missingParameters.length > 0) {
|
|
119
|
+
throw new form_data_source_errors_1.BPMFormDataSourceException(form_data_source_errors_1.BPM_FORM_DATA_SOURCE_ERROR_CODES.WAITING_FOR_DEPENDENCIES);
|
|
120
|
+
}
|
|
121
|
+
const result = await this.callProvider(source, 'resolve', (signal) => source.resolve({
|
|
122
|
+
authContext: input.authContext,
|
|
123
|
+
bindings: bindings.values,
|
|
124
|
+
signal,
|
|
125
|
+
values,
|
|
126
|
+
}));
|
|
127
|
+
const options = this.validateResolveResult(result, values, source.descriptor.maximumResultCount);
|
|
128
|
+
const optionByValue = new Map(options.map((option) => [
|
|
129
|
+
option.value,
|
|
130
|
+
option,
|
|
131
|
+
]));
|
|
132
|
+
return values.map((value) => optionByValue.get(value));
|
|
133
|
+
}
|
|
134
|
+
async readRuntimeSchema(input, authContext) {
|
|
135
|
+
const templateId = readOptionalText(input.templateId);
|
|
136
|
+
const instanceId = readOptionalText(input.instanceId);
|
|
137
|
+
if (Boolean(templateId) === Boolean(instanceId)) {
|
|
138
|
+
throw new form_data_source_errors_1.BPMFormDataSourceForbiddenException(form_data_source_errors_1.BPM_FORM_DATA_SOURCE_ERROR_CODES.RUNTIME_CONTEXT_FORBIDDEN);
|
|
139
|
+
}
|
|
140
|
+
if (templateId) {
|
|
141
|
+
const launchableTemplates = await this.workflowEngineService.listLaunchableApprovalTemplates(authContext.memberId);
|
|
142
|
+
const template = launchableTemplates.find((candidate) => candidate.id === templateId);
|
|
143
|
+
if (!template?.currentVersionId) {
|
|
144
|
+
throw new form_data_source_errors_1.BPMFormDataSourceForbiddenException(form_data_source_errors_1.BPM_FORM_DATA_SOURCE_ERROR_CODES.RUNTIME_CONTEXT_FORBIDDEN);
|
|
145
|
+
}
|
|
146
|
+
const templateVersion = await this.approvalTemplateVersionRepository.findOne({
|
|
147
|
+
where: {
|
|
148
|
+
id: template.currentVersionId,
|
|
149
|
+
status: template_enums_1.ApprovalTemplateVersionStatusEnum.PUBLISHED,
|
|
150
|
+
},
|
|
151
|
+
});
|
|
152
|
+
if (!templateVersion?.formDefinitionVersionId) {
|
|
153
|
+
throw new form_data_source_errors_1.BPMFormDataSourceForbiddenException(form_data_source_errors_1.BPM_FORM_DATA_SOURCE_ERROR_CODES.RUNTIME_CONTEXT_FORBIDDEN);
|
|
154
|
+
}
|
|
155
|
+
return this.readPublishedFormSchema(templateVersion.formDefinitionVersionId);
|
|
156
|
+
}
|
|
157
|
+
const instance = await this.workflowEngineService.getApprovalInstance(instanceId, authContext);
|
|
158
|
+
if (instance.initiatorMemberId !== authContext.memberId ||
|
|
159
|
+
instance.state !== workflow_engine_enums_1.ApprovalInstanceStateEnum.RETURNED) {
|
|
160
|
+
throw new form_data_source_errors_1.BPMFormDataSourceForbiddenException(form_data_source_errors_1.BPM_FORM_DATA_SOURCE_ERROR_CODES.RUNTIME_CONTEXT_FORBIDDEN);
|
|
161
|
+
}
|
|
162
|
+
const snapshot = instance.formDefinitionSnapshot;
|
|
163
|
+
const schema = isRecord(snapshot.schema) ? snapshot.schema : null;
|
|
164
|
+
const uiSchema = isRecord(snapshot.uiSchema) ? snapshot.uiSchema : null;
|
|
165
|
+
if (!schema || !uiSchema) {
|
|
166
|
+
throw new form_data_source_errors_1.BPMFormDataSourceForbiddenException(form_data_source_errors_1.BPM_FORM_DATA_SOURCE_ERROR_CODES.RUNTIME_CONTEXT_FORBIDDEN);
|
|
167
|
+
}
|
|
168
|
+
return this.parseSchema(JSON.stringify(schema), JSON.stringify(uiSchema));
|
|
169
|
+
}
|
|
170
|
+
async readPublishedFormSchema(formDefinitionVersionId) {
|
|
171
|
+
const version = await this.formDefinitionVersionRepository.findOne({
|
|
172
|
+
where: {
|
|
173
|
+
id: formDefinitionVersionId,
|
|
174
|
+
status: form_enums_1.FormDefinitionVersionStatusEnum.PUBLISHED,
|
|
175
|
+
},
|
|
176
|
+
});
|
|
177
|
+
if (!version) {
|
|
178
|
+
throw new form_data_source_errors_1.BPMFormDataSourceForbiddenException(form_data_source_errors_1.BPM_FORM_DATA_SOURCE_ERROR_CODES.RUNTIME_CONTEXT_FORBIDDEN);
|
|
179
|
+
}
|
|
180
|
+
return this.parseSchema(JSON.stringify(version.schema), JSON.stringify(version.uiSchema));
|
|
181
|
+
}
|
|
182
|
+
parseSchema(schemaJson, uiSchemaJson) {
|
|
183
|
+
try {
|
|
184
|
+
const parsed = (0, form_schema_validator_1.parseAndValidateFormSchemas)(schemaJson, uiSchemaJson);
|
|
185
|
+
return {
|
|
186
|
+
schema: parsed.schema,
|
|
187
|
+
uiSchemaJson: JSON.stringify(parsed.uiSchema),
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
throw new common_1.BadRequestException('Form DataSource schema is invalid');
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
assertEnvironmentSchema(schema) {
|
|
195
|
+
const errors = this.lintDefinitionSchemaEnvironment(schema);
|
|
196
|
+
if (errors.length === 0) {
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
// Report the code of the FIRST error that carries one, deciding by line
|
|
200
|
+
// shape: the emitted `<path>.dataSource <CODE>` form, else a binding line
|
|
201
|
+
// whose code is implied rather than written (its prose quotes a
|
|
202
|
+
// designer-chosen name that must never be read as a code), else the
|
|
203
|
+
// descriptor fallback. Scanning the code list with `includes()` instead
|
|
204
|
+
// made the answer depend on enum declaration order and would misfire the
|
|
205
|
+
// day one code becomes a substring of another.
|
|
206
|
+
const [code] = errors.flatMap((error) => {
|
|
207
|
+
const candidate = readLintLineErrorCode(error);
|
|
208
|
+
return candidate ? [candidate] : readBindingLintErrorCode(error);
|
|
209
|
+
});
|
|
210
|
+
throw new form_data_source_errors_1.BPMFormDataSourceException(code ?? form_data_source_errors_1.BPM_FORM_DATA_SOURCE_ERROR_CODES.INVALID_DESCRIPTOR);
|
|
211
|
+
}
|
|
212
|
+
parseFormData(formDataJson) {
|
|
213
|
+
if (!formDataJson?.trim()) {
|
|
214
|
+
return {};
|
|
215
|
+
}
|
|
216
|
+
try {
|
|
217
|
+
const value = JSON.parse(formDataJson);
|
|
218
|
+
if (isRecord(value)) {
|
|
219
|
+
return value;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
catch {
|
|
223
|
+
// The stable error below deliberately hides parser details.
|
|
224
|
+
}
|
|
225
|
+
throw new form_data_source_errors_1.BPMFormDataSourceException(form_data_source_errors_1.BPM_FORM_DATA_SOURCE_ERROR_CODES.INVALID_BINDING);
|
|
226
|
+
}
|
|
227
|
+
readOptionField(schema, fieldKey) {
|
|
228
|
+
const field = schema.fields.find((candidate) => candidate.fieldKey === fieldKey);
|
|
229
|
+
if (!field || !isFormOptionField(field)) {
|
|
230
|
+
throw new form_data_source_errors_1.BPMFormDataSourceException(form_data_source_errors_1.BPM_FORM_DATA_SOURCE_ERROR_CODES.FIELD_NOT_DYNAMIC);
|
|
231
|
+
}
|
|
232
|
+
return field;
|
|
233
|
+
}
|
|
234
|
+
readDynamicOptionField(field) {
|
|
235
|
+
if (!(0, form_1.isFormDataSourceFieldDefinition)(field)) {
|
|
236
|
+
throw new form_data_source_errors_1.BPMFormDataSourceException(form_data_source_errors_1.BPM_FORM_DATA_SOURCE_ERROR_CODES.FIELD_NOT_DYNAMIC);
|
|
237
|
+
}
|
|
238
|
+
return field;
|
|
239
|
+
}
|
|
240
|
+
readSourceOrThrow(reference) {
|
|
241
|
+
const source = this.registry.get(reference.key, reference.version);
|
|
242
|
+
if (!source) {
|
|
243
|
+
throw new form_data_source_errors_1.BPMFormDataSourceException(this.readMissingSourceCode(reference.key));
|
|
244
|
+
}
|
|
245
|
+
const descriptorErrors = this.readDescriptorErrors(source.descriptor);
|
|
246
|
+
if (descriptorErrors.length > 0) {
|
|
247
|
+
throw new form_data_source_errors_1.BPMFormDataSourceException(form_data_source_errors_1.BPM_FORM_DATA_SOURCE_ERROR_CODES.INVALID_DESCRIPTOR);
|
|
248
|
+
}
|
|
249
|
+
return source;
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* A key the host never registered and a key whose requested version was
|
|
253
|
+
* dropped are different operational problems, so they keep distinct codes:
|
|
254
|
+
* the first tells the designer the source is gone, the second that only this
|
|
255
|
+
* version is.
|
|
256
|
+
*/
|
|
257
|
+
readMissingSourceCode(key) {
|
|
258
|
+
const hasKey = this.registry
|
|
259
|
+
.list()
|
|
260
|
+
.some((candidate) => candidate.descriptor?.key === key);
|
|
261
|
+
return hasKey
|
|
262
|
+
? form_data_source_errors_1.BPM_FORM_DATA_SOURCE_ERROR_CODES.DATA_SOURCE_VERSION_MISSING
|
|
263
|
+
: form_data_source_errors_1.BPM_FORM_DATA_SOURCE_ERROR_CODES.DATA_SOURCE_MISSING;
|
|
264
|
+
}
|
|
265
|
+
assertControlSupported(field, descriptor) {
|
|
266
|
+
const control = field.type;
|
|
267
|
+
if (!descriptor.supportedControls.includes(control)) {
|
|
268
|
+
throw new form_data_source_errors_1.BPMFormDataSourceException(form_data_source_errors_1.BPM_FORM_DATA_SOURCE_ERROR_CODES.UNSUPPORTED_CONTROL);
|
|
269
|
+
}
|
|
270
|
+
if ((control === 'radio' || control === 'checkbox') &&
|
|
271
|
+
(!descriptor.returnsCompleteList || descriptor.maximumResultCount > 50)) {
|
|
272
|
+
throw new form_data_source_errors_1.BPMFormDataSourceException(form_data_source_errors_1.BPM_FORM_DATA_SOURCE_ERROR_CODES.UNSUPPORTED_CONTROL);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
assertSearchRequest(descriptor, searchText, cursor) {
|
|
276
|
+
if (!descriptor.supportsSearch && searchText) {
|
|
277
|
+
throw new form_data_source_errors_1.BPMFormDataSourceException(form_data_source_errors_1.BPM_FORM_DATA_SOURCE_ERROR_CODES.SEARCH_NOT_SUPPORTED);
|
|
278
|
+
}
|
|
279
|
+
if (descriptor.supportsSearch &&
|
|
280
|
+
searchText.length > 0 &&
|
|
281
|
+
searchText.length < descriptor.minimumSearchLength) {
|
|
282
|
+
throw new form_data_source_errors_1.BPMFormDataSourceException(form_data_source_errors_1.BPM_FORM_DATA_SOURCE_ERROR_CODES.SEARCH_TOO_SHORT);
|
|
283
|
+
}
|
|
284
|
+
if (cursor && descriptor.paginationMode === 'NONE') {
|
|
285
|
+
throw new form_data_source_errors_1.BPMFormDataSourceException(form_data_source_errors_1.BPM_FORM_DATA_SOURCE_ERROR_CODES.INVALID_BINDING);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
readBindingValues(field, descriptor, formData) {
|
|
289
|
+
const parameterByKey = new Map(descriptor.parameters.map((parameter) => [
|
|
290
|
+
parameter.key,
|
|
291
|
+
parameter,
|
|
292
|
+
]));
|
|
293
|
+
const bindingValues = field.dataSource.bindings.reduce((values, binding) => {
|
|
294
|
+
const parameter = parameterByKey.get(binding.parameter);
|
|
295
|
+
if (!parameter) {
|
|
296
|
+
throw new form_data_source_errors_1.BPMFormDataSourceException(form_data_source_errors_1.BPM_FORM_DATA_SOURCE_ERROR_CODES.INVALID_BINDING);
|
|
297
|
+
}
|
|
298
|
+
const nextValue = binding.from.kind === 'FIELD'
|
|
299
|
+
? readFormDataValue(formData[binding.from.fieldKey])
|
|
300
|
+
: binding.from.value;
|
|
301
|
+
if (typeof nextValue === 'undefined') {
|
|
302
|
+
return values;
|
|
303
|
+
}
|
|
304
|
+
this.assertParameterValue(parameter, nextValue);
|
|
305
|
+
return { ...values, [parameter.key]: nextValue };
|
|
306
|
+
}, {});
|
|
307
|
+
const missingParameters = descriptor.parameters
|
|
308
|
+
.filter((parameter) => parameter.required)
|
|
309
|
+
.filter((parameter) => !isPresentFormDataValue(bindingValues[parameter.key]))
|
|
310
|
+
.map((parameter) => parameter.key);
|
|
311
|
+
if (JSON.stringify(bindingValues).length > MAX_PARAMETER_BYTES) {
|
|
312
|
+
throw new form_data_source_errors_1.BPMFormDataSourceException(form_data_source_errors_1.BPM_FORM_DATA_SOURCE_ERROR_CODES.PARAMETER_LIMIT_EXCEEDED);
|
|
313
|
+
}
|
|
314
|
+
return { missingParameters, values: bindingValues };
|
|
315
|
+
}
|
|
316
|
+
assertParameterValue(parameter, value) {
|
|
317
|
+
const valid = (parameter.type === 'BOOLEAN' && typeof value === 'boolean') ||
|
|
318
|
+
(parameter.type === 'NUMBER' && typeof value === 'number') ||
|
|
319
|
+
(parameter.type === 'STRING' && typeof value === 'string') ||
|
|
320
|
+
(parameter.type === 'STRING_ARRAY' && isStringArray(value)) ||
|
|
321
|
+
value === null;
|
|
322
|
+
if (!valid) {
|
|
323
|
+
throw new form_data_source_errors_1.BPMFormDataSourceException(form_data_source_errors_1.BPM_FORM_DATA_SOURCE_ERROR_CODES.INVALID_BINDING);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
validateRequestedValues(values, maximumResultCount) {
|
|
327
|
+
if (values.length === 0 ||
|
|
328
|
+
values.some((value) => !value.trim()) ||
|
|
329
|
+
new Set(values).size !== values.length) {
|
|
330
|
+
throw new form_data_source_errors_1.BPMFormDataSourceException(form_data_source_errors_1.BPM_FORM_DATA_SOURCE_ERROR_CODES.INVALID_BINDING);
|
|
331
|
+
}
|
|
332
|
+
if (values.length > maximumResultCount) {
|
|
333
|
+
throw new form_data_source_errors_1.BPMFormDataSourceException(form_data_source_errors_1.BPM_FORM_DATA_SOURCE_ERROR_CODES.RESULT_LIMIT_EXCEEDED);
|
|
334
|
+
}
|
|
335
|
+
return [...values];
|
|
336
|
+
}
|
|
337
|
+
validateSearchResult(result, descriptor) {
|
|
338
|
+
if (!isRecord(result) || !Array.isArray(result.options)) {
|
|
339
|
+
throw new form_data_source_errors_1.BPMFormDataSourceException(form_data_source_errors_1.BPM_FORM_DATA_SOURCE_ERROR_CODES.INVALID_PROVIDER_RESULT);
|
|
340
|
+
}
|
|
341
|
+
if (result.options.length > descriptor.pageSize ||
|
|
342
|
+
result.options.length > descriptor.maximumResultCount) {
|
|
343
|
+
throw new form_data_source_errors_1.BPMFormDataSourceException(form_data_source_errors_1.BPM_FORM_DATA_SOURCE_ERROR_CODES.RESULT_LIMIT_EXCEEDED);
|
|
344
|
+
}
|
|
345
|
+
return this.validateOptions(result.options);
|
|
346
|
+
}
|
|
347
|
+
validateResolveResult(result, values, maximumResultCount) {
|
|
348
|
+
if (!Array.isArray(result) || result.length > maximumResultCount) {
|
|
349
|
+
throw new form_data_source_errors_1.BPMFormDataSourceException(form_data_source_errors_1.BPM_FORM_DATA_SOURCE_ERROR_CODES.INVALID_PROVIDER_RESULT);
|
|
350
|
+
}
|
|
351
|
+
const options = this.validateOptions(result);
|
|
352
|
+
const requestedValues = new Set(values);
|
|
353
|
+
// A value the caller never asked for is a provider contract breach.
|
|
354
|
+
if (options.some((option) => !requestedValues.has(option.value))) {
|
|
355
|
+
throw new form_data_source_errors_1.BPMFormDataSourceException(form_data_source_errors_1.BPM_FORM_DATA_SOURCE_ERROR_CODES.INVALID_PROVIDER_RESULT);
|
|
356
|
+
}
|
|
357
|
+
// Every requested value resolved to exactly one option, or the submitted
|
|
358
|
+
// value is simply no longer selectable — that is a user-facing failure.
|
|
359
|
+
if (options.length !== values.length) {
|
|
360
|
+
throw new form_data_source_errors_1.BPMFormDataSourceException(form_data_source_errors_1.BPM_FORM_DATA_SOURCE_ERROR_CODES.VALUE_NOT_RESOLVED);
|
|
361
|
+
}
|
|
362
|
+
return options;
|
|
363
|
+
}
|
|
364
|
+
validateOptions(value) {
|
|
365
|
+
if (!Array.isArray(value)) {
|
|
366
|
+
throw new form_data_source_errors_1.BPMFormDataSourceException(form_data_source_errors_1.BPM_FORM_DATA_SOURCE_ERROR_CODES.INVALID_PROVIDER_RESULT);
|
|
367
|
+
}
|
|
368
|
+
const options = value.filter(isFormFieldOption);
|
|
369
|
+
if (options.length !== value.length ||
|
|
370
|
+
options.some((option) => !option.label.trim() || !option.value.trim()) ||
|
|
371
|
+
new Set(options.map((option) => option.value)).size !== options.length) {
|
|
372
|
+
throw new form_data_source_errors_1.BPMFormDataSourceException(form_data_source_errors_1.BPM_FORM_DATA_SOURCE_ERROR_CODES.INVALID_PROVIDER_RESULT);
|
|
373
|
+
}
|
|
374
|
+
return options;
|
|
375
|
+
}
|
|
376
|
+
readNextCursor(result, descriptor) {
|
|
377
|
+
const nextCursor = result.nextCursor ?? null;
|
|
378
|
+
if ((nextCursor !== null && typeof nextCursor !== 'string') ||
|
|
379
|
+
(descriptor.paginationMode === 'NONE' && nextCursor !== null)) {
|
|
380
|
+
throw new form_data_source_errors_1.BPMFormDataSourceException(form_data_source_errors_1.BPM_FORM_DATA_SOURCE_ERROR_CODES.INVALID_PROVIDER_RESULT);
|
|
381
|
+
}
|
|
382
|
+
return nextCursor;
|
|
383
|
+
}
|
|
384
|
+
async callProvider(source, operation, call) {
|
|
385
|
+
const controller = new AbortController();
|
|
386
|
+
let timeoutId;
|
|
387
|
+
const startedAt = Date.now();
|
|
388
|
+
try {
|
|
389
|
+
const result = await Promise.race([
|
|
390
|
+
call(controller.signal),
|
|
391
|
+
new Promise((_resolve, reject) => {
|
|
392
|
+
timeoutId = setTimeout(() => {
|
|
393
|
+
controller.abort();
|
|
394
|
+
const timeout = new Error('provider timeout');
|
|
395
|
+
Object.assign(timeout, { kind: 'FORM_DATA_SOURCE_TIMEOUT' });
|
|
396
|
+
reject(timeout);
|
|
397
|
+
}, PROVIDER_TIMEOUT_MS);
|
|
398
|
+
}),
|
|
399
|
+
]);
|
|
400
|
+
this.logger.log(JSON.stringify({
|
|
401
|
+
dataSourceKey: source.descriptor.key,
|
|
402
|
+
dataSourceVersion: source.descriptor.version,
|
|
403
|
+
durationMs: Date.now() - startedAt,
|
|
404
|
+
operation,
|
|
405
|
+
status: 'success',
|
|
406
|
+
}));
|
|
407
|
+
return result;
|
|
408
|
+
}
|
|
409
|
+
catch (error) {
|
|
410
|
+
const code = isTimeoutMarker(error)
|
|
411
|
+
? form_data_source_errors_1.BPM_FORM_DATA_SOURCE_ERROR_CODES.TIMEOUT
|
|
412
|
+
: form_data_source_errors_1.BPM_FORM_DATA_SOURCE_ERROR_CODES.PROVIDER_FAILURE;
|
|
413
|
+
this.logger.warn(JSON.stringify({
|
|
414
|
+
dataSourceKey: source.descriptor.key,
|
|
415
|
+
dataSourceVersion: source.descriptor.version,
|
|
416
|
+
durationMs: Date.now() - startedAt,
|
|
417
|
+
errorCode: code,
|
|
418
|
+
operation,
|
|
419
|
+
status: 'error',
|
|
420
|
+
}));
|
|
421
|
+
throw new form_data_source_errors_1.BPMFormDataSourceException(code);
|
|
422
|
+
}
|
|
423
|
+
finally {
|
|
424
|
+
if (timeoutId) {
|
|
425
|
+
clearTimeout(timeoutId);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
readDescriptorErrors(descriptor) {
|
|
430
|
+
const descriptorValue = isRecord(descriptor)
|
|
431
|
+
? descriptor
|
|
432
|
+
: {};
|
|
433
|
+
const parameters = Array.isArray(descriptorValue.parameters)
|
|
434
|
+
? descriptorValue.parameters
|
|
435
|
+
: [];
|
|
436
|
+
const supportedControls = Array.isArray(descriptorValue.supportedControls)
|
|
437
|
+
? descriptorValue.supportedControls
|
|
438
|
+
: [];
|
|
439
|
+
const version = descriptorValue.version;
|
|
440
|
+
const maximumResultCount = descriptorValue.maximumResultCount;
|
|
441
|
+
const pageSize = descriptorValue.pageSize;
|
|
442
|
+
const minimumSearchLength = descriptorValue.minimumSearchLength;
|
|
443
|
+
const errors = [
|
|
444
|
+
...(typeof descriptorValue.key === 'string' && descriptorValue.key.trim()
|
|
445
|
+
? []
|
|
446
|
+
: ['descriptor.key is required']),
|
|
447
|
+
...(typeof descriptorValue.label === 'string' && descriptorValue.label.trim()
|
|
448
|
+
? []
|
|
449
|
+
: ['descriptor.label is required']),
|
|
450
|
+
...(isPositiveInteger(version)
|
|
451
|
+
? []
|
|
452
|
+
: ['descriptor.version must be a positive integer']),
|
|
453
|
+
...(isPositiveInteger(maximumResultCount)
|
|
454
|
+
? []
|
|
455
|
+
: ['descriptor.maximumResultCount must be positive']),
|
|
456
|
+
...(isPositiveInteger(pageSize)
|
|
457
|
+
? []
|
|
458
|
+
: ['descriptor.pageSize must be positive']),
|
|
459
|
+
...(isNonNegativeInteger(minimumSearchLength)
|
|
460
|
+
? []
|
|
461
|
+
: ['descriptor.minimumSearchLength must be non-negative']),
|
|
462
|
+
...(typeof pageSize === 'number' &&
|
|
463
|
+
typeof maximumResultCount === 'number' &&
|
|
464
|
+
pageSize <= maximumResultCount
|
|
465
|
+
? []
|
|
466
|
+
: ['descriptor.pageSize cannot exceed descriptor.maximumResultCount']),
|
|
467
|
+
...(descriptorValue.paginationMode === 'CURSOR' ||
|
|
468
|
+
descriptorValue.paginationMode === 'NONE'
|
|
469
|
+
? []
|
|
470
|
+
: ['descriptor.paginationMode is invalid']),
|
|
471
|
+
...(descriptorValue.revalidationPolicy === 'ALWAYS' ||
|
|
472
|
+
descriptorValue.revalidationPolicy === 'WHEN_VALUE_OR_BINDINGS_CHANGE'
|
|
473
|
+
? []
|
|
474
|
+
: ['descriptor.revalidationPolicy is invalid']),
|
|
475
|
+
...(Array.isArray(descriptorValue.parameters)
|
|
476
|
+
? []
|
|
477
|
+
: ['descriptor.parameters must be an array']),
|
|
478
|
+
...(typeof descriptorValue.returnsCompleteList === 'boolean'
|
|
479
|
+
? []
|
|
480
|
+
: ['descriptor.returnsCompleteList must be boolean']),
|
|
481
|
+
...(typeof descriptorValue.supportsSearch === 'boolean'
|
|
482
|
+
? []
|
|
483
|
+
: ['descriptor.supportsSearch must be boolean']),
|
|
484
|
+
...(Array.isArray(descriptorValue.supportedControls) &&
|
|
485
|
+
supportedControls.every((control) => SOURCE_CONTROLS.includes(control))
|
|
486
|
+
? []
|
|
487
|
+
: ['descriptor.supportedControls contains an invalid control']),
|
|
488
|
+
...(new Set(supportedControls).size === supportedControls.length
|
|
489
|
+
? []
|
|
490
|
+
: ['descriptor.supportedControls contains duplicates']),
|
|
491
|
+
];
|
|
492
|
+
const parameterErrors = Array.isArray(descriptorValue.parameters)
|
|
493
|
+
? parameters.flatMap((parameter, index) => this.readParameterErrors(parameter, index))
|
|
494
|
+
: [];
|
|
495
|
+
const parameterKeys = parameters.flatMap((parameter) => isRecord(parameter) && typeof parameter.key === 'string'
|
|
496
|
+
? [parameter.key]
|
|
497
|
+
: []);
|
|
498
|
+
const duplicateParameterKeys = Array.isArray(descriptorValue.parameters)
|
|
499
|
+
? [
|
|
500
|
+
...new Set(parameterKeys
|
|
501
|
+
.filter((key, index, keys) => keys.indexOf(key) !== index)),
|
|
502
|
+
]
|
|
503
|
+
: [];
|
|
504
|
+
const duplicateParameterErrors = duplicateParameterKeys.map((key) => `descriptor.parameters.key is duplicated: ${key}`);
|
|
505
|
+
return [...errors, ...parameterErrors, ...duplicateParameterErrors];
|
|
506
|
+
}
|
|
507
|
+
readParameterErrors(parameter, index) {
|
|
508
|
+
const parameterValue = isRecord(parameter) ? parameter : {};
|
|
509
|
+
return [
|
|
510
|
+
...(typeof parameterValue.key === 'string' && parameterValue.key.trim()
|
|
511
|
+
? []
|
|
512
|
+
: [`descriptor.parameters[${index}].key is required`]),
|
|
513
|
+
...(typeof parameterValue.required === 'boolean'
|
|
514
|
+
? []
|
|
515
|
+
: [`descriptor.parameters[${index}].required must be boolean`]),
|
|
516
|
+
...(PARAMETER_TYPES.includes(parameterValue.type)
|
|
517
|
+
? []
|
|
518
|
+
: [`descriptor.parameters[${index}].type is invalid`]),
|
|
519
|
+
];
|
|
520
|
+
}
|
|
521
|
+
readControlErrors(field, descriptor, path) {
|
|
522
|
+
const control = field.type;
|
|
523
|
+
const declaresControl = descriptor.supportedControls.includes(control);
|
|
524
|
+
const allowsCompleteList = control !== 'radio' && control !== 'checkbox'
|
|
525
|
+
? true
|
|
526
|
+
: descriptor.returnsCompleteList && descriptor.maximumResultCount <= 50;
|
|
527
|
+
// Both checks fail the same control for the same reason, so report the code
|
|
528
|
+
// once instead of repeating it in the field-level error list.
|
|
529
|
+
return declaresControl && allowsCompleteList
|
|
530
|
+
? []
|
|
531
|
+
: [`${path} ${form_data_source_errors_1.BPM_FORM_DATA_SOURCE_ERROR_CODES.UNSUPPORTED_CONTROL}`];
|
|
532
|
+
}
|
|
533
|
+
readBindingEnvironmentErrors(reference, descriptor, path) {
|
|
534
|
+
const parameterKeys = new Set(descriptor.parameters.map((parameter) => parameter.key));
|
|
535
|
+
const bindingKeys = new Set(reference.bindings.map((binding) => binding.parameter));
|
|
536
|
+
const missingRequired = descriptor.parameters
|
|
537
|
+
.filter((parameter) => parameter.required && !bindingKeys.has(parameter.key))
|
|
538
|
+
.map((parameter) => `${path}.bindings missing required parameter: ${parameter.key}`);
|
|
539
|
+
const unknownParameters = reference.bindings
|
|
540
|
+
.filter((binding) => !parameterKeys.has(binding.parameter))
|
|
541
|
+
.map((binding) => `${path}.bindings unknown parameter: ${binding.parameter}`);
|
|
542
|
+
return [...missingRequired, ...unknownParameters];
|
|
543
|
+
}
|
|
544
|
+
};
|
|
545
|
+
exports.FormDataSourceService = FormDataSourceService;
|
|
546
|
+
exports.FormDataSourceService = FormDataSourceService = FormDataSourceService_1 = tslib_1.__decorate([
|
|
547
|
+
(0, common_1.Injectable)(),
|
|
548
|
+
tslib_1.__param(0, (0, common_1.Inject)(form_data_source_types_1.BPM_FORM_DATA_SOURCE_REGISTRY)),
|
|
549
|
+
tslib_1.__param(1, (0, typeorm_1.InjectRepository)(approval_template_version_entity_1.ApprovalTemplateVersionEntity)),
|
|
550
|
+
tslib_1.__param(2, (0, typeorm_1.InjectRepository)(form_definition_version_entity_1.FormDefinitionVersionEntity)),
|
|
551
|
+
tslib_1.__metadata("design:paramtypes", [Object, typeorm_2.Repository,
|
|
552
|
+
typeorm_2.Repository,
|
|
553
|
+
workflow_engine_service_1.WorkflowEngineService])
|
|
554
|
+
], FormDataSourceService);
|
|
555
|
+
function isFormOptionField(field) {
|
|
556
|
+
return (field.type === 'select' ||
|
|
557
|
+
field.type === 'autocomplete' ||
|
|
558
|
+
field.type === 'radio' ||
|
|
559
|
+
field.type === 'checkbox');
|
|
560
|
+
}
|
|
561
|
+
function isFormFieldOption(value) {
|
|
562
|
+
return (isRecord(value) &&
|
|
563
|
+
typeof value.label === 'string' &&
|
|
564
|
+
typeof value.value === 'string');
|
|
565
|
+
}
|
|
566
|
+
function isRecord(value) {
|
|
567
|
+
return typeof value === 'object' && value !== null;
|
|
568
|
+
}
|
|
569
|
+
function isStringArray(value) {
|
|
570
|
+
return Array.isArray(value) && value.every((item) => typeof item === 'string');
|
|
571
|
+
}
|
|
572
|
+
function readFormDataValue(value) {
|
|
573
|
+
if (value === null ||
|
|
574
|
+
typeof value === 'boolean' ||
|
|
575
|
+
typeof value === 'number' ||
|
|
576
|
+
typeof value === 'string' ||
|
|
577
|
+
isStringArrayValue(value)) {
|
|
578
|
+
return value;
|
|
579
|
+
}
|
|
580
|
+
if (typeof value === 'undefined') {
|
|
581
|
+
return undefined;
|
|
582
|
+
}
|
|
583
|
+
throw new form_data_source_errors_1.BPMFormDataSourceException(form_data_source_errors_1.BPM_FORM_DATA_SOURCE_ERROR_CODES.INVALID_BINDING);
|
|
584
|
+
}
|
|
585
|
+
function isStringArrayValue(value) {
|
|
586
|
+
return Array.isArray(value) && value.every((item) => typeof item === 'string');
|
|
587
|
+
}
|
|
588
|
+
function isPresentFormDataValue(value) {
|
|
589
|
+
if (typeof value === 'undefined' || value === null) {
|
|
590
|
+
return false;
|
|
591
|
+
}
|
|
592
|
+
if (typeof value === 'string') {
|
|
593
|
+
return value.trim().length > 0;
|
|
594
|
+
}
|
|
595
|
+
if (Array.isArray(value)) {
|
|
596
|
+
return value.length > 0;
|
|
597
|
+
}
|
|
598
|
+
return true;
|
|
599
|
+
}
|
|
600
|
+
function readOptionalText(value) {
|
|
601
|
+
const text = value?.trim() ?? '';
|
|
602
|
+
return text || null;
|
|
603
|
+
}
|
|
604
|
+
function isTimeoutMarker(value) {
|
|
605
|
+
return (value instanceof Error &&
|
|
606
|
+
value.kind ===
|
|
607
|
+
'FORM_DATA_SOURCE_TIMEOUT');
|
|
608
|
+
}
|
|
609
|
+
/**
|
|
610
|
+
* Matches only the code-bearing lint shape `<path>.dataSource <CODE>`. Reading
|
|
611
|
+
* the trailing token alone would misreport prose such as
|
|
612
|
+
* `...bindings unknown parameter: FORM_DATA_SOURCE_TIMEOUT`, where the code-like
|
|
613
|
+
* text is a parameter name — chosen by the host in its descriptor, or by the
|
|
614
|
+
* designer in a binding — rather than an error code.
|
|
615
|
+
*/
|
|
616
|
+
const LINT_LINE_CODE_PATTERN = /^\S+\.dataSource (FORM_DATA_SOURCE_[A-Z_]+)$/u;
|
|
617
|
+
/**
|
|
618
|
+
* Binding lint lines stay prose because they quote a parameter name chosen by
|
|
619
|
+
* the host or the designer, so their code is derived from the line shape
|
|
620
|
+
* instead of being appended
|
|
621
|
+
* to the text — appending it would put a raw code back on the designer's lint
|
|
622
|
+
* panel, which the client formatter deliberately never rewrites inside prose.
|
|
623
|
+
*
|
|
624
|
+
* Without this the preview would fall back to `INVALID_DESCRIPTOR` ("contact
|
|
625
|
+
* your administrator") for a binding the designer can fix themselves.
|
|
626
|
+
*/
|
|
627
|
+
const LINT_BINDING_LINE_PATTERN = /^schema\.fields\[\d+\]\.dataSource\.bindings /u;
|
|
628
|
+
function readBindingLintErrorCode(error) {
|
|
629
|
+
return LINT_BINDING_LINE_PATTERN.test(error)
|
|
630
|
+
? [form_data_source_errors_1.BPM_FORM_DATA_SOURCE_ERROR_CODES.INVALID_BINDING]
|
|
631
|
+
: [];
|
|
632
|
+
}
|
|
633
|
+
function readLintLineErrorCode(error) {
|
|
634
|
+
const candidate = LINT_LINE_CODE_PATTERN.exec(error)?.[1];
|
|
635
|
+
return candidate && isFormDataSourceErrorCode(candidate) ? candidate : null;
|
|
636
|
+
}
|
|
637
|
+
function isFormDataSourceErrorCode(value) {
|
|
638
|
+
return Object.values(form_data_source_errors_1.BPM_FORM_DATA_SOURCE_ERROR_CODES).includes(value);
|
|
639
|
+
}
|
|
640
|
+
function isPositiveInteger(value) {
|
|
641
|
+
return typeof value === 'number' && Number.isInteger(value) && value > 0;
|
|
642
|
+
}
|
|
643
|
+
function isNonNegativeInteger(value) {
|
|
644
|
+
return typeof value === 'number' && Number.isInteger(value) && value >= 0;
|
|
645
|
+
}
|
|
646
|
+
//# sourceMappingURL=form-data-source.service.js.map
|