@rytass/bpm-core-shared 0.17.6 โ 0.17.7
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 +30 -0
- package/package.json +1 -1
- package/src/index.d.ts +3 -0
- package/src/index.js +3 -0
- package/src/index.js.map +1 -1
- package/src/lib/field-access-lint.d.ts +119 -0
- package/src/lib/field-access-lint.js +379 -0
- package/src/lib/field-access-lint.js.map +1 -0
- package/src/lib/field-access-matrix.d.ts +101 -0
- package/src/lib/field-access-matrix.js +213 -0
- package/src/lib/field-access-matrix.js.map +1 -0
- package/src/lib/field-access.d.ts +63 -0
- package/src/lib/field-access.js +140 -0
- package/src/lib/field-access.js.map +1 -0
- package/src/lib/workflow-command.d.ts +26 -1
- package/src/lib/workflow-command.js +52 -0
- package/src/lib/workflow-command.js.map +1 -1
- package/src/lib/workflow-graph.d.ts +48 -0
- package/src/lib/workflow-graph.js +58 -1
- package/src/lib/workflow-graph.js.map +1 -1
- package/src/lib/workflow-toolset.js +77 -1
- package/src/lib/workflow-toolset.js.map +1 -1
- package/src/lib/workflow.d.ts +20 -4
- package/src/lib/workflow.js.map +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,33 @@
|
|
|
1
|
+
## 0.17.7 (2026-10-22)
|
|
2
|
+
|
|
3
|
+
### ๐ Features
|
|
4
|
+
|
|
5
|
+
- **bpm-core-react:** add the field access overview to the template designer ([1de7665](https://github.com/Rytass/BPMCore/commit/1de7665))
|
|
6
|
+
- **shared:** add the field access matrix and its commands ([b0a9aa3](https://github.com/Rytass/BPMCore/commit/b0a9aa3))
|
|
7
|
+
- **bpm-core-react:** let the fill node's approver fill in fields on the case page ([9cd9eb2](https://github.com/Rytass/BPMCore/commit/9cd9eb2))
|
|
8
|
+
- **bpm-core:** flag tasks whose node lets the approver fill in fields ([57f1d61](https://github.com/Rytass/BPMCore/commit/57f1d61))
|
|
9
|
+
- **bpm-core-react:** resolve per-field access for the instance viewer ([7cd040c](https://github.com/Rytass/BPMCore/commit/7cd040c))
|
|
10
|
+
- **bpm-core:** adopt fieldAccess node model per ADR 20 ([b25cf71](https://github.com/Rytass/BPMCore/commit/b25cf71))
|
|
11
|
+
- **bpm-core-client:** send approver-filled data and keep it off launch and resubmit forms ([a33d7f9](https://github.com/Rytass/BPMCore/commit/a33d7f9))
|
|
12
|
+
- **bpm-core:** refuse conditions that read approver-filled fields too early ([5ad995f](https://github.com/Rytass/BPMCore/commit/5ad995f))
|
|
13
|
+
- **bpm-core:** refuse form rules that clash with approver-filled fields ([a55253e](https://github.com/Rytass/BPMCore/commit/a55253e))
|
|
14
|
+
- **bpm-core:** refuse to publish field permissions the engine cannot honour ([7361a9e](https://github.com/Rytass/BPMCore/commit/7361a9e))
|
|
15
|
+
- **bpm-core:** flag task notifications that need the form opened ([77fd492](https://github.com/Rytass/BPMCore/commit/77fd492))
|
|
16
|
+
- **bpm-core:** let the filling node write approver-filled fields on approval ([502500c](https://github.com/Rytass/BPMCore/commit/502500c))
|
|
17
|
+
- **shared:** add field permission helpers for approver-filled fields ([6386b1c](https://github.com/Rytass/BPMCore/commit/6386b1c))
|
|
18
|
+
|
|
19
|
+
### ๐ฉน Fixes
|
|
20
|
+
|
|
21
|
+
- **shared:** read a SET_FORM_FIELD path the way the engine writes it ([3ba2962](https://github.com/Rytass/BPMCore/commit/3ba2962))
|
|
22
|
+
- **bpm-core-react:** send only the fill fields the approver changed ([1250eac](https://github.com/Rytass/BPMCore/commit/1250eac))
|
|
23
|
+
- **template:** stop rethrowing designer save and publish errors ([af93e67](https://github.com/Rytass/BPMCore/commit/af93e67))
|
|
24
|
+
- **bpm-core-client:** update launch mocks for the template version definition ([452d600](https://github.com/Rytass/BPMCore/commit/452d600))
|
|
25
|
+
|
|
26
|
+
### โค๏ธ Thank You
|
|
27
|
+
|
|
28
|
+
- Chia Yu Pai @fantasywind
|
|
29
|
+
- Kai-Chieh Yang
|
|
30
|
+
|
|
1
31
|
## 0.17.6 (2026-10-20)
|
|
2
32
|
|
|
3
33
|
This was a version bump only for shared to align it with other projects, there were no code changes.
|
package/package.json
CHANGED
package/src/index.d.ts
CHANGED
package/src/index.js
CHANGED
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
4
|
tslib_1.__exportStar(require("./lib/condition"), exports);
|
|
5
|
+
tslib_1.__exportStar(require("./lib/field-access"), exports);
|
|
6
|
+
tslib_1.__exportStar(require("./lib/field-access-lint"), exports);
|
|
7
|
+
tslib_1.__exportStar(require("./lib/field-access-matrix"), exports);
|
|
5
8
|
tslib_1.__exportStar(require("./lib/form"), exports);
|
|
6
9
|
tslib_1.__exportStar(require("./lib/identity"), exports);
|
|
7
10
|
tslib_1.__exportStar(require("./lib/organization"), exports);
|
package/src/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../libs/shared/src/index.ts"],"names":[],"mappings":";;;AAAA,0DAAgC;AAChC,qDAA2B;AAC3B,yDAA+B;AAC/B,6DAAmC;AACnC,uDAA6B;AAC7B,yDAA+B;AAC/B,+DAAqC;AACrC,iEAAuC;AACvC,iEAAuC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../libs/shared/src/index.ts"],"names":[],"mappings":";;;AAAA,0DAAgC;AAChC,6DAAmC;AACnC,kEAAwC;AACxC,oEAA0C;AAC1C,qDAA2B;AAC3B,yDAA+B;AAC/B,6DAAmC;AACnC,uDAA6B;AAC7B,yDAA+B;AAC/B,+DAAqC;AACrC,iEAAuC;AACvC,iEAAuC"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { FormDefinitionSchema, FormFieldDefinition } from './form';
|
|
2
|
+
import type { FieldAccessDisplay, FieldAccessEntry, FieldAccessFill, UserTaskNode, WorkflowDefinition, WorkflowEdge } from './workflow';
|
|
3
|
+
/**
|
|
4
|
+
* The field access rules (ADR 20 ยง4) as structured issues. The publish lint
|
|
5
|
+
* turns each into its `message` line, and the designer's field access matrix
|
|
6
|
+
* places it on the fields and nodes it names, so the two read one rule set.
|
|
7
|
+
* `lintApproverFilledFieldReads` (a condition reading a field before anybody
|
|
8
|
+
* filled it in) stays in the backend: it needs the expression sources of
|
|
9
|
+
* every node, which the matrix does not show.
|
|
10
|
+
*/
|
|
11
|
+
export type FieldAccessIssueCode = 'applicantRuleReadsApproverFilled' | 'approverFilledFieldDataSource' | 'approverFilledFieldFileUpload' | 'approverFilledFieldFormRule' | 'approverFilledMultipleFillNodesOnPath' | 'approverFilledRequiredBoolean' | 'approverFilledTableDataSourceColumn' | 'fieldAccessAutoApprove' | 'fieldAccessDuplicate' | 'fieldAccessFillHidden' | 'fieldAccessGroupPolicy' | 'fieldAccessInvalid' | 'fieldAccessSkipNode' | 'fieldAccessUnknownField' | 'legacyFieldPermissions' | 'setFormFieldApproverFilled';
|
|
12
|
+
export interface FieldAccessIssue {
|
|
13
|
+
readonly code: FieldAccessIssueCode;
|
|
14
|
+
/** The top-level fields the issue is about, the offending one first. */
|
|
15
|
+
readonly fieldKeys: readonly string[];
|
|
16
|
+
/** The publish-lint line, from `WORKFLOW_LINT_MESSAGES`. */
|
|
17
|
+
readonly message: string;
|
|
18
|
+
/** The nodes the issue is about, in definition order where there are two. */
|
|
19
|
+
readonly nodeIds: readonly string[];
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Why a user task node cannot let its approver fill fields in: a decision
|
|
23
|
+
* shared by several approvers (`PARALLEL_ALL` / `QUORUM`) has no single
|
|
24
|
+
* filler, and a node that can approve or skip itself would pass without
|
|
25
|
+
* anybody filling anything in.
|
|
26
|
+
*/
|
|
27
|
+
export type UserTaskFillConflict = 'autoApprove' | 'groupPolicy' | 'skipNode';
|
|
28
|
+
export declare function readUserTaskFillConflicts(node: UserTaskNode): readonly UserTaskFillConflict[];
|
|
29
|
+
export declare const FIELD_ACCESS_DISPLAYS: readonly FieldAccessDisplay[];
|
|
30
|
+
export declare const FIELD_ACCESS_FILLS: readonly FieldAccessFill[];
|
|
31
|
+
/**
|
|
32
|
+
* Whether a stored entry is one the publish lint accepts. Stricter than
|
|
33
|
+
* `readNodeFieldAccess`, which the engine reads with: a blank `fieldKey`
|
|
34
|
+
* passes there and fails here, so writers check with this one.
|
|
35
|
+
*/
|
|
36
|
+
export declare function isFieldAccessEntryValid(entry: unknown): entry is FieldAccessEntry;
|
|
37
|
+
/**
|
|
38
|
+
* One user task node's issues, in publish-lint order: the deprecated
|
|
39
|
+
* `fieldPermissions` key first, then its `fieldAccess`.
|
|
40
|
+
*
|
|
41
|
+
* `fieldPermissions` was reserved and never enforced, so whatever a draft
|
|
42
|
+
* holds there means nothing. Rather than read it as `fieldAccess` (which would
|
|
43
|
+
* suddenly enforce a shape nobody tested) or drop it silently, a draft that
|
|
44
|
+
* still carries the key cannot be published until it is removed.
|
|
45
|
+
*
|
|
46
|
+
* The shape and duplicate checks read the raw `fieldAccess`:
|
|
47
|
+
* `readNodeFieldAccess` tolerates a bad draft by skipping malformed entries
|
|
48
|
+
* and keeping the first entry per `fieldKey`, which is exactly what these two
|
|
49
|
+
* checks have to see. Once the shape is reported, the node's other field
|
|
50
|
+
* access rules are skipped, since they would read a list the engine is not
|
|
51
|
+
* going to honour anyway. Whether each `fieldKey` names a top-level field of
|
|
52
|
+
* the form is checked against the form (`readFormFieldAccessIssues`).
|
|
53
|
+
*/
|
|
54
|
+
export declare function readNodeFieldAccessIssues(node: UserTaskNode): readonly FieldAccessIssue[];
|
|
55
|
+
/**
|
|
56
|
+
* The nodes reachable from `startNodeIds` along `edges` without entering one
|
|
57
|
+
* of `blockedNodeIds`, the start nodes included unless blocked. Walks the
|
|
58
|
+
* graph one frontier at a time and drops every node it has already seen, so a
|
|
59
|
+
* cycle ends the walk instead of feeding it.
|
|
60
|
+
*/
|
|
61
|
+
export declare function readReachableWorkflowNodeIds(edges: readonly WorkflowEdge[], startNodeIds: readonly string[], blockedNodeIds?: ReadonlySet<string>): ReadonlySet<string>;
|
|
62
|
+
/**
|
|
63
|
+
* Whether two nodes can both run in one case: one reaches the other, or a
|
|
64
|
+
* parallel split sends each down a branch of its own (reachable from one
|
|
65
|
+
* outgoing edge of the split but not from another, and the other way round).
|
|
66
|
+
* Nodes on mutually exclusive branches never both run, and neither do two
|
|
67
|
+
* nodes that both lie after the join, which every branch reaches alike. The
|
|
68
|
+
* graph may hold a cycle, which the reachability walk copes with.
|
|
69
|
+
*/
|
|
70
|
+
export declare function createWorkflowCoRunReader(definition: WorkflowDefinition): (nodeId: string, otherNodeId: string) => boolean;
|
|
71
|
+
/**
|
|
72
|
+
* The issues read from the whole definition, in publish-lint order: a system
|
|
73
|
+
* node writing an approver-filled field, then two fill nodes of one field
|
|
74
|
+
* that can both run in one case.
|
|
75
|
+
*
|
|
76
|
+
* A field an approver fills in is empty until then, and the approver's value
|
|
77
|
+
* is the one the case keeps. A system node writing it would either be
|
|
78
|
+
* overwritten or overwrite the approver, so the two are kept apart.
|
|
79
|
+
*
|
|
80
|
+
* One field, one filler per run: when two nodes that fill the same field in
|
|
81
|
+
* can both run in one case (`createWorkflowCoRunReader`), the later one
|
|
82
|
+
* overwrites the earlier and the signed value no longer tells who answered.
|
|
83
|
+
* Fill nodes on mutually exclusive branches (one per region, say) stay
|
|
84
|
+
* allowed. Reported once per field and pair, in node order.
|
|
85
|
+
*/
|
|
86
|
+
export declare function readDefinitionFieldAccessIssues(definition: WorkflowDefinition): readonly FieldAccessIssue[];
|
|
87
|
+
/**
|
|
88
|
+
* Why a form field cannot be one an approver fills in, as the issues the
|
|
89
|
+
* publish lint reports once it is: a form-level rule (`required` / `hidden`
|
|
90
|
+
* set to `true`, the others set at all โ `required: false` and
|
|
91
|
+
* `hidden: false`, what the form editor writes for "off", are not rules), a
|
|
92
|
+
* data source, a file upload, or a table with a data-source column. Empty
|
|
93
|
+
* when the field can be filled in.
|
|
94
|
+
*/
|
|
95
|
+
export declare function readFormFieldFillIssues(field: FormFieldDefinition): readonly FieldAccessIssue[];
|
|
96
|
+
/**
|
|
97
|
+
* True when a CEL expression reads the top-level form field `fieldKey` โ
|
|
98
|
+
* `form.x`, `formData.x`, `form["x"]`, or any of those with `form . x` spacing
|
|
99
|
+
* or a deeper step after it (`form.x.y`, `form.x[0]`). `has(form.x)` counts.
|
|
100
|
+
*
|
|
101
|
+
* The root has to be a bare `form` / `formData`: `myform.x` and `a.form.x` are
|
|
102
|
+
* somebody else's `x`. The key has to end there: `form.xy` is another field.
|
|
103
|
+
* `form` and `formData` are the two allowed root identifiers that carry the
|
|
104
|
+
* form data (`WORKFLOW_EXPRESSION_ROOT_IDENTIFIERS`). A string literal that
|
|
105
|
+
* merely spells `form.x` counts too: a false hit only makes the publish lint
|
|
106
|
+
* stricter.
|
|
107
|
+
*/
|
|
108
|
+
export declare function referencesFormField(expression: string, fieldKey: string): boolean;
|
|
109
|
+
/**
|
|
110
|
+
* The issues read against the form the definition is bound to, in
|
|
111
|
+
* publish-lint order: a `fieldKey` that is not a top-level field of the form,
|
|
112
|
+
* an approver-filled field the form will not let anybody fill in
|
|
113
|
+
* (`readFormFieldFillIssues`, once per field however many nodes fill it in),
|
|
114
|
+
* `fill: 'REQUIRED'` on a boolean (`false` is an answer, so required can never
|
|
115
|
+
* fail), and an applicant's rule that reads an approver-filled field โ the
|
|
116
|
+
* rule is evaluated against the submitted form, where that field is still
|
|
117
|
+
* empty, and the evaluation silently compares against nothing.
|
|
118
|
+
*/
|
|
119
|
+
export declare function readFormFieldAccessIssues(definition: WorkflowDefinition, schema: FormDefinitionSchema | null): readonly FieldAccessIssue[];
|
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FIELD_ACCESS_FILLS = exports.FIELD_ACCESS_DISPLAYS = void 0;
|
|
4
|
+
exports.readUserTaskFillConflicts = readUserTaskFillConflicts;
|
|
5
|
+
exports.isFieldAccessEntryValid = isFieldAccessEntryValid;
|
|
6
|
+
exports.readNodeFieldAccessIssues = readNodeFieldAccessIssues;
|
|
7
|
+
exports.readReachableWorkflowNodeIds = readReachableWorkflowNodeIds;
|
|
8
|
+
exports.createWorkflowCoRunReader = createWorkflowCoRunReader;
|
|
9
|
+
exports.readDefinitionFieldAccessIssues = readDefinitionFieldAccessIssues;
|
|
10
|
+
exports.readFormFieldFillIssues = readFormFieldFillIssues;
|
|
11
|
+
exports.referencesFormField = referencesFormField;
|
|
12
|
+
exports.readFormFieldAccessIssues = readFormFieldAccessIssues;
|
|
13
|
+
const form_1 = require("./form");
|
|
14
|
+
const field_access_1 = require("./field-access");
|
|
15
|
+
const workflow_graph_1 = require("./workflow-graph");
|
|
16
|
+
function readUserTaskFillConflicts(node) {
|
|
17
|
+
var _a, _b, _c, _d;
|
|
18
|
+
return [
|
|
19
|
+
...(((_a = node.data.decisionPolicy) === null || _a === void 0 ? void 0 : _a.type) === 'PARALLEL_ALL' ||
|
|
20
|
+
((_b = node.data.decisionPolicy) === null || _b === void 0 ? void 0 : _b.type) === 'QUORUM'
|
|
21
|
+
? ['groupPolicy']
|
|
22
|
+
: []),
|
|
23
|
+
...(((_c = node.data.sla) === null || _c === void 0 ? void 0 : _c.onTimeout) === 'AUTO_APPROVE'
|
|
24
|
+
? ['autoApprove']
|
|
25
|
+
: []),
|
|
26
|
+
...(((_d = node.data.excludeInitiator) === null || _d === void 0 ? void 0 : _d.whenEmpty) === 'SKIP_NODE'
|
|
27
|
+
? ['skipNode']
|
|
28
|
+
: []),
|
|
29
|
+
];
|
|
30
|
+
}
|
|
31
|
+
const FILL_CONFLICT_ISSUES = {
|
|
32
|
+
autoApprove: {
|
|
33
|
+
code: 'fieldAccessAutoApprove',
|
|
34
|
+
message: workflow_graph_1.WORKFLOW_LINT_MESSAGES.fieldAccessAutoApprove,
|
|
35
|
+
},
|
|
36
|
+
groupPolicy: {
|
|
37
|
+
code: 'fieldAccessGroupPolicy',
|
|
38
|
+
message: workflow_graph_1.WORKFLOW_LINT_MESSAGES.fieldAccessGroupPolicy,
|
|
39
|
+
},
|
|
40
|
+
skipNode: {
|
|
41
|
+
code: 'fieldAccessSkipNode',
|
|
42
|
+
message: workflow_graph_1.WORKFLOW_LINT_MESSAGES.fieldAccessSkipNode,
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
function isPlainRecord(value) {
|
|
46
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
47
|
+
}
|
|
48
|
+
exports.FIELD_ACCESS_DISPLAYS = [
|
|
49
|
+
'SHOW',
|
|
50
|
+
'HIDE',
|
|
51
|
+
];
|
|
52
|
+
exports.FIELD_ACCESS_FILLS = [
|
|
53
|
+
'NONE',
|
|
54
|
+
'OPTIONAL',
|
|
55
|
+
'REQUIRED',
|
|
56
|
+
];
|
|
57
|
+
/**
|
|
58
|
+
* Whether a stored entry is one the publish lint accepts. Stricter than
|
|
59
|
+
* `readNodeFieldAccess`, which the engine reads with: a blank `fieldKey`
|
|
60
|
+
* passes there and fails here, so writers check with this one.
|
|
61
|
+
*/
|
|
62
|
+
function isFieldAccessEntryValid(entry) {
|
|
63
|
+
return (isPlainRecord(entry) &&
|
|
64
|
+
typeof entry['fieldKey'] === 'string' &&
|
|
65
|
+
entry['fieldKey'].trim() !== '' &&
|
|
66
|
+
exports.FIELD_ACCESS_DISPLAYS.some((display) => display === entry['display']) &&
|
|
67
|
+
exports.FIELD_ACCESS_FILLS.some((fill) => fill === entry['fill']));
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* One user task node's issues, in publish-lint order: the deprecated
|
|
71
|
+
* `fieldPermissions` key first, then its `fieldAccess`.
|
|
72
|
+
*
|
|
73
|
+
* `fieldPermissions` was reserved and never enforced, so whatever a draft
|
|
74
|
+
* holds there means nothing. Rather than read it as `fieldAccess` (which would
|
|
75
|
+
* suddenly enforce a shape nobody tested) or drop it silently, a draft that
|
|
76
|
+
* still carries the key cannot be published until it is removed.
|
|
77
|
+
*
|
|
78
|
+
* The shape and duplicate checks read the raw `fieldAccess`:
|
|
79
|
+
* `readNodeFieldAccess` tolerates a bad draft by skipping malformed entries
|
|
80
|
+
* and keeping the first entry per `fieldKey`, which is exactly what these two
|
|
81
|
+
* checks have to see. Once the shape is reported, the node's other field
|
|
82
|
+
* access rules are skipped, since they would read a list the engine is not
|
|
83
|
+
* going to honour anyway. Whether each `fieldKey` names a top-level field of
|
|
84
|
+
* the form is checked against the form (`readFormFieldAccessIssues`).
|
|
85
|
+
*/
|
|
86
|
+
function readNodeFieldAccessIssues(node) {
|
|
87
|
+
const nodeId = node.id;
|
|
88
|
+
const legacy = node.data.fieldPermissions;
|
|
89
|
+
const legacyIssues = legacy === undefined
|
|
90
|
+
? []
|
|
91
|
+
: [
|
|
92
|
+
{
|
|
93
|
+
code: 'legacyFieldPermissions',
|
|
94
|
+
fieldKeys: [],
|
|
95
|
+
message: workflow_graph_1.WORKFLOW_LINT_MESSAGES.legacyFieldPermissions(nodeId),
|
|
96
|
+
nodeIds: [nodeId],
|
|
97
|
+
},
|
|
98
|
+
];
|
|
99
|
+
const raw = node.data.fieldAccess;
|
|
100
|
+
if (raw === undefined) {
|
|
101
|
+
return legacyIssues;
|
|
102
|
+
}
|
|
103
|
+
const entries = Array.isArray(raw)
|
|
104
|
+
? raw
|
|
105
|
+
: undefined;
|
|
106
|
+
if (entries === undefined || !entries.every(isFieldAccessEntryValid)) {
|
|
107
|
+
return [
|
|
108
|
+
...legacyIssues,
|
|
109
|
+
{
|
|
110
|
+
code: 'fieldAccessInvalid',
|
|
111
|
+
fieldKeys: [],
|
|
112
|
+
message: workflow_graph_1.WORKFLOW_LINT_MESSAGES.fieldAccessInvalid(nodeId),
|
|
113
|
+
nodeIds: [nodeId],
|
|
114
|
+
},
|
|
115
|
+
];
|
|
116
|
+
}
|
|
117
|
+
const fieldKeys = entries.map((entry) => entry.fieldKey);
|
|
118
|
+
const hasFillableField = (0, field_access_1.readNodeFillableFieldKeys)(node).size > 0;
|
|
119
|
+
return [
|
|
120
|
+
...legacyIssues,
|
|
121
|
+
...fieldKeys
|
|
122
|
+
.filter((fieldKey, index) => fieldKeys.indexOf(fieldKey) !== index)
|
|
123
|
+
.filter((fieldKey, index, repeated) => repeated.indexOf(fieldKey) === index)
|
|
124
|
+
.map((fieldKey) => ({
|
|
125
|
+
code: 'fieldAccessDuplicate',
|
|
126
|
+
fieldKeys: [fieldKey],
|
|
127
|
+
message: workflow_graph_1.WORKFLOW_LINT_MESSAGES.fieldAccessDuplicate(nodeId, fieldKey),
|
|
128
|
+
nodeIds: [nodeId],
|
|
129
|
+
})),
|
|
130
|
+
...(0, field_access_1.readNodeFieldAccess)(node)
|
|
131
|
+
.filter((entry) => entry.fill !== 'NONE' && entry.display === 'HIDE')
|
|
132
|
+
.map((entry) => ({
|
|
133
|
+
code: 'fieldAccessFillHidden',
|
|
134
|
+
fieldKeys: [entry.fieldKey],
|
|
135
|
+
message: workflow_graph_1.WORKFLOW_LINT_MESSAGES.fieldAccessFillHidden(nodeId, entry.fieldKey),
|
|
136
|
+
nodeIds: [nodeId],
|
|
137
|
+
})),
|
|
138
|
+
...(hasFillableField ? readUserTaskFillConflicts(node) : []).map((conflict) => ({
|
|
139
|
+
code: FILL_CONFLICT_ISSUES[conflict].code,
|
|
140
|
+
fieldKeys: [],
|
|
141
|
+
message: FILL_CONFLICT_ISSUES[conflict].message(nodeId),
|
|
142
|
+
nodeIds: [nodeId],
|
|
143
|
+
})),
|
|
144
|
+
];
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* The nodes reachable from `startNodeIds` along `edges` without entering one
|
|
148
|
+
* of `blockedNodeIds`, the start nodes included unless blocked. Walks the
|
|
149
|
+
* graph one frontier at a time and drops every node it has already seen, so a
|
|
150
|
+
* cycle ends the walk instead of feeding it.
|
|
151
|
+
*/
|
|
152
|
+
function readReachableWorkflowNodeIds(edges, startNodeIds, blockedNodeIds = new Set()) {
|
|
153
|
+
const walk = (frontier, visited) => {
|
|
154
|
+
const fresh = [...new Set(frontier)].filter((nodeId) => !visited.has(nodeId) && !blockedNodeIds.has(nodeId));
|
|
155
|
+
return fresh.length
|
|
156
|
+
? walk(edges
|
|
157
|
+
.filter((edge) => fresh.includes(edge.source))
|
|
158
|
+
.map((edge) => edge.target), new Set([...visited, ...fresh]))
|
|
159
|
+
: visited;
|
|
160
|
+
};
|
|
161
|
+
return walk(startNodeIds, new Set());
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Whether two nodes can both run in one case: one reaches the other, or a
|
|
165
|
+
* parallel split sends each down a branch of its own (reachable from one
|
|
166
|
+
* outgoing edge of the split but not from another, and the other way round).
|
|
167
|
+
* Nodes on mutually exclusive branches never both run, and neither do two
|
|
168
|
+
* nodes that both lie after the join, which every branch reaches alike. The
|
|
169
|
+
* graph may hold a cycle, which the reachability walk copes with.
|
|
170
|
+
*/
|
|
171
|
+
function createWorkflowCoRunReader(definition) {
|
|
172
|
+
const reachableCache = new Map();
|
|
173
|
+
const readReachable = (nodeId) => {
|
|
174
|
+
const cached = reachableCache.get(nodeId);
|
|
175
|
+
if (cached !== undefined) {
|
|
176
|
+
return cached;
|
|
177
|
+
}
|
|
178
|
+
const reachable = readReachableWorkflowNodeIds(definition.edges, [nodeId]);
|
|
179
|
+
reachableCache.set(nodeId, reachable);
|
|
180
|
+
return reachable;
|
|
181
|
+
};
|
|
182
|
+
const parallelBranches = definition.nodes
|
|
183
|
+
.filter((node) => node.type === 'parallelGateway')
|
|
184
|
+
.map((node) => definition.edges
|
|
185
|
+
.filter((edge) => edge.source === node.id)
|
|
186
|
+
.map((edge) => readReachable(edge.target)))
|
|
187
|
+
.filter((branches) => branches.length >= 2);
|
|
188
|
+
const isOnOwnBranch = (branches, nodeId, otherNodeId) => branches.some((branch, index) => branch.has(nodeId) &&
|
|
189
|
+
!branch.has(otherNodeId) &&
|
|
190
|
+
branches.some((other, otherIndex) => otherIndex !== index &&
|
|
191
|
+
other.has(otherNodeId) &&
|
|
192
|
+
!other.has(nodeId)));
|
|
193
|
+
return (nodeId, otherNodeId) => readReachable(nodeId).has(otherNodeId) ||
|
|
194
|
+
readReachable(otherNodeId).has(nodeId) ||
|
|
195
|
+
parallelBranches.some((branches) => isOnOwnBranch(branches, nodeId, otherNodeId));
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* The issues read from the whole definition, in publish-lint order: a system
|
|
199
|
+
* node writing an approver-filled field, then two fill nodes of one field
|
|
200
|
+
* that can both run in one case.
|
|
201
|
+
*
|
|
202
|
+
* A field an approver fills in is empty until then, and the approver's value
|
|
203
|
+
* is the one the case keeps. A system node writing it would either be
|
|
204
|
+
* overwritten or overwrite the approver, so the two are kept apart.
|
|
205
|
+
*
|
|
206
|
+
* One field, one filler per run: when two nodes that fill the same field in
|
|
207
|
+
* can both run in one case (`createWorkflowCoRunReader`), the later one
|
|
208
|
+
* overwrites the earlier and the signed value no longer tells who answered.
|
|
209
|
+
* Fill nodes on mutually exclusive branches (one per region, say) stay
|
|
210
|
+
* allowed. Reported once per field and pair, in node order.
|
|
211
|
+
*/
|
|
212
|
+
function readDefinitionFieldAccessIssues(definition) {
|
|
213
|
+
const approverFilled = (0, field_access_1.readApproverFilledFieldKeys)(definition);
|
|
214
|
+
const writeIssues = definition.nodes
|
|
215
|
+
.filter((node) => node.type === 'serviceTask')
|
|
216
|
+
.flatMap((node) => {
|
|
217
|
+
const action = node.data.action;
|
|
218
|
+
const fieldPath = isPlainRecord(action) ? action['fieldPath'] : undefined;
|
|
219
|
+
const fieldKey = isPlainRecord(action) &&
|
|
220
|
+
action['type'] === 'SET_FORM_FIELD' &&
|
|
221
|
+
typeof fieldPath === 'string'
|
|
222
|
+
? (0, field_access_1.readFormFieldPathTopLevelKey)(fieldPath)
|
|
223
|
+
: undefined;
|
|
224
|
+
return fieldKey !== undefined && approverFilled.has(fieldKey)
|
|
225
|
+
? [
|
|
226
|
+
{
|
|
227
|
+
code: 'setFormFieldApproverFilled',
|
|
228
|
+
fieldKeys: [fieldKey],
|
|
229
|
+
message: workflow_graph_1.WORKFLOW_LINT_MESSAGES.setFormFieldApproverFilled(node.id, fieldKey),
|
|
230
|
+
nodeIds: [node.id],
|
|
231
|
+
},
|
|
232
|
+
]
|
|
233
|
+
: [];
|
|
234
|
+
});
|
|
235
|
+
const userTasks = definition.nodes.filter((node) => node.type === 'userTask');
|
|
236
|
+
const canBothRun = createWorkflowCoRunReader(definition);
|
|
237
|
+
const pathIssues = [...approverFilled].flatMap((fieldKey) => {
|
|
238
|
+
const fillNodeIds = [
|
|
239
|
+
...new Set(userTasks
|
|
240
|
+
.filter((node) => (0, field_access_1.readNodeFillableFieldKeys)(node).has(fieldKey))
|
|
241
|
+
.map((node) => node.id)),
|
|
242
|
+
];
|
|
243
|
+
return fillNodeIds.flatMap((nodeId, index) => fillNodeIds
|
|
244
|
+
.slice(index + 1)
|
|
245
|
+
.filter((otherNodeId) => canBothRun(nodeId, otherNodeId))
|
|
246
|
+
.map((otherNodeId) => ({
|
|
247
|
+
code: 'approverFilledMultipleFillNodesOnPath',
|
|
248
|
+
fieldKeys: [fieldKey],
|
|
249
|
+
message: workflow_graph_1.WORKFLOW_LINT_MESSAGES.approverFilledMultipleFillNodesOnPath(fieldKey, nodeId, otherNodeId),
|
|
250
|
+
nodeIds: [nodeId, otherNodeId],
|
|
251
|
+
})));
|
|
252
|
+
});
|
|
253
|
+
return [...writeIssues, ...pathIssues];
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Why a form field cannot be one an approver fills in, as the issues the
|
|
257
|
+
* publish lint reports once it is: a form-level rule (`required` / `hidden`
|
|
258
|
+
* set to `true`, the others set at all โ `required: false` and
|
|
259
|
+
* `hidden: false`, what the form editor writes for "off", are not rules), a
|
|
260
|
+
* data source, a file upload, or a table with a data-source column. Empty
|
|
261
|
+
* when the field can be filled in.
|
|
262
|
+
*/
|
|
263
|
+
function readFormFieldFillIssues(field) {
|
|
264
|
+
const { fieldKey } = field;
|
|
265
|
+
const issue = (code, message) => ({
|
|
266
|
+
code,
|
|
267
|
+
fieldKeys: [fieldKey],
|
|
268
|
+
message,
|
|
269
|
+
nodeIds: [],
|
|
270
|
+
});
|
|
271
|
+
return [
|
|
272
|
+
...workflow_graph_1.APPROVER_FILLED_FORM_RULES.filter((rule) => rule === 'required' || rule === 'hidden'
|
|
273
|
+
? field[rule] === true
|
|
274
|
+
: field[rule] !== undefined).map((rule) => issue('approverFilledFieldFormRule', workflow_graph_1.WORKFLOW_LINT_MESSAGES.approverFilledFieldFormRule(fieldKey, rule))),
|
|
275
|
+
...((0, form_1.isFormDataSourceFieldDefinition)(field)
|
|
276
|
+
? [
|
|
277
|
+
issue('approverFilledFieldDataSource', workflow_graph_1.WORKFLOW_LINT_MESSAGES.approverFilledFieldDataSource(fieldKey)),
|
|
278
|
+
]
|
|
279
|
+
: []),
|
|
280
|
+
...(field.type === 'file_upload'
|
|
281
|
+
? [
|
|
282
|
+
issue('approverFilledFieldFileUpload', workflow_graph_1.WORKFLOW_LINT_MESSAGES.approverFilledFieldFileUpload(fieldKey)),
|
|
283
|
+
]
|
|
284
|
+
: []),
|
|
285
|
+
...((0, form_1.isTableFieldDefinition)(field) &&
|
|
286
|
+
field.columns.some(form_1.isFormDataSourceFieldDefinition)
|
|
287
|
+
? [
|
|
288
|
+
issue('approverFilledTableDataSourceColumn', workflow_graph_1.WORKFLOW_LINT_MESSAGES.approverFilledTableDataSourceColumn(fieldKey)),
|
|
289
|
+
]
|
|
290
|
+
: []),
|
|
291
|
+
];
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* True when a CEL expression reads the top-level form field `fieldKey` โ
|
|
295
|
+
* `form.x`, `formData.x`, `form["x"]`, or any of those with `form . x` spacing
|
|
296
|
+
* or a deeper step after it (`form.x.y`, `form.x[0]`). `has(form.x)` counts.
|
|
297
|
+
*
|
|
298
|
+
* The root has to be a bare `form` / `formData`: `myform.x` and `a.form.x` are
|
|
299
|
+
* somebody else's `x`. The key has to end there: `form.xy` is another field.
|
|
300
|
+
* `form` and `formData` are the two allowed root identifiers that carry the
|
|
301
|
+
* form data (`WORKFLOW_EXPRESSION_ROOT_IDENTIFIERS`). A string literal that
|
|
302
|
+
* merely spells `form.x` counts too: a false hit only makes the publish lint
|
|
303
|
+
* stricter.
|
|
304
|
+
*/
|
|
305
|
+
function referencesFormField(expression, fieldKey) {
|
|
306
|
+
const escapedKey = fieldKey.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&');
|
|
307
|
+
// Not preceded by an identifier character or a dot, so `myform` and
|
|
308
|
+
// `a.form` do not pass for the root.
|
|
309
|
+
const root = '(?<![\\p{L}\\p{N}_.])(?:formData|form)\\s*';
|
|
310
|
+
return [
|
|
311
|
+
new RegExp(`${root}\\.\\s*${escapedKey}(?![\\p{L}\\p{N}_])`, 'u'),
|
|
312
|
+
new RegExp(`${root}\\[\\s*["']${escapedKey}["']\\s*\\]`, 'u'),
|
|
313
|
+
].some((pattern) => pattern.test(expression));
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* The issues read against the form the definition is bound to, in
|
|
317
|
+
* publish-lint order: a `fieldKey` that is not a top-level field of the form,
|
|
318
|
+
* an approver-filled field the form will not let anybody fill in
|
|
319
|
+
* (`readFormFieldFillIssues`, once per field however many nodes fill it in),
|
|
320
|
+
* `fill: 'REQUIRED'` on a boolean (`false` is an answer, so required can never
|
|
321
|
+
* fail), and an applicant's rule that reads an approver-filled field โ the
|
|
322
|
+
* rule is evaluated against the submitted form, where that field is still
|
|
323
|
+
* empty, and the evaluation silently compares against nothing.
|
|
324
|
+
*/
|
|
325
|
+
function readFormFieldAccessIssues(definition, schema) {
|
|
326
|
+
var _a, _b;
|
|
327
|
+
const fieldsByKey = new Map(((_a = schema === null || schema === void 0 ? void 0 : schema.fields) !== null && _a !== void 0 ? _a : []).map((field) => [
|
|
328
|
+
field.fieldKey,
|
|
329
|
+
field,
|
|
330
|
+
]));
|
|
331
|
+
const userTasks = definition.nodes.filter((node) => node.type === 'userTask');
|
|
332
|
+
const unknownFieldIssues = userTasks.flatMap((node) => (0, field_access_1.readNodeFieldAccess)(node)
|
|
333
|
+
.filter(({ fieldKey }) => !fieldsByKey.has(fieldKey))
|
|
334
|
+
.map(({ fieldKey }) => ({
|
|
335
|
+
code: 'fieldAccessUnknownField',
|
|
336
|
+
fieldKeys: [fieldKey],
|
|
337
|
+
message: workflow_graph_1.WORKFLOW_LINT_MESSAGES.fieldAccessUnknownField(node.id, fieldKey),
|
|
338
|
+
nodeIds: [node.id],
|
|
339
|
+
})));
|
|
340
|
+
const requiredBooleanIssues = userTasks.flatMap((node) => (0, field_access_1.readNodeFieldAccess)(node)
|
|
341
|
+
.filter(({ fieldKey, fill }) => {
|
|
342
|
+
var _a;
|
|
343
|
+
return fill === 'REQUIRED' &&
|
|
344
|
+
((_a = fieldsByKey.get(fieldKey)) === null || _a === void 0 ? void 0 : _a.type) === 'boolean';
|
|
345
|
+
})
|
|
346
|
+
.map(({ fieldKey }) => ({
|
|
347
|
+
code: 'approverFilledRequiredBoolean',
|
|
348
|
+
fieldKeys: [fieldKey],
|
|
349
|
+
message: workflow_graph_1.WORKFLOW_LINT_MESSAGES.approverFilledRequiredBoolean(node.id, fieldKey),
|
|
350
|
+
nodeIds: [node.id],
|
|
351
|
+
})));
|
|
352
|
+
const approverFilled = (0, field_access_1.readApproverFilledFieldKeys)(definition);
|
|
353
|
+
const applicantRuleIssues = ((_b = schema === null || schema === void 0 ? void 0 : schema.fields) !== null && _b !== void 0 ? _b : [])
|
|
354
|
+
.filter((field) => !approverFilled.has(field.fieldKey))
|
|
355
|
+
.flatMap((field) => workflow_graph_1.APPLICANT_FIELD_CONDITION_RULES.flatMap((rule) => {
|
|
356
|
+
const expression = field[rule];
|
|
357
|
+
return typeof expression === 'string'
|
|
358
|
+
? [...approverFilled]
|
|
359
|
+
.filter((fieldKey) => referencesFormField(expression, fieldKey))
|
|
360
|
+
.map((fieldKey) => ({
|
|
361
|
+
code: 'applicantRuleReadsApproverFilled',
|
|
362
|
+
fieldKeys: [field.fieldKey, fieldKey],
|
|
363
|
+
message: workflow_graph_1.WORKFLOW_LINT_MESSAGES.applicantRuleReadsApproverFilled(field.fieldKey, rule, fieldKey),
|
|
364
|
+
nodeIds: [],
|
|
365
|
+
}))
|
|
366
|
+
: [];
|
|
367
|
+
}));
|
|
368
|
+
const fieldIssues = [...approverFilled].flatMap((fieldKey) => {
|
|
369
|
+
const field = fieldsByKey.get(fieldKey);
|
|
370
|
+
return field === undefined ? [] : readFormFieldFillIssues(field);
|
|
371
|
+
});
|
|
372
|
+
return [
|
|
373
|
+
...unknownFieldIssues,
|
|
374
|
+
...fieldIssues,
|
|
375
|
+
...requiredBooleanIssues,
|
|
376
|
+
...applicantRuleIssues,
|
|
377
|
+
];
|
|
378
|
+
}
|
|
379
|
+
//# sourceMappingURL=field-access-lint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"field-access-lint.js","sourceRoot":"","sources":["../../../../../libs/shared/src/lib/field-access-lint.ts"],"names":[],"mappings":"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"}
|