@atlassian/forge-conditions 0.3.3-next.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 +120 -0
- package/LICENSE.txt +7 -0
- package/README.md +63 -0
- package/out/check.d.ts +3 -0
- package/out/check.d.ts.map +1 -0
- package/out/check.js +147 -0
- package/out/common.d.ts +16 -0
- package/out/common.d.ts.map +1 -0
- package/out/common.js +24 -0
- package/out/condition-types/entity-property.d.ts +9 -0
- package/out/condition-types/entity-property.d.ts.map +1 -0
- package/out/condition-types/entity-property.js +98 -0
- package/out/index.d.ts +3 -0
- package/out/index.d.ts.map +1 -0
- package/out/index.js +5 -0
- package/out/text.d.ts +7 -0
- package/out/text.d.ts.map +1 -0
- package/out/text.js +8 -0
- package/out/types.d.ts +62 -0
- package/out/types.d.ts.map +1 -0
- package/out/types.js +37 -0
- package/package.json +15 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# @atlassian/forge-conditions
|
|
2
|
+
|
|
3
|
+
## 0.3.3-next.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 9da1330: Add publishConfig
|
|
8
|
+
|
|
9
|
+
## 0.3.2
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- a5e7647: Update license for Forge public packages
|
|
14
|
+
|
|
15
|
+
## 0.3.2-next.0
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- a5e7647: Update license for Forge public packages
|
|
20
|
+
|
|
21
|
+
## 0.3.1
|
|
22
|
+
|
|
23
|
+
### Patch Changes
|
|
24
|
+
|
|
25
|
+
- 652e9f2: Bump Typescript and ESlint to latest
|
|
26
|
+
|
|
27
|
+
## 0.3.1-next.0
|
|
28
|
+
|
|
29
|
+
### Patch Changes
|
|
30
|
+
|
|
31
|
+
- 652e9f23: Bump Typescript and ESlint to latest
|
|
32
|
+
|
|
33
|
+
## 0.3.0
|
|
34
|
+
|
|
35
|
+
### Minor Changes
|
|
36
|
+
|
|
37
|
+
- 3367e8d: Update display conditions processing logic to support Confluence entity property conditions
|
|
38
|
+
|
|
39
|
+
### Patch Changes
|
|
40
|
+
|
|
41
|
+
- 3f30fe8: Export types.ts as part of the library
|
|
42
|
+
|
|
43
|
+
## 0.3.0-next.1
|
|
44
|
+
|
|
45
|
+
### Patch Changes
|
|
46
|
+
|
|
47
|
+
- 3f30fe8: Export types.ts as part of the library
|
|
48
|
+
|
|
49
|
+
## 0.3.0-next.0
|
|
50
|
+
|
|
51
|
+
### Minor Changes
|
|
52
|
+
|
|
53
|
+
- 3367e8d: Update display conditions processing logic to support Confluence entity property conditions
|
|
54
|
+
|
|
55
|
+
## 0.2.0
|
|
56
|
+
|
|
57
|
+
### Minor Changes
|
|
58
|
+
|
|
59
|
+
- a55d9c8: Changed validation and runtime error messages for display conditions
|
|
60
|
+
|
|
61
|
+
## 0.2.0-next.0
|
|
62
|
+
|
|
63
|
+
### Minor Changes
|
|
64
|
+
|
|
65
|
+
- a55d9c8: Changed validation and runtime error messages for display conditions
|
|
66
|
+
|
|
67
|
+
## 0.1.0
|
|
68
|
+
|
|
69
|
+
### Minor Changes
|
|
70
|
+
|
|
71
|
+
- dd27c38: Add display condition types and validation
|
|
72
|
+
|
|
73
|
+
### Patch Changes
|
|
74
|
+
|
|
75
|
+
- b41cc4c: Fix exported content
|
|
76
|
+
- 41dcd69: Moved CSP logic to its own package and bridge script to cli-shared
|
|
77
|
+
|
|
78
|
+
## 0.1.0-next.2
|
|
79
|
+
|
|
80
|
+
### Patch Changes
|
|
81
|
+
|
|
82
|
+
- 41dcd69: Moved CSP logic to its own package and bridge script to cli-shared
|
|
83
|
+
|
|
84
|
+
## 0.1.0-next.1
|
|
85
|
+
|
|
86
|
+
### Minor Changes
|
|
87
|
+
|
|
88
|
+
- dd27c38: Add display condition types and validation
|
|
89
|
+
|
|
90
|
+
## 0.0.5-next.0
|
|
91
|
+
|
|
92
|
+
### Patch Changes
|
|
93
|
+
|
|
94
|
+
- b41cc4c: Fix exported content
|
|
95
|
+
|
|
96
|
+
## 0.0.4
|
|
97
|
+
|
|
98
|
+
### Patch Changes
|
|
99
|
+
|
|
100
|
+
- 059a822: Set build target to ES5
|
|
101
|
+
|
|
102
|
+
## 0.0.4-next.0
|
|
103
|
+
|
|
104
|
+
### Patch Changes
|
|
105
|
+
|
|
106
|
+
- 059a822: Set build target to ES5
|
|
107
|
+
|
|
108
|
+
## 0.0.3
|
|
109
|
+
|
|
110
|
+
## 0.0.2
|
|
111
|
+
|
|
112
|
+
### Patch Changes
|
|
113
|
+
|
|
114
|
+
- 1546f65: Add an initial version of Forge conditions
|
|
115
|
+
|
|
116
|
+
## 0.0.2-next.0
|
|
117
|
+
|
|
118
|
+
### Patch Changes
|
|
119
|
+
|
|
120
|
+
- 1546f65: Add an initial version of Forge conditions
|
package/LICENSE.txt
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
Copyright (c) 2025 Atlassian
|
|
2
|
+
Permission is hereby granted to use this software in accordance with the terms
|
|
3
|
+
and conditions outlined in the Atlassian Developer Terms, which can be found
|
|
4
|
+
at the following URL:
|
|
5
|
+
https://developer.atlassian.com/platform/marketplace/atlassian-developer-terms/
|
|
6
|
+
By using this software, you agree to comply with these terms and conditions.
|
|
7
|
+
If you do not agree with these terms, you are not permitted to use this software.
|
package/README.md
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Forge conditions
|
|
2
|
+
|
|
3
|
+
The package validates provided conditions against provided data.
|
|
4
|
+
It compares the static data and supports few basic logical operations such as:
|
|
5
|
+
* and
|
|
6
|
+
* or
|
|
7
|
+
* not
|
|
8
|
+
|
|
9
|
+
## How to use
|
|
10
|
+
|
|
11
|
+
Import `doesMeetConditions` and invoke it with two arguments to get a `boolean` result:
|
|
12
|
+
```javascript
|
|
13
|
+
doesMeetConditions({}, {}) // true
|
|
14
|
+
doesMeetConditions({}, { isAdmin: false }) // true, no conditions
|
|
15
|
+
doesMeetConditions({ isAdmin: true }, { isAdmin: false }) // false, condition requires an admin
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Where the first argument defines what conditions have to be met, and the second one is a static data.
|
|
19
|
+
|
|
20
|
+
In case a top-level operation isn't specified, the `and` operation is applied.
|
|
21
|
+
It may be changed by specifying another operation though.
|
|
22
|
+
|
|
23
|
+
### A full example of usage
|
|
24
|
+
|
|
25
|
+
```javascript
|
|
26
|
+
import { doesMeetConditions } from '@atlassian/forge-conditions';
|
|
27
|
+
|
|
28
|
+
const conditions = {
|
|
29
|
+
isLoggedIn: true,
|
|
30
|
+
or: {
|
|
31
|
+
isAdmin: true,
|
|
32
|
+
anotherProp: ['this', 'or', 'whatever'],
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const staticContext = {
|
|
37
|
+
isLoggedIn: true,
|
|
38
|
+
isAdmin: false,
|
|
39
|
+
anotherProp: 'this',
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// true, because isLoggedIn matches and one of the `or` conditions matched as well
|
|
43
|
+
doesMeetConditions(conditions, staticContext);
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
All supported operations can be nested if needed:
|
|
47
|
+
|
|
48
|
+
```javascript
|
|
49
|
+
const conditions = {
|
|
50
|
+
or: {
|
|
51
|
+
isLoggedIn: true,
|
|
52
|
+
not: {
|
|
53
|
+
anotherProp: ['O_GOD_NOT_THIS_OH_NO_HELP_NOOOOOO'],
|
|
54
|
+
and: {
|
|
55
|
+
isAdmin: true,
|
|
56
|
+
not: {
|
|
57
|
+
issueType: 'Bug',
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
```
|
package/out/check.d.ts
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { Conditions, StaticContext, ClientDataProvider } from './types';
|
|
2
|
+
export declare const doesMeetConditions: (conditions: Conditions, staticContext: StaticContext, clientDataProvider?: ClientDataProvider) => Promise<boolean> | boolean;
|
|
3
|
+
//# sourceMappingURL=check.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../src/check.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkD,UAAU,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAoNxH,eAAO,MAAM,kBAAkB,eACjB,UAAU,iBACP,aAAa,uBACP,kBAAkB,KACtC,QAAQ,OAAO,CAAC,GAAG,OAwBrB,CAAC"}
|
package/out/check.js
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.doesMeetConditions = void 0;
|
|
4
|
+
const common_1 = require("./common");
|
|
5
|
+
const text_1 = require("./text");
|
|
6
|
+
const entity_property_1 = require("./condition-types/entity-property");
|
|
7
|
+
const unhandledOperation = (operation) => {
|
|
8
|
+
throw new Error(text_1.errors.unhandledOperation(operation));
|
|
9
|
+
};
|
|
10
|
+
const checkOperation = (operation, conditionsInput, staticContextInput, clientData) => {
|
|
11
|
+
const conditions = (0, common_1.isObjectOrArray)(conditionsInput) ? conditionsInput : {};
|
|
12
|
+
const staticContext = (0, common_1.isObject)(staticContextInput) ? staticContextInput : {};
|
|
13
|
+
let staticKeys = [];
|
|
14
|
+
let operationEntries = [];
|
|
15
|
+
let propertyConditions;
|
|
16
|
+
if (Array.isArray(conditions)) {
|
|
17
|
+
propertyConditions = conditions;
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
staticKeys = Object.keys(conditions).filter(common_1.isStaticKey);
|
|
21
|
+
propertyConditions = Object.entries(conditions)
|
|
22
|
+
.filter(([key]) => (0, common_1.isEntityPropertyCondition)(key))
|
|
23
|
+
.map(([key, condition]) => ({ [key]: condition }));
|
|
24
|
+
operationEntries = Object.entries(conditions).filter(([key, _]) => (0, common_1.isOperation)(key));
|
|
25
|
+
}
|
|
26
|
+
const staticKeysLength = staticKeys.length;
|
|
27
|
+
const operationsLength = operationEntries.length;
|
|
28
|
+
const propertyConditionsLength = propertyConditions.length;
|
|
29
|
+
const staticEqualityComparator = (key) => (Array.isArray(conditions[key]) ? conditions[key] : [conditions[key]]).includes(staticContext[key]);
|
|
30
|
+
if (staticKeysLength === 0 && operationsLength === 0 && propertyConditionsLength === 0) {
|
|
31
|
+
return common_1.Instruction.Skip;
|
|
32
|
+
}
|
|
33
|
+
if (staticKeysLength !== 0 || propertyConditionsLength !== 0) {
|
|
34
|
+
let clientDataConditionResult;
|
|
35
|
+
switch (operation) {
|
|
36
|
+
case common_1.AND_OPERATION:
|
|
37
|
+
if (staticKeysLength && !staticKeys.every(staticEqualityComparator)) {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
clientDataConditionResult = entity_property_1.entityPropertyHandlers[common_1.AND_OPERATION](propertyConditions, clientData);
|
|
41
|
+
if (clientDataConditionResult !== common_1.Instruction.Continue) {
|
|
42
|
+
return clientDataConditionResult;
|
|
43
|
+
}
|
|
44
|
+
break;
|
|
45
|
+
case common_1.OR_OPERATION:
|
|
46
|
+
if (staticKeysLength && staticKeys.some(staticEqualityComparator)) {
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
clientDataConditionResult = entity_property_1.entityPropertyHandlers[common_1.OR_OPERATION](propertyConditions, clientData);
|
|
50
|
+
if (clientDataConditionResult !== common_1.Instruction.Continue) {
|
|
51
|
+
return clientDataConditionResult;
|
|
52
|
+
}
|
|
53
|
+
break;
|
|
54
|
+
case common_1.NOT_OPERATION:
|
|
55
|
+
if (staticKeysLength && staticKeys.some((key) => !staticEqualityComparator(key))) {
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
clientDataConditionResult = entity_property_1.entityPropertyHandlers[common_1.NOT_OPERATION](propertyConditions, clientData);
|
|
59
|
+
if (clientDataConditionResult !== common_1.Instruction.Continue) {
|
|
60
|
+
return clientDataConditionResult;
|
|
61
|
+
}
|
|
62
|
+
break;
|
|
63
|
+
default:
|
|
64
|
+
return unhandledOperation(operation);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
for (let index = 0; index < operationEntries.length; index += 1) {
|
|
68
|
+
const [nextOperation, nextConditions] = operationEntries[index];
|
|
69
|
+
const nextOperationResult = checkOperation(nextOperation, nextConditions, staticContext, clientData);
|
|
70
|
+
if (nextOperationResult === common_1.Instruction.NeedData) {
|
|
71
|
+
return nextOperationResult;
|
|
72
|
+
}
|
|
73
|
+
switch (operation) {
|
|
74
|
+
case common_1.AND_OPERATION:
|
|
75
|
+
if (nextOperationResult === false) {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
if (nextOperationResult === common_1.Instruction.Skip && operationsLength === 1) {
|
|
79
|
+
return staticKeysLength + propertyConditionsLength === 0 ? common_1.Instruction.Skip : true;
|
|
80
|
+
}
|
|
81
|
+
break;
|
|
82
|
+
case common_1.OR_OPERATION:
|
|
83
|
+
if (nextOperationResult === true) {
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
if (nextOperationResult === common_1.Instruction.Skip && operationsLength === 1) {
|
|
87
|
+
return staticKeysLength + propertyConditionsLength === 0 ? common_1.Instruction.Skip : false;
|
|
88
|
+
}
|
|
89
|
+
break;
|
|
90
|
+
case common_1.NOT_OPERATION:
|
|
91
|
+
if (nextOperationResult === false) {
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
if (nextOperationResult === common_1.Instruction.Skip && operationsLength === 1) {
|
|
95
|
+
return staticKeysLength + propertyConditionsLength === 0 ? common_1.Instruction.Skip : false;
|
|
96
|
+
}
|
|
97
|
+
break;
|
|
98
|
+
default:
|
|
99
|
+
return unhandledOperation(operation);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
switch (operation) {
|
|
103
|
+
case common_1.AND_OPERATION:
|
|
104
|
+
return true;
|
|
105
|
+
case common_1.OR_OPERATION:
|
|
106
|
+
return false;
|
|
107
|
+
case common_1.NOT_OPERATION:
|
|
108
|
+
return false;
|
|
109
|
+
default:
|
|
110
|
+
return unhandledOperation(operation);
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
const validateNesting = (conditionsInput, nesting = 0) => {
|
|
114
|
+
if (nesting >= 10) {
|
|
115
|
+
throw new Error(text_1.errors.nestingOvercomplicated());
|
|
116
|
+
}
|
|
117
|
+
const conditions = (0, common_1.isObjectOrArray)(conditionsInput) ? conditionsInput : {};
|
|
118
|
+
if (Array.isArray(conditions)) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
Object.entries(conditions)
|
|
122
|
+
.filter(([key, _]) => (0, common_1.isOperation)(key))
|
|
123
|
+
.forEach(([_, condition]) => validateNesting(condition, nesting + 1));
|
|
124
|
+
};
|
|
125
|
+
const doesMeetConditions = (conditions, staticContext, clientDataProvider) => {
|
|
126
|
+
try {
|
|
127
|
+
validateNesting(conditions);
|
|
128
|
+
let result = checkOperation(common_1.AND_OPERATION, conditions, staticContext);
|
|
129
|
+
if (result !== common_1.Instruction.NeedData) {
|
|
130
|
+
return result === common_1.Instruction.Skip ? true : result;
|
|
131
|
+
}
|
|
132
|
+
if (!clientDataProvider) {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
return clientDataProvider
|
|
136
|
+
.fetchPropertyValues((0, entity_property_1.collectEntityPropertiesToFetch)(conditions))
|
|
137
|
+
.then((clientData) => {
|
|
138
|
+
result = checkOperation(common_1.AND_OPERATION, conditions, staticContext, clientData);
|
|
139
|
+
return result === common_1.Instruction.Skip ? true : result;
|
|
140
|
+
})
|
|
141
|
+
.catch(() => false);
|
|
142
|
+
}
|
|
143
|
+
catch (_a) {
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
exports.doesMeetConditions = doesMeetConditions;
|
package/out/common.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { AndOperation, NotOperation, OrOperation, PropertyConditionType, SupportedOperations } from './types';
|
|
2
|
+
export declare const AND_OPERATION: AndOperation;
|
|
3
|
+
export declare const OR_OPERATION: OrOperation;
|
|
4
|
+
export declare const NOT_OPERATION: NotOperation;
|
|
5
|
+
export declare const SUPPORTED_OPERATIONS: SupportedOperations;
|
|
6
|
+
export declare enum Instruction {
|
|
7
|
+
Skip = "skip",
|
|
8
|
+
NeedData = "need-data",
|
|
9
|
+
Continue = "continue"
|
|
10
|
+
}
|
|
11
|
+
export declare const isObject: (x: any) => boolean;
|
|
12
|
+
export declare const isObjectOrArray: (x: any) => boolean;
|
|
13
|
+
export declare const isOperation: (key: string) => boolean;
|
|
14
|
+
export declare const isEntityPropertyCondition: (key: string) => key is PropertyConditionType;
|
|
15
|
+
export declare const isStaticKey: (key: string) => boolean;
|
|
16
|
+
//# sourceMappingURL=common.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../src/common.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,YAAY,EAEZ,WAAW,EACX,qBAAqB,EACrB,mBAAmB,EACpB,MAAM,SAAS,CAAC;AAEjB,eAAO,MAAM,aAAa,EAAE,YAAoB,CAAC;AACjD,eAAO,MAAM,YAAY,EAAE,WAAkB,CAAC;AAC9C,eAAO,MAAM,aAAa,EAAE,YAAoB,CAAC;AACjD,eAAO,MAAM,oBAAoB,EAAE,mBAAkE,CAAC;AAEtG,oBAAY,WAAW;IACrB,IAAI,SAAS;IACb,QAAQ,cAAc;IACtB,QAAQ,aAAa;CACtB;AAED,eAAO,MAAM,QAAQ,MAAO,GAAG,KAAG,OAAkE,CAAC;AACrG,eAAO,MAAM,eAAe,MAAO,GAAG,KAAG,OAA0C,CAAC;AAEpF,eAAO,MAAM,WAAW,QAAS,MAAM,KAAG,OAA0D,CAAC;AACrG,eAAO,MAAM,yBAAyB,QAAS,MAAM,iCACwB,CAAC;AAC9E,eAAO,MAAM,WAAW,QAAS,MAAM,KAAG,OAA4E,CAAC"}
|
package/out/common.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isStaticKey = exports.isEntityPropertyCondition = exports.isOperation = exports.isObjectOrArray = exports.isObject = exports.Instruction = exports.SUPPORTED_OPERATIONS = exports.NOT_OPERATION = exports.OR_OPERATION = exports.AND_OPERATION = void 0;
|
|
4
|
+
const types_1 = require("./types");
|
|
5
|
+
exports.AND_OPERATION = 'and';
|
|
6
|
+
exports.OR_OPERATION = 'or';
|
|
7
|
+
exports.NOT_OPERATION = 'not';
|
|
8
|
+
exports.SUPPORTED_OPERATIONS = [exports.AND_OPERATION, exports.OR_OPERATION, exports.NOT_OPERATION];
|
|
9
|
+
var Instruction;
|
|
10
|
+
(function (Instruction) {
|
|
11
|
+
Instruction["Skip"] = "skip";
|
|
12
|
+
Instruction["NeedData"] = "need-data";
|
|
13
|
+
Instruction["Continue"] = "continue";
|
|
14
|
+
})(Instruction = exports.Instruction || (exports.Instruction = {}));
|
|
15
|
+
const isObject = (x) => Object.prototype.toString.call(x) === '[object Object]';
|
|
16
|
+
exports.isObject = isObject;
|
|
17
|
+
const isObjectOrArray = (x) => (0, exports.isObject)(x) || Array.isArray(x);
|
|
18
|
+
exports.isObjectOrArray = isObjectOrArray;
|
|
19
|
+
const isOperation = (key) => exports.SUPPORTED_OPERATIONS.includes(key);
|
|
20
|
+
exports.isOperation = isOperation;
|
|
21
|
+
const isEntityPropertyCondition = (key) => Object.values(types_1.PropertyConditionType).includes(key);
|
|
22
|
+
exports.isEntityPropertyCondition = isEntityPropertyCondition;
|
|
23
|
+
const isStaticKey = (key) => !(0, exports.isOperation)(key) && !(0, exports.isEntityPropertyCondition)(key);
|
|
24
|
+
exports.isStaticKey = isStaticKey;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ClientData, Conditions, EntityPropertyCondition, PropertyValueRequest } from '../types';
|
|
2
|
+
import { Instruction } from '../common';
|
|
3
|
+
export declare const entityPropertyHandlers: {
|
|
4
|
+
and: (propertyConditions: EntityPropertyCondition[], clientData?: ClientData) => boolean | Instruction;
|
|
5
|
+
or: (propertyConditions: EntityPropertyCondition[], clientData?: ClientData) => boolean | Instruction;
|
|
6
|
+
not: (propertyConditions: EntityPropertyCondition[], clientData?: ClientData) => boolean | Instruction;
|
|
7
|
+
};
|
|
8
|
+
export declare const collectEntityPropertiesToFetch: (conditionsInput: Conditions) => PropertyValueRequest[];
|
|
9
|
+
//# sourceMappingURL=entity-property.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entity-property.d.ts","sourceRoot":"","sources":["../../src/condition-types/entity-property.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,UAAU,EAEV,uBAAuB,EAEvB,oBAAoB,EAErB,MAAM,UAAU,CAAC;AAElB,OAAO,EAIL,WAAW,EAIZ,MAAM,WAAW,CAAC;AAiHnB,eAAO,MAAM,sBAAsB;8BAxDb,uBAAuB,EAAE,eAChC,UAAU,KACtB,OAAO,GAAG,WAAW;6BAgBF,uBAAuB,EAAE,eAChC,UAAU,KACtB,OAAO,GAAG,WAAW;8BAgBF,uBAAuB,EAAE,eAChC,UAAU,KACtB,OAAO,GAAG,WAAW;CAsBvB,CAAC;AAgBF,eAAO,MAAM,8BAA8B,oBAAqB,UAAU,KAAG,oBAAoB,EAiChG,CAAC"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.collectEntityPropertiesToFetch = exports.entityPropertyHandlers = void 0;
|
|
4
|
+
const types_1 = require("../types");
|
|
5
|
+
const text_1 = require("../text");
|
|
6
|
+
const common_1 = require("../common");
|
|
7
|
+
const asArray = (value) => (Array.isArray(value) ? value : [value]);
|
|
8
|
+
const entityId = (entityProperty) => [entityProperty.entity, entityProperty.propertyKey, entityProperty.objectName].filter(Boolean).join('-');
|
|
9
|
+
const doesEntityPropertyMatch = (condition, propertyValuesResponse) => {
|
|
10
|
+
const conditionType = Object.keys(condition)[0];
|
|
11
|
+
const conditionFields = condition[conditionType];
|
|
12
|
+
const id = entityId(conditionFields);
|
|
13
|
+
const propertyValue = propertyValuesResponse[id];
|
|
14
|
+
const expectedValue = conditionFields.value;
|
|
15
|
+
let propValueArray;
|
|
16
|
+
switch (conditionType) {
|
|
17
|
+
case types_1.PropertyConditionType.EntityPropertyExists:
|
|
18
|
+
return propertyValue != null;
|
|
19
|
+
case types_1.PropertyConditionType.EntityPropertyEqualTo:
|
|
20
|
+
return propertyValue === expectedValue;
|
|
21
|
+
case types_1.PropertyConditionType.EntityPropertyContainsAny:
|
|
22
|
+
propValueArray = asArray(propertyValue);
|
|
23
|
+
return asArray(expectedValue).some((expected) => propValueArray.includes(expected));
|
|
24
|
+
case types_1.PropertyConditionType.EntityPropertyContainsAll:
|
|
25
|
+
propValueArray = asArray(propertyValue);
|
|
26
|
+
return asArray(expectedValue).every((expected) => propValueArray.includes(expected));
|
|
27
|
+
default:
|
|
28
|
+
throw new Error(text_1.errors.unsupportedConditionType(conditionType));
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
const clientConditionsPreCheck = (clientDataConditionsLength, clientData) => {
|
|
32
|
+
if (!clientDataConditionsLength) {
|
|
33
|
+
return common_1.Instruction.Continue;
|
|
34
|
+
}
|
|
35
|
+
if (!clientData) {
|
|
36
|
+
return common_1.Instruction.NeedData;
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
const entityPropertyAndHandler = (propertyConditions, clientData) => {
|
|
40
|
+
const preCheck = clientConditionsPreCheck(propertyConditions.length, clientData);
|
|
41
|
+
if (preCheck) {
|
|
42
|
+
return preCheck;
|
|
43
|
+
}
|
|
44
|
+
if (!propertyConditions.every((propCondition) => doesEntityPropertyMatch(propCondition, clientData.propertyValues))) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
return common_1.Instruction.Continue;
|
|
48
|
+
};
|
|
49
|
+
const entityPropertyOrHandler = (propertyConditions, clientData) => {
|
|
50
|
+
const preCheck = clientConditionsPreCheck(propertyConditions.length, clientData);
|
|
51
|
+
if (preCheck) {
|
|
52
|
+
return preCheck;
|
|
53
|
+
}
|
|
54
|
+
if (propertyConditions.some((propCondition) => doesEntityPropertyMatch(propCondition, clientData.propertyValues))) {
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
return common_1.Instruction.Continue;
|
|
58
|
+
};
|
|
59
|
+
const entityPropertyNotHandler = (propertyConditions, clientData) => {
|
|
60
|
+
const preCheck = clientConditionsPreCheck(propertyConditions.length, clientData);
|
|
61
|
+
if (preCheck) {
|
|
62
|
+
return preCheck;
|
|
63
|
+
}
|
|
64
|
+
if (propertyConditions.some((propCondition) => !doesEntityPropertyMatch(propCondition, clientData.propertyValues))) {
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
return common_1.Instruction.Continue;
|
|
68
|
+
};
|
|
69
|
+
exports.entityPropertyHandlers = {
|
|
70
|
+
[common_1.AND_OPERATION]: entityPropertyAndHandler,
|
|
71
|
+
[common_1.OR_OPERATION]: entityPropertyOrHandler,
|
|
72
|
+
[common_1.NOT_OPERATION]: entityPropertyNotHandler
|
|
73
|
+
};
|
|
74
|
+
const buildPropertyValueRequest = (entityProperty) => {
|
|
75
|
+
return Object.assign({ id: entityId(entityProperty), entity: entityProperty.entity, propertyKey: entityProperty.propertyKey }, (entityProperty.objectName && { objectName: entityProperty.objectName }));
|
|
76
|
+
};
|
|
77
|
+
const collectEntityPropertiesToFetch = (conditionsInput) => {
|
|
78
|
+
const conditions = (0, common_1.isObjectOrArray)(conditionsInput) ? conditionsInput : {};
|
|
79
|
+
const propertyRequests = [];
|
|
80
|
+
if (Array.isArray(conditions)) {
|
|
81
|
+
for (const propertyCondition of conditions) {
|
|
82
|
+
const key = Object.keys(propertyCondition).find(common_1.isEntityPropertyCondition);
|
|
83
|
+
if (key) {
|
|
84
|
+
const entityProperty = propertyCondition[key];
|
|
85
|
+
propertyRequests.push(buildPropertyValueRequest(entityProperty));
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return propertyRequests;
|
|
89
|
+
}
|
|
90
|
+
Object.entries(conditions)
|
|
91
|
+
.filter(([key, _]) => (0, common_1.isEntityPropertyCondition)(key))
|
|
92
|
+
.forEach(([_, condition]) => propertyRequests.push(buildPropertyValueRequest(condition)));
|
|
93
|
+
Object.entries(conditions)
|
|
94
|
+
.filter(([key, _]) => (0, common_1.isOperation)(key))
|
|
95
|
+
.forEach(([_, condition]) => propertyRequests.push(...(0, exports.collectEntityPropertiesToFetch)(condition)));
|
|
96
|
+
return propertyRequests;
|
|
97
|
+
};
|
|
98
|
+
exports.collectEntityPropertiesToFetch = collectEntityPropertiesToFetch;
|
package/out/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC"}
|
package/out/index.js
ADDED
package/out/text.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { PropertyConditionType } from './types';
|
|
2
|
+
export declare const errors: {
|
|
3
|
+
nestingOvercomplicated: () => string;
|
|
4
|
+
unhandledOperation: (operation: never) => string;
|
|
5
|
+
unsupportedConditionType: (conditionType: PropertyConditionType) => string;
|
|
6
|
+
};
|
|
7
|
+
//# sourceMappingURL=text.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../src/text.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC;AAEhD,eAAO,MAAM,MAAM;kCACW,MAAM;oCACF,KAAK,KAAG,MAAM;8CACJ,qBAAqB,KAAG,MAAM;CAEzE,CAAC"}
|
package/out/text.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.errors = void 0;
|
|
4
|
+
exports.errors = {
|
|
5
|
+
nestingOvercomplicated: () => 'Nesting of display conditions exceeds 10 levels',
|
|
6
|
+
unhandledOperation: (operation) => `Unhandled operation: ${operation}`,
|
|
7
|
+
unsupportedConditionType: (conditionType) => `Unsupported condition type: ${conditionType}`
|
|
8
|
+
};
|
package/out/types.d.ts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
export declare type AndOperation = 'and';
|
|
2
|
+
export declare type OrOperation = 'or';
|
|
3
|
+
export declare type NotOperation = 'not';
|
|
4
|
+
export declare type Operation = AndOperation | OrOperation | NotOperation;
|
|
5
|
+
export declare type SupportedOperations = [AndOperation, OrOperation, NotOperation];
|
|
6
|
+
export declare type GenericCondition<T> = AndCondition<T> | OrCondition<T> | NotCondition<T> | T;
|
|
7
|
+
export declare type AndCondition<T> = T & {
|
|
8
|
+
[key in AndOperation]: GenericCondition<T>;
|
|
9
|
+
};
|
|
10
|
+
export declare type OrCondition<T> = T & {
|
|
11
|
+
[key in OrOperation]: GenericCondition<T>;
|
|
12
|
+
};
|
|
13
|
+
export declare type NotCondition<T> = T & {
|
|
14
|
+
[key in NotOperation]: GenericCondition<T>;
|
|
15
|
+
};
|
|
16
|
+
export declare enum PropertyConditionType {
|
|
17
|
+
EntityPropertyExists = "entityPropertyExists",
|
|
18
|
+
EntityPropertyEqualTo = "entityPropertyEqualTo",
|
|
19
|
+
EntityPropertyContainsAny = "entityPropertyContainsAny",
|
|
20
|
+
EntityPropertyContainsAll = "entityPropertyContainsAll"
|
|
21
|
+
}
|
|
22
|
+
export declare enum EntityType {
|
|
23
|
+
Space = "space",
|
|
24
|
+
Content = "content"
|
|
25
|
+
}
|
|
26
|
+
export interface EntityProperty {
|
|
27
|
+
entity: EntityType;
|
|
28
|
+
propertyKey: string;
|
|
29
|
+
objectName?: string;
|
|
30
|
+
value: string | string[];
|
|
31
|
+
}
|
|
32
|
+
export declare type EntityPropertyCondition = {
|
|
33
|
+
[key in PropertyConditionType]?: EntityProperty;
|
|
34
|
+
};
|
|
35
|
+
export interface PropertyValueRequest {
|
|
36
|
+
id: string;
|
|
37
|
+
entity: EntityType;
|
|
38
|
+
propertyKey: string;
|
|
39
|
+
objectName?: string;
|
|
40
|
+
}
|
|
41
|
+
export interface PropertyValuesResponse {
|
|
42
|
+
[id: string]: string | string[];
|
|
43
|
+
}
|
|
44
|
+
export interface ClientData {
|
|
45
|
+
propertyValues: PropertyValuesResponse;
|
|
46
|
+
}
|
|
47
|
+
export declare class ClientDataProvider {
|
|
48
|
+
private readonly globalFetchPromise;
|
|
49
|
+
private globalFetchResolve?;
|
|
50
|
+
private globalFetchReject?;
|
|
51
|
+
propertyValueRequests: PropertyValueRequest[];
|
|
52
|
+
constructor();
|
|
53
|
+
fetchPropertyValues(propValueRequests: PropertyValueRequest[]): Promise<ClientData>;
|
|
54
|
+
resolve(clientData: ClientData): void;
|
|
55
|
+
reject(reason: any): void;
|
|
56
|
+
}
|
|
57
|
+
export declare type Condition = StaticContext | (StaticContext & EntityPropertyCondition) | EntityPropertyCondition[];
|
|
58
|
+
export declare type Conditions = GenericCondition<Condition>;
|
|
59
|
+
export declare type StaticContext = {
|
|
60
|
+
[key in string]: any;
|
|
61
|
+
};
|
|
62
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAEA,oBAAY,YAAY,GAAG,KAAK,CAAC;AACjC,oBAAY,WAAW,GAAG,IAAI,CAAC;AAC/B,oBAAY,YAAY,GAAG,KAAK,CAAC;AAEjC,oBAAY,SAAS,GAAG,YAAY,GAAG,WAAW,GAAG,YAAY,CAAC;AAClE,oBAAY,mBAAmB,GAAG,CAAC,YAAY,EAAE,WAAW,EAAE,YAAY,CAAC,CAAC;AAE5E,oBAAY,gBAAgB,CAAC,CAAC,IAAI,YAAY,CAAC,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AACzF,oBAAY,YAAY,CAAC,CAAC,IAAI,CAAC,GAAG;KAC/B,GAAG,IAAI,YAAY,GAAG,gBAAgB,CAAC,CAAC,CAAC;CAC3C,CAAC;AAEF,oBAAY,WAAW,CAAC,CAAC,IAAI,CAAC,GAAG;KAC9B,GAAG,IAAI,WAAW,GAAG,gBAAgB,CAAC,CAAC,CAAC;CAC1C,CAAC;AAEF,oBAAY,YAAY,CAAC,CAAC,IAAI,CAAC,GAAG;KAC/B,GAAG,IAAI,YAAY,GAAG,gBAAgB,CAAC,CAAC,CAAC;CAC3C,CAAC;AAEF,oBAAY,qBAAqB;IAC/B,oBAAoB,yBAAyB;IAC7C,qBAAqB,0BAA0B;IAC/C,yBAAyB,8BAA8B;IACvD,yBAAyB,8BAA8B;CACxD;AAED,oBAAY,UAAU;IACpB,KAAK,UAAU;IACf,OAAO,YAAY;CACpB;AAKD,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,UAAU,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;CAC1B;AAKD,oBAAY,uBAAuB,GAAG;KACnC,GAAG,IAAI,qBAAqB,CAAC,CAAC,EAAE,cAAc;CAChD,CAAC;AAKF,MAAM,WAAW,oBAAoB;IAInC,EAAE,EAAE,MAAM,CAAC;IAIX,MAAM,EAAE,UAAU,CAAC;IAInB,WAAW,EAAE,MAAM,CAAC;IAKpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAWD,MAAM,WAAW,sBAAsB;IACrC,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,EAAE,CAAC;CACjC;AAKD,MAAM,WAAW,UAAU;IACzB,cAAc,EAAE,sBAAsB,CAAC;CACxC;AAaD,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAsB;IACzD,OAAO,CAAC,kBAAkB,CAAC,CAA8B;IACzD,OAAO,CAAC,iBAAiB,CAAC,CAAwB;IAKlD,qBAAqB,EAAE,oBAAoB,EAAE,CAAC;;IAe9C,mBAAmB,CAAC,iBAAiB,EAAE,oBAAoB,EAAE,GAAG,OAAO,CAAC,UAAU,CAAC;IAanF,OAAO,CAAC,UAAU,EAAE,UAAU,GAAG,IAAI;IAYrC,MAAM,CAAC,MAAM,EAAE,GAAG,GAAG,IAAI;CAG1B;AAQD,oBAAY,SAAS,GAAG,aAAa,GAAG,CAAC,aAAa,GAAG,uBAAuB,CAAC,GAAG,uBAAuB,EAAE,CAAC;AAK9G,oBAAY,UAAU,GAAG,gBAAgB,CAAC,SAAS,CAAC,CAAC;AAQrD,oBAAY,aAAa,GAAG;KACzB,GAAG,IAAI,MAAM,GAAG,GAAG;CACrB,CAAC"}
|
package/out/types.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ClientDataProvider = exports.EntityType = exports.PropertyConditionType = void 0;
|
|
4
|
+
var PropertyConditionType;
|
|
5
|
+
(function (PropertyConditionType) {
|
|
6
|
+
PropertyConditionType["EntityPropertyExists"] = "entityPropertyExists";
|
|
7
|
+
PropertyConditionType["EntityPropertyEqualTo"] = "entityPropertyEqualTo";
|
|
8
|
+
PropertyConditionType["EntityPropertyContainsAny"] = "entityPropertyContainsAny";
|
|
9
|
+
PropertyConditionType["EntityPropertyContainsAll"] = "entityPropertyContainsAll";
|
|
10
|
+
})(PropertyConditionType = exports.PropertyConditionType || (exports.PropertyConditionType = {}));
|
|
11
|
+
var EntityType;
|
|
12
|
+
(function (EntityType) {
|
|
13
|
+
EntityType["Space"] = "space";
|
|
14
|
+
EntityType["Content"] = "content";
|
|
15
|
+
})(EntityType = exports.EntityType || (exports.EntityType = {}));
|
|
16
|
+
class ClientDataProvider {
|
|
17
|
+
constructor() {
|
|
18
|
+
this.globalFetchPromise = new Promise((resolve, reject) => {
|
|
19
|
+
this.globalFetchResolve = resolve;
|
|
20
|
+
this.globalFetchReject = reject;
|
|
21
|
+
});
|
|
22
|
+
this.propertyValueRequests = [];
|
|
23
|
+
}
|
|
24
|
+
fetchPropertyValues(propValueRequests) {
|
|
25
|
+
this.propertyValueRequests.push(...propValueRequests);
|
|
26
|
+
return this.globalFetchPromise;
|
|
27
|
+
}
|
|
28
|
+
resolve(clientData) {
|
|
29
|
+
var _a;
|
|
30
|
+
(_a = this.globalFetchResolve) === null || _a === void 0 ? void 0 : _a.call(this, clientData);
|
|
31
|
+
}
|
|
32
|
+
reject(reason) {
|
|
33
|
+
var _a;
|
|
34
|
+
(_a = this.globalFetchReject) === null || _a === void 0 ? void 0 : _a.call(this, reason);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
exports.ClientDataProvider = ClientDataProvider;
|
package/package.json
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@atlassian/forge-conditions",
|
|
3
|
+
"version": "0.3.3-next.0",
|
|
4
|
+
"description": "Support conditions in the forge apps",
|
|
5
|
+
"main": "out/index.js",
|
|
6
|
+
"license": "SEE LICENSE IN LICENSE.txt",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "yarn run clean && yarn run compile",
|
|
9
|
+
"compile": "tsc -b -v",
|
|
10
|
+
"clean": "rm -rf ./out && rm -f tsconfig.tsbuildinfo"
|
|
11
|
+
},
|
|
12
|
+
"publishConfig": {
|
|
13
|
+
"registry": "https://packages.atlassian.com/api/npm/npm-public/"
|
|
14
|
+
}
|
|
15
|
+
}
|