@servicenow/sdk-build-plugins 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/AttachmentPlugin.d.ts +253 -0
- package/dist/AttachmentPlugin.js +216 -0
- package/dist/AttachmentPlugin.js.map +1 -0
- package/dist/BusinessRulePlugin.d.ts +56 -0
- package/dist/BusinessRulePlugin.js +171 -0
- package/dist/BusinessRulePlugin.js.map +1 -0
- package/dist/CrossScopePrivilegePlugin.d.ts +22 -0
- package/dist/CrossScopePrivilegePlugin.js +42 -0
- package/dist/CrossScopePrivilegePlugin.js.map +1 -0
- package/dist/DefaultPlugin.d.ts +71 -0
- package/dist/DefaultPlugin.js +238 -0
- package/dist/DefaultPlugin.js.map +1 -0
- package/dist/IdPlugin.d.ts +17 -0
- package/dist/IdPlugin.js +45 -0
- package/dist/IdPlugin.js.map +1 -0
- package/dist/ListPlugin.d.ts +91 -0
- package/dist/ListPlugin.js +398 -0
- package/dist/ListPlugin.js.map +1 -0
- package/dist/PropertyPlugin.d.ts +122 -0
- package/dist/PropertyPlugin.js +165 -0
- package/dist/PropertyPlugin.js.map +1 -0
- package/dist/ScriptTemplatePlugin.d.ts +31 -0
- package/dist/ScriptTemplatePlugin.js +208 -0
- package/dist/ScriptTemplatePlugin.js.map +1 -0
- package/dist/UserPreferencePlugin.d.ts +16 -0
- package/dist/UserPreferencePlugin.js +30 -0
- package/dist/UserPreferencePlugin.js.map +1 -0
- package/dist/aclAndRole/AclPlugin.d.ts +117 -0
- package/dist/aclAndRole/AclPlugin.js +285 -0
- package/dist/aclAndRole/AclPlugin.js.map +1 -0
- package/dist/aclAndRole/RolePlugin.d.ts +58 -0
- package/dist/aclAndRole/RolePlugin.js +152 -0
- package/dist/aclAndRole/RolePlugin.js.map +1 -0
- package/dist/aclAndRole/Util.d.ts +3 -0
- package/dist/aclAndRole/Util.js +106 -0
- package/dist/aclAndRole/Util.js.map +1 -0
- package/dist/app/ApplicationMenuPlugin.d.ts +32 -0
- package/dist/app/ApplicationMenuPlugin.js +106 -0
- package/dist/app/ApplicationMenuPlugin.js.map +1 -0
- package/dist/atf/ATFComposer.d.ts +492 -0
- package/dist/atf/ATFComposer.js +2717 -0
- package/dist/atf/ATFComposer.js.map +1 -0
- package/dist/atf/TestPlugin.d.ts +31 -0
- package/dist/atf/TestPlugin.js +95 -0
- package/dist/atf/TestPlugin.js.map +1 -0
- package/dist/atf/index.d.ts +1 -0
- package/dist/atf/index.js +9 -0
- package/dist/atf/index.js.map +1 -0
- package/dist/db/ColumnPlugins.d.ts +278 -0
- package/dist/db/ColumnPlugins.js +112 -0
- package/dist/db/ColumnPlugins.js.map +1 -0
- package/dist/db/RecordPlugin.d.ts +208 -0
- package/dist/db/RecordPlugin.js +287 -0
- package/dist/db/RecordPlugin.js.map +1 -0
- package/dist/db/TablePlugin.d.ts +742 -0
- package/dist/db/TablePlugin.js +1249 -0
- package/dist/db/TablePlugin.js.map +1 -0
- package/dist/db/index.d.ts +3 -0
- package/dist/db/index.js +27 -0
- package/dist/db/index.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +51 -0
- package/dist/index.js.map +1 -0
- package/dist/scriptedRESTAPI/RESTDeserializationUtils.d.ts +12 -0
- package/dist/scriptedRESTAPI/RESTDeserializationUtils.js +371 -0
- package/dist/scriptedRESTAPI/RESTDeserializationUtils.js.map +1 -0
- package/dist/scriptedRESTAPI/RESTSerializationUtils.d.ts +15 -0
- package/dist/scriptedRESTAPI/RESTSerializationUtils.js +177 -0
- package/dist/scriptedRESTAPI/RESTSerializationUtils.js.map +1 -0
- package/dist/scriptedRESTAPI/RestApiPlugin.d.ts +144 -0
- package/dist/scriptedRESTAPI/RestApiPlugin.js +318 -0
- package/dist/scriptedRESTAPI/RestApiPlugin.js.map +1 -0
- package/dist/scriptedRESTAPI/RestSchemaUtils.d.ts +190 -0
- package/dist/scriptedRESTAPI/RestSchemaUtils.js +53 -0
- package/dist/scriptedRESTAPI/RestSchemaUtils.js.map +1 -0
- package/dist/scriptedRESTAPI/RestUtils.d.ts +75 -0
- package/dist/scriptedRESTAPI/RestUtils.js +469 -0
- package/dist/scriptedRESTAPI/RestUtils.js.map +1 -0
- package/dist/scripts/ClientScriptPlugin.d.ts +43 -0
- package/dist/scripts/ClientScriptPlugin.js +190 -0
- package/dist/scripts/ClientScriptPlugin.js.map +1 -0
- package/dist/scripts/scriptUtils.d.ts +15 -0
- package/dist/scripts/scriptUtils.js +83 -0
- package/dist/scripts/scriptUtils.js.map +1 -0
- package/dist/uxf/ExperiencePlugin.d.ts +22 -0
- package/dist/uxf/ExperiencePlugin.js +55 -0
- package/dist/uxf/ExperiencePlugin.js.map +1 -0
- package/dist/uxf/RoutesPlugin.d.ts +22 -0
- package/dist/uxf/RoutesPlugin.js +176 -0
- package/dist/uxf/RoutesPlugin.js.map +1 -0
- package/dist/uxf/UxfFormulaParser/cleanUxValue.d.ts +4 -0
- package/dist/uxf/UxfFormulaParser/cleanUxValue.js +65 -0
- package/dist/uxf/UxfFormulaParser/cleanUxValue.js.map +1 -0
- package/dist/uxf/UxfFormulaParser/grammerParser/api.d.ts +189 -0
- package/dist/uxf/UxfFormulaParser/grammerParser/api.js +158 -0
- package/dist/uxf/UxfFormulaParser/grammerParser/api.js.map +1 -0
- package/dist/uxf/UxfFormulaParser/grammerParser/clientTransformMap.d.ts +13 -0
- package/dist/uxf/UxfFormulaParser/grammerParser/clientTransformMap.js +604 -0
- package/dist/uxf/UxfFormulaParser/grammerParser/clientTransformMap.js.map +1 -0
- package/dist/uxf/UxfFormulaParser/grammerParser/grammarParser.d.ts +12 -0
- package/dist/uxf/UxfFormulaParser/grammerParser/grammarParser.js +551 -0
- package/dist/uxf/UxfFormulaParser/grammerParser/grammarParser.js.map +1 -0
- package/dist/uxf/UxfFormulaParser/grammerParser/spanHelpers.d.ts +31 -0
- package/dist/uxf/UxfFormulaParser/grammerParser/spanHelpers.js +64 -0
- package/dist/uxf/UxfFormulaParser/grammerParser/spanHelpers.js.map +1 -0
- package/dist/uxf/UxfFormulaParser/index.d.ts +3 -0
- package/dist/uxf/UxfFormulaParser/index.js +11 -0
- package/dist/uxf/UxfFormulaParser/index.js.map +1 -0
- package/dist/uxf/UxfFormulaParser/parser.d.ts +8 -0
- package/dist/uxf/UxfFormulaParser/parser.js +87 -0
- package/dist/uxf/UxfFormulaParser/parser.js.map +1 -0
- package/dist/uxf/UxfFormulaParser/utils/getErrorMsg.d.ts +8 -0
- package/dist/uxf/UxfFormulaParser/utils/getErrorMsg.js +17 -0
- package/dist/uxf/UxfFormulaParser/utils/getErrorMsg.js.map +1 -0
- package/dist/uxf/constants.d.ts +2 -0
- package/dist/uxf/constants.js +8 -0
- package/dist/uxf/constants.js.map +1 -0
- package/dist/uxf/index.d.ts +2 -0
- package/dist/uxf/index.js +11 -0
- package/dist/uxf/index.js.map +1 -0
- package/dist/uxf/tectonicIdGenerator.d.ts +12 -0
- package/dist/uxf/tectonicIdGenerator.js +102 -0
- package/dist/uxf/tectonicIdGenerator.js.map +1 -0
- package/license +9 -0
- package/package.json +42 -0
- package/src/AttachmentPlugin.ts +262 -0
- package/src/BusinessRulePlugin.ts +251 -0
- package/src/CrossScopePrivilegePlugin.ts +54 -0
- package/src/DefaultPlugin.ts +272 -0
- package/src/IdPlugin.ts +47 -0
- package/src/ListPlugin.ts +497 -0
- package/src/PropertyPlugin.ts +218 -0
- package/src/ScriptTemplatePlugin.ts +223 -0
- package/src/UserPreferencePlugin.ts +36 -0
- package/src/aclAndRole/AclPlugin.ts +410 -0
- package/src/aclAndRole/RolePlugin.ts +225 -0
- package/src/aclAndRole/Util.ts +104 -0
- package/src/app/ApplicationMenuPlugin.ts +158 -0
- package/src/atf/ATFComposer.ts +3356 -0
- package/src/atf/TestPlugin.ts +119 -0
- package/src/atf/index.ts +1 -0
- package/src/db/ColumnPlugins.ts +117 -0
- package/src/db/RecordPlugin.ts +391 -0
- package/src/db/TablePlugin.ts +1581 -0
- package/src/db/index.ts +3 -0
- package/src/index.ts +16 -0
- package/src/scriptedRESTAPI/RESTDeserializationUtils.ts +410 -0
- package/src/scriptedRESTAPI/RESTSerializationUtils.ts +227 -0
- package/src/scriptedRESTAPI/RestApiPlugin.ts +438 -0
- package/src/scriptedRESTAPI/RestSchemaUtils.ts +72 -0
- package/src/scriptedRESTAPI/RestUtils.ts +507 -0
- package/src/scripts/ClientScriptPlugin.ts +251 -0
- package/src/scripts/scriptUtils.ts +81 -0
- package/src/uxf/ExperiencePlugin.ts +64 -0
- package/src/uxf/RoutesPlugin.ts +215 -0
- package/src/uxf/UxfFormulaParser/cleanUxValue.ts +73 -0
- package/src/uxf/UxfFormulaParser/grammerParser/api.js +166 -0
- package/src/uxf/UxfFormulaParser/grammerParser/clientTransformMap.js +606 -0
- package/src/uxf/UxfFormulaParser/grammerParser/grammarParser.js +551 -0
- package/src/uxf/UxfFormulaParser/grammerParser/spanHelpers.js +65 -0
- package/src/uxf/UxfFormulaParser/index.ts +4 -0
- package/src/uxf/UxfFormulaParser/parser.ts +64 -0
- package/src/uxf/UxfFormulaParser/utils/getErrorMsg.ts +13 -0
- package/src/uxf/constants.ts +4 -0
- package/src/uxf/index.ts +2 -0
- package/src/uxf/tectonicIdGenerator.ts +81 -0
|
@@ -0,0 +1,507 @@
|
|
|
1
|
+
/* eslint-disable no-case-declarations */
|
|
2
|
+
import * as ts from 'ts-morph'
|
|
3
|
+
import {
|
|
4
|
+
Context,
|
|
5
|
+
Document,
|
|
6
|
+
Result,
|
|
7
|
+
DocumentPointer,
|
|
8
|
+
removeNode,
|
|
9
|
+
getCallExpressionName,
|
|
10
|
+
Arranged,
|
|
11
|
+
UnlinkedDocument,
|
|
12
|
+
getNodeId,
|
|
13
|
+
} from '@servicenow/sdk-build-core'
|
|
14
|
+
import { isEqual } from 'lodash'
|
|
15
|
+
import { RestApi } from '@servicenow/sdk-core/runtime/rest'
|
|
16
|
+
import { RecordPlugin } from '../db/RecordPlugin'
|
|
17
|
+
|
|
18
|
+
export const restTables = [
|
|
19
|
+
'sys_ws_definition',
|
|
20
|
+
'sys_ws_operation',
|
|
21
|
+
'sys_ws_version',
|
|
22
|
+
'sys_ws_header',
|
|
23
|
+
'sys_ws_query_parameter',
|
|
24
|
+
'sys_ws_header_map',
|
|
25
|
+
'sys_ws_query_parameter_map',
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
let restDocumentMap: any = undefined
|
|
29
|
+
|
|
30
|
+
/** checks if a given query_parameter or header doc is consumed by the given rest or not in current transformation*/
|
|
31
|
+
const isConsumedByRest = (restId: string, restDocMap: any, document: Document) => {
|
|
32
|
+
if (restDocMap[restId] && restDocMap[restId].route_attrs_map) {
|
|
33
|
+
const found = Object.values(restDocMap[restId].route_attrs_map).find(
|
|
34
|
+
(doc: any) =>
|
|
35
|
+
doc.data['data'].web_service_query_parameter === document.guid ||
|
|
36
|
+
doc.data['data'].web_service_header === document.guid
|
|
37
|
+
)
|
|
38
|
+
return found ? true : false
|
|
39
|
+
}
|
|
40
|
+
return false
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function getRouteAttrMapResult(document: Document, restDocMap: any): Result<DocumentPointer | undefined> {
|
|
44
|
+
if (document.action === 'DELETE') {
|
|
45
|
+
return { handled: false }
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* if the given attribute map record references query parameter or routes record
|
|
49
|
+
* not part of the current app we make it a record call.
|
|
50
|
+
*/
|
|
51
|
+
const isUnHandled = restDocMap['unHandled_records'].find((doc) => doc.id === document.guid)
|
|
52
|
+
if (isUnHandled) {
|
|
53
|
+
return { handled: false }
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const routeId = document.data!['data']['web_service_operation']
|
|
57
|
+
const paramField =
|
|
58
|
+
document.data!['table'] === 'sys_ws_header_map' ? 'web_service_header' : 'web_service_query_parameter'
|
|
59
|
+
potentialRecordCallRouteParams.delete(document.data!['data'][paramField])
|
|
60
|
+
/** if the attribute map record is consumed by any rest then associated appropriate parent */
|
|
61
|
+
return { handled: true, result: { kind: 'record', guid: routeId } }
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** utility function to get the args node of a call expression node*/
|
|
65
|
+
export const getArgs = (document: Document) => {
|
|
66
|
+
const node = document.node!.asKindOrThrow(ts.SyntaxKind.CallExpression)
|
|
67
|
+
return node.getArguments()[0]!.asKindOrThrow(ts.SyntaxKind.ObjectLiteralExpression)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* utility function that iterates over all the headers or parameters of all routes
|
|
72
|
+
* inside a rest api and calls the provided callback function.
|
|
73
|
+
*/
|
|
74
|
+
export function iterateAllRouteAttrNode(
|
|
75
|
+
document: Document,
|
|
76
|
+
eleAttrName: string,
|
|
77
|
+
callback: (
|
|
78
|
+
expression: ts.ArrayLiteralExpression,
|
|
79
|
+
element: ts.Expression,
|
|
80
|
+
compositeKey: { attr: string; route: string; rest: string }
|
|
81
|
+
) => void
|
|
82
|
+
) {
|
|
83
|
+
const argsNode = getArgs(document)
|
|
84
|
+
const restId = getNodeId(argsNode)!
|
|
85
|
+
argsNode
|
|
86
|
+
.getProperty('routes')
|
|
87
|
+
?.asKind(ts.ts.SyntaxKind.PropertyAssignment)
|
|
88
|
+
?.getInitializerIfKindOrThrow(ts.ts.SyntaxKind.ArrayLiteralExpression)
|
|
89
|
+
?.getElements()
|
|
90
|
+
.forEach((element) => {
|
|
91
|
+
const routeId = getNodeId(element.asKindOrThrow(ts.SyntaxKind.ObjectLiteralExpression))!
|
|
92
|
+
const arrayExpression = element
|
|
93
|
+
.asKind(ts.ts.SyntaxKind.ObjectLiteralExpression)
|
|
94
|
+
?.getProperty(eleAttrName)
|
|
95
|
+
?.asKind(ts.ts.SyntaxKind.PropertyAssignment)
|
|
96
|
+
?.getInitializerIfKindOrThrow(ts.ts.SyntaxKind.ArrayLiteralExpression)
|
|
97
|
+
|
|
98
|
+
arrayExpression?.getElements().forEach((element) => {
|
|
99
|
+
const attrId = getNodeId(element.asKindOrThrow(ts.SyntaxKind.ObjectLiteralExpression))!
|
|
100
|
+
callback(arrayExpression, element, {
|
|
101
|
+
attr: attrId,
|
|
102
|
+
route: routeId,
|
|
103
|
+
rest: restId,
|
|
104
|
+
})
|
|
105
|
+
})
|
|
106
|
+
})
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* keeps track of all those params records associated with a rest node,
|
|
111
|
+
* so if some m2m records removes all its associations then we would create record call.
|
|
112
|
+
*/
|
|
113
|
+
export const potentialRecordCallRouteParams = new Set<string>()
|
|
114
|
+
/**
|
|
115
|
+
* There are some of the completely unassociated param records generated when an
|
|
116
|
+
* m2m record swtiches from one rest to another rest entity. we track them to generate records calls
|
|
117
|
+
* if required.
|
|
118
|
+
*/
|
|
119
|
+
export const completelyUnassociatedParamIds = new Set<string>()
|
|
120
|
+
/**
|
|
121
|
+
* Ids of records which are going to be a record call so need not handle them in rest generator.
|
|
122
|
+
*/
|
|
123
|
+
export const unHandledIds: string[] = []
|
|
124
|
+
|
|
125
|
+
/** Based on the result it adds the document id to unHandledIds which is later on used by generator
|
|
126
|
+
* to avoid generating nodes for them since it's expected to be handled by record plugin.
|
|
127
|
+
*/
|
|
128
|
+
export function handleAndReturnResult(result: Result<DocumentPointer | undefined>, document: Document) {
|
|
129
|
+
if (!result.handled) {
|
|
130
|
+
unHandledIds.push(document.guid)
|
|
131
|
+
}
|
|
132
|
+
return result
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Performs the following operations:
|
|
137
|
+
* 1. If the documents associated rest node is the same as the referenced rest in data, let the rest node handle it.
|
|
138
|
+
* 2. If it refernces a different rest node, then clean up the current rest node and its keys. If the referenced rest node
|
|
139
|
+
* has a mapping record to consume this parameter or header let it handle, else make it a record call.
|
|
140
|
+
*/
|
|
141
|
+
export function getRouteAttrWithRestNodeResult(
|
|
142
|
+
document: Document,
|
|
143
|
+
context: Context,
|
|
144
|
+
restDocMap: any
|
|
145
|
+
): Result<DocumentPointer | undefined> {
|
|
146
|
+
const restId = document.data!['data']['web_service_definition']
|
|
147
|
+
const nodeId = getNodeId(getArgs(document))!
|
|
148
|
+
const nodeRestId = context.keys.explicit[nodeId]!.id
|
|
149
|
+
if (document.action === 'DELETE') {
|
|
150
|
+
return { handled: true, result: { kind: 'record', guid: nodeRestId } }
|
|
151
|
+
}
|
|
152
|
+
if (restId === nodeRestId) {
|
|
153
|
+
return { handled: true, result: { kind: 'record', guid: restId } }
|
|
154
|
+
}
|
|
155
|
+
const attrName = document.data!['table'] === 'sys_ws_header' ? 'headers' : 'parameters'
|
|
156
|
+
let deleteAttrKey: string | undefined = undefined
|
|
157
|
+
iterateAllRouteAttrNode(document, attrName, (arrayExp, element, compKey) => {
|
|
158
|
+
const attrSysId = context.keys.explicit[compKey.attr]!.id
|
|
159
|
+
if (attrSysId === document.guid) {
|
|
160
|
+
deleteAttrKey = compKey.attr
|
|
161
|
+
const idx = context.keys.composite.findIndex((k) => isEqual(k.key, compKey))
|
|
162
|
+
if (idx !== -1) {
|
|
163
|
+
context.keys.composite.splice(idx, 1)
|
|
164
|
+
}
|
|
165
|
+
arrayExp.removeElement(element)
|
|
166
|
+
}
|
|
167
|
+
})
|
|
168
|
+
if (deleteAttrKey) {
|
|
169
|
+
delete context.keys.explicit[deleteAttrKey]
|
|
170
|
+
}
|
|
171
|
+
potentialRecordCallRouteParams.delete(document.guid)
|
|
172
|
+
deleteDocNode(document, context)
|
|
173
|
+
document['changedData'] = { data: document.data!['data'] }
|
|
174
|
+
if (!isConsumed(document, restDocMap)) {
|
|
175
|
+
return { handled: false }
|
|
176
|
+
}
|
|
177
|
+
return { handled: true, result: { kind: 'record', guid: restId } }
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function isConsumed(document: Document, restDocMap: any) {
|
|
181
|
+
const restId = document.data!['data']['web_service_definition']
|
|
182
|
+
const isUnHandled = restDocMap['unHandled_records'].find((doc) => doc.id === document.guid)
|
|
183
|
+
if (isUnHandled) {
|
|
184
|
+
return false
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return isConsumedByRest(restId, restDocMap, document)
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Deletes node reference from document and updates in context docs as well to keep it updated.
|
|
192
|
+
*/
|
|
193
|
+
const deleteDocNode = (document: Document, context: Context) => {
|
|
194
|
+
const foundDoc = context.getAllDocuments().find((doc) => doc.guid === document.guid)
|
|
195
|
+
delete foundDoc?.node
|
|
196
|
+
delete document.node
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* checks to see if the document is consumed by any rest api. If consumed then
|
|
201
|
+
* remove that record call expression and its associated keys and let rest handle
|
|
202
|
+
* it, else update the record call.
|
|
203
|
+
*/
|
|
204
|
+
export function getRouteAttrWithRecordNodeResult(
|
|
205
|
+
document: Document,
|
|
206
|
+
context: Context,
|
|
207
|
+
restDocMap: any
|
|
208
|
+
): Result<DocumentPointer | undefined> {
|
|
209
|
+
if (document.action === 'DELETE') {
|
|
210
|
+
return { handled: false }
|
|
211
|
+
}
|
|
212
|
+
if (!isConsumed(document, restDocMap)) {
|
|
213
|
+
return { handled: false }
|
|
214
|
+
}
|
|
215
|
+
const recordId = getNodeId(getArgs(document))!
|
|
216
|
+
removeNode(document.node!)
|
|
217
|
+
deleteDocNode(document, context)
|
|
218
|
+
delete context.keys.explicit[recordId]
|
|
219
|
+
document['changedData'] = { data: document.data!['data'] }
|
|
220
|
+
return { handled: true, result: { kind: 'record', guid: document.data!['data']['web_service_definition'] } }
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/** Gets the rest id for the given route id.*/
|
|
224
|
+
const getRestIdForRoute = (routeId: string, restDocMap: any) => {
|
|
225
|
+
let restId: string | undefined = undefined
|
|
226
|
+
Object.keys(restDocMap)
|
|
227
|
+
.filter((key) => key !== 'unHanlded_records' && key !== 'delete_records')
|
|
228
|
+
.forEach((key) => {
|
|
229
|
+
if (restDocMap[key].routes) {
|
|
230
|
+
const foundRoute = Object.values(restDocMap[key].routes).find((doc: any) => doc.id === routeId)
|
|
231
|
+
if (foundRoute) {
|
|
232
|
+
restId = key
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
})
|
|
236
|
+
return restId
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/** cleans the mapping node from given array and keys file*/
|
|
240
|
+
const cleanMapDocInNode = (
|
|
241
|
+
arrayExp: ts.ArrayLiteralExpression,
|
|
242
|
+
element: ts.Expression,
|
|
243
|
+
compKey: { attr: string; route: string; rest: string },
|
|
244
|
+
context: Context,
|
|
245
|
+
document: Document
|
|
246
|
+
) => {
|
|
247
|
+
const idx = context.keys.composite.findIndex((k) => isEqual(k.key, compKey))
|
|
248
|
+
if (idx !== -1) {
|
|
249
|
+
const compObj = context.keys.composite[idx]
|
|
250
|
+
if (compObj?.id === document.guid) {
|
|
251
|
+
arrayExp.removeElement(element)
|
|
252
|
+
context.keys.composite.splice(idx, 1)
|
|
253
|
+
return context.keys.explicit[compKey.attr]?.id
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
return undefined
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Performs the following operations:
|
|
261
|
+
* 1. If the mapping record references a differnt route or query param not part of the app
|
|
262
|
+
* then clean its presence from current rest node and create a record call for it.
|
|
263
|
+
* 2. If if references a different route and query param in same app, the clean current rest
|
|
264
|
+
* and update the new rest node.
|
|
265
|
+
* 3. If references same rest then update it.
|
|
266
|
+
*
|
|
267
|
+
* In addition to that, it also tracks the params unassociated to create record call if needed.
|
|
268
|
+
*/
|
|
269
|
+
export function getRouteAttrMapWithRestNodeResult(
|
|
270
|
+
document: Document,
|
|
271
|
+
context: Context,
|
|
272
|
+
restDocMap: any
|
|
273
|
+
): Result<DocumentPointer | undefined> {
|
|
274
|
+
const restNodeId = getNodeId(getArgs(document))
|
|
275
|
+
const restNodeSysId = context.keys.explicit[restNodeId!]!.id
|
|
276
|
+
const routeId = document.data!['data']['web_service_operation']
|
|
277
|
+
if (document.action === 'DELETE') {
|
|
278
|
+
return { handled: true, result: { kind: 'record', guid: routeId } }
|
|
279
|
+
}
|
|
280
|
+
const isUnHandled = restDocMap['unHandled_records'].find((doc) => doc.id === document.guid)
|
|
281
|
+
const attrName = document.data!['table'] === 'sys_ws_header_map' ? 'headers' : 'parameters'
|
|
282
|
+
if (isUnHandled) {
|
|
283
|
+
let unAssociatedId: string | undefined = undefined
|
|
284
|
+
document['changedData'] = { data: document.data!['data'] }
|
|
285
|
+
iterateAllRouteAttrNode(document, attrName, (arrayExp, element, compKey) => {
|
|
286
|
+
unAssociatedId = unAssociatedId ?? cleanMapDocInNode(arrayExp, element, compKey, context, document)
|
|
287
|
+
})
|
|
288
|
+
if (unAssociatedId) {
|
|
289
|
+
if (!isParamAssociated(document, attrName, context, unAssociatedId)) {
|
|
290
|
+
completelyUnassociatedParamIds.add(unAssociatedId)
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
deleteDocNode(document, context)
|
|
294
|
+
return { handled: false }
|
|
295
|
+
}
|
|
296
|
+
const paramField =
|
|
297
|
+
document.data!['table'] === 'sys_ws_header_map' ? 'web_service_header' : 'web_service_query_parameter'
|
|
298
|
+
potentialRecordCallRouteParams.delete(document.data!['data'][paramField])
|
|
299
|
+
const restId = getRestIdForRoute(routeId, restDocMap)!
|
|
300
|
+
if (restId !== restNodeSysId) {
|
|
301
|
+
let unAssociatedId: string | undefined = undefined
|
|
302
|
+
document['changedData'] = { data: document.data!['data'] }
|
|
303
|
+
iterateAllRouteAttrNode(document, attrName, (arrayExp, element, compKey) => {
|
|
304
|
+
unAssociatedId = unAssociatedId ?? cleanMapDocInNode(arrayExp, element, compKey, context, document)
|
|
305
|
+
})
|
|
306
|
+
if (unAssociatedId) {
|
|
307
|
+
if (!isParamAssociated(document, attrName, context, unAssociatedId)) {
|
|
308
|
+
completelyUnassociatedParamIds.add(unAssociatedId)
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
deleteDocNode(document, context)
|
|
312
|
+
}
|
|
313
|
+
return { handled: true, result: { kind: 'record', guid: routeId } }
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Performs following operation
|
|
318
|
+
* 1. If given mapping record references some routes or param not in app update the record call.
|
|
319
|
+
* 2. If references some existing route and param, then remove the current record call and its keys.
|
|
320
|
+
* Update the new rest node.
|
|
321
|
+
*/
|
|
322
|
+
export function getRouteAttrMapWithRecordNodeResult(
|
|
323
|
+
document: Document,
|
|
324
|
+
context: Context,
|
|
325
|
+
restDocMap: any
|
|
326
|
+
): Result<DocumentPointer | undefined> {
|
|
327
|
+
if (document.action === 'DELETE') {
|
|
328
|
+
return { handled: false }
|
|
329
|
+
}
|
|
330
|
+
const routeId = document.data!['data']['web_service_operation']
|
|
331
|
+
const isUnHandled = restDocMap['unHandled_records'].find((doc) => doc.id === document.guid)
|
|
332
|
+
if (isUnHandled) {
|
|
333
|
+
return { handled: false }
|
|
334
|
+
}
|
|
335
|
+
document['changedData'] = { data: document.data!['data'] }
|
|
336
|
+
const recordId = getNodeId(getArgs(document))!
|
|
337
|
+
const paramField =
|
|
338
|
+
document.data!['table'] === 'sys_ws_header_map' ? 'web_service_header' : 'web_service_query_parameter'
|
|
339
|
+
potentialRecordCallRouteParams.delete(document.data!['data'][paramField])
|
|
340
|
+
removeNode(document.node!)
|
|
341
|
+
deleteDocNode(document, context)
|
|
342
|
+
delete context.keys.explicit[recordId]
|
|
343
|
+
return { handled: true, result: { kind: 'record', guid: routeId } }
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* If the incoming parameter or header record is consumed by rest associated it to the rest node, else make it a record call.
|
|
348
|
+
*/
|
|
349
|
+
export function getRouteAttrResult(document: Document, restDocMap: any): Result<DocumentPointer | undefined> {
|
|
350
|
+
if (document.action === 'DELETE') {
|
|
351
|
+
return { handled: false }
|
|
352
|
+
}
|
|
353
|
+
const restId = document.data!['data']['web_service_definition']
|
|
354
|
+
if (isConsumedByRest(restId, restDocMap, document)) {
|
|
355
|
+
return { handled: true, result: { kind: 'record', guid: restId } }
|
|
356
|
+
}
|
|
357
|
+
return { handled: false }
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
const findRecInDocs = (docs: any[], id: string, table: string) => {
|
|
361
|
+
return docs?.find((doc) => doc.data!['table'] === table && doc.id == id)
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
export function getRestDocumentMap(context: Context) {
|
|
365
|
+
if (restDocumentMap) {
|
|
366
|
+
return restDocumentMap
|
|
367
|
+
}
|
|
368
|
+
/**gets all rest related docs */
|
|
369
|
+
const allRestDocs = context.getAllDocuments().filter((doc) => restTables.includes(doc.data!['table']))
|
|
370
|
+
allRestDocs.sort((doc1, doc2) => {
|
|
371
|
+
const doc1Table = doc1.data!['table']
|
|
372
|
+
const doc2Table = doc2.data!['table']
|
|
373
|
+
return restTables.indexOf(doc1Table) - restTables.indexOf(doc2Table)
|
|
374
|
+
})
|
|
375
|
+
const unHandledDocs: any[] = []
|
|
376
|
+
/** filters and gets all delete records and insert_or_update records */
|
|
377
|
+
const delRestDocs = allRestDocs.filter((doc) => doc.action === 'DELETE')
|
|
378
|
+
const existingDocs = allRestDocs.filter((doc) => doc.action !== 'DELETE')
|
|
379
|
+
existingDocs.map((doc) => {
|
|
380
|
+
const table = doc.data!['table']
|
|
381
|
+
if (
|
|
382
|
+
(table === 'sys_ws_query_parameter' || table === 'sys_ws_header') &&
|
|
383
|
+
doc.node &&
|
|
384
|
+
getCallExpressionName(doc.node as ts.CallExpression) === RestApi.name
|
|
385
|
+
) {
|
|
386
|
+
potentialRecordCallRouteParams.add(doc.guid)
|
|
387
|
+
}
|
|
388
|
+
})
|
|
389
|
+
/**
|
|
390
|
+
* Generates the rest document map with insert or udpate records
|
|
391
|
+
* and includes only mapping records that are being transformed (this is needed to determine if an
|
|
392
|
+
* parameter or header record will be consumed by rest in current transformation)
|
|
393
|
+
*/
|
|
394
|
+
restDocumentMap = existingDocs.reduce((docMap, doc) => {
|
|
395
|
+
switch (doc.data!['table']) {
|
|
396
|
+
case 'sys_ws_definition':
|
|
397
|
+
docMap[doc.guid] = {
|
|
398
|
+
restDef: doc,
|
|
399
|
+
}
|
|
400
|
+
break
|
|
401
|
+
case 'sys_ws_operation':
|
|
402
|
+
const op_restId = doc.data!['data']['web_service_definition']
|
|
403
|
+
if (docMap[op_restId]) {
|
|
404
|
+
;(docMap[op_restId].routes ??= {})[doc.guid] = doc
|
|
405
|
+
}
|
|
406
|
+
break
|
|
407
|
+
case 'sys_ws_version':
|
|
408
|
+
const v_restId = doc.data!['data']['web_service_definition']
|
|
409
|
+
if (docMap[v_restId]) {
|
|
410
|
+
;(docMap[v_restId].versions ??= {})[doc.guid] = doc
|
|
411
|
+
}
|
|
412
|
+
break
|
|
413
|
+
case 'sys_ws_query_parameter':
|
|
414
|
+
case 'sys_ws_header':
|
|
415
|
+
const qp_restId = doc.data!['data']['web_service_definition']
|
|
416
|
+
if (docMap[qp_restId]) {
|
|
417
|
+
;(docMap[qp_restId].route_attrs ??= {})[doc.guid] = doc
|
|
418
|
+
} else {
|
|
419
|
+
//throw error if the transforming doc references a deleted record
|
|
420
|
+
if (doc.changedData) {
|
|
421
|
+
const found = findRecInDocs(delRestDocs, qp_restId, 'sys_ws_definition')
|
|
422
|
+
if (found) {
|
|
423
|
+
throw Error(
|
|
424
|
+
`Found invalid rest route param record: ${doc.guid} referencing deleted rest record: ${qp_restId}`
|
|
425
|
+
)
|
|
426
|
+
}
|
|
427
|
+
unHandledDocs.push(doc)
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
break
|
|
431
|
+
case 'sys_ws_query_parameter_map':
|
|
432
|
+
case 'sys_ws_header_map':
|
|
433
|
+
if (!doc.changedData) {
|
|
434
|
+
break
|
|
435
|
+
}
|
|
436
|
+
const attrTable =
|
|
437
|
+
doc.data!['table'] === 'sys_ws_header_map' ? 'sys_ws_header' : 'sys_ws_query_parameter'
|
|
438
|
+
const attr =
|
|
439
|
+
doc.data!['table'] === 'sys_ws_header_map' ? 'web_service_header' : 'web_service_query_parameter'
|
|
440
|
+
const qpm_routeId = doc.data!['data']['web_service_operation']
|
|
441
|
+
const qpm_paramId = doc.data!['data'][attr]
|
|
442
|
+
const delOperationFound = findRecInDocs(delRestDocs, qpm_routeId, 'sys_ws_operation')
|
|
443
|
+
const delParamFound = findRecInDocs(delRestDocs, qpm_paramId, attrTable)
|
|
444
|
+
if (delOperationFound || delParamFound) {
|
|
445
|
+
throw Error(
|
|
446
|
+
`Found invalid rest map record: ${doc.guid} referencing deleted record: ${
|
|
447
|
+
delOperationFound ? delOperationFound : delParamFound
|
|
448
|
+
}`
|
|
449
|
+
)
|
|
450
|
+
}
|
|
451
|
+
const routeRec = findRecInDocs(existingDocs, qpm_routeId, 'sys_ws_operation')
|
|
452
|
+
const paramRec = findRecInDocs(existingDocs, qpm_paramId, attrTable)
|
|
453
|
+
/**if both route and parameter are part of same rest then it will be consumed by rest */
|
|
454
|
+
if (routeRec && paramRec) {
|
|
455
|
+
const routeRestId = routeRec.data!['data']['web_service_definition']
|
|
456
|
+
const paramRestId = paramRec.data!['data']['web_service_definition']
|
|
457
|
+
if (routeRestId !== paramRestId) {
|
|
458
|
+
throw Error(
|
|
459
|
+
`Found invalid rest mapping record: ${doc.guid} which has param: ${qpm_paramId} and route: ${qpm_routeId} pointing to different rest definition`
|
|
460
|
+
)
|
|
461
|
+
}
|
|
462
|
+
;(docMap[routeRestId].route_attrs_map ??= {})[doc.guid] = doc
|
|
463
|
+
} else if (paramRec) {
|
|
464
|
+
const paramRestId = paramRec.data!['data']['web_service_definition']
|
|
465
|
+
const foundRestRec = findRecInDocs(existingDocs, paramRestId, 'sys_ws_definition')
|
|
466
|
+
/**In mapping records resources and paramter should point to same rest*/
|
|
467
|
+
if (foundRestRec) {
|
|
468
|
+
throw Error(
|
|
469
|
+
`Found invalid rest mapping record: ${doc.guid} where the resource references different rest entity than the rest attr.`
|
|
470
|
+
)
|
|
471
|
+
}
|
|
472
|
+
unHandledDocs.push(doc)
|
|
473
|
+
} else {
|
|
474
|
+
unHandledDocs.push(doc)
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
return docMap
|
|
478
|
+
}, {})
|
|
479
|
+
restDocumentMap['delete_records'] = delRestDocs ?? []
|
|
480
|
+
restDocumentMap['unHandled_records'] = unHandledDocs ?? []
|
|
481
|
+
return restDocumentMap
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
export function isParamAssociated(document: Document, eleAttrName: string, context: Context, paramSysId: string) {
|
|
485
|
+
let isAssociated = false
|
|
486
|
+
iterateAllRouteAttrNode(document, eleAttrName, (_expression, _element, compKey) => {
|
|
487
|
+
if (context.keys.explicit[compKey.attr]?.id === paramSysId) {
|
|
488
|
+
isAssociated = true
|
|
489
|
+
}
|
|
490
|
+
})
|
|
491
|
+
return isAssociated
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
/**
|
|
495
|
+
* Helper function that creates a record call for the document passed.
|
|
496
|
+
*/
|
|
497
|
+
export function createRecordCall(paramSysId: string, context: Context) {
|
|
498
|
+
const paramKey = context.keys.findExplicitKeyById(paramSysId)
|
|
499
|
+
if (paramKey) {
|
|
500
|
+
delete context.keys.explicit[paramKey]
|
|
501
|
+
}
|
|
502
|
+
const document = context.getDocument(paramSysId)!
|
|
503
|
+
document['changedData'] = { data: document.data!['data'] }
|
|
504
|
+
delete document?.node
|
|
505
|
+
const linkedDoc = RecordPlugin.generators.record(document as UnlinkedDocument<'record'> & Arranged, context)
|
|
506
|
+
RecordPlugin.transformers.record.CallExpression(linkedDoc)
|
|
507
|
+
}
|