@servicenow/sdk-build-core 2.1.3 → 2.2.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/BuildOptions.d.ts +0 -8
- package/dist/BuildOptions.js +2 -4
- package/dist/BuildOptions.js.map +1 -1
- package/dist/GUID.d.ts +1 -1
- package/dist/GUID.js +5 -33
- package/dist/GUID.js.map +1 -1
- package/dist/Keys.d.ts +3 -3
- package/dist/Keys.js +5 -6
- package/dist/Keys.js.map +1 -1
- package/dist/TypeScript.d.ts +1 -1
- package/dist/TypeScript.js +4 -27
- package/dist/TypeScript.js.map +1 -1
- package/dist/XML.js +1 -4
- package/dist/XML.js.map +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -14
- package/dist/index.js.map +1 -1
- package/dist/plugins/Context.d.ts +3 -8
- package/dist/plugins/Diagnostic.d.ts +2 -3
- package/dist/plugins/Diagnostic.js +1 -25
- package/dist/plugins/Diagnostic.js.map +1 -1
- package/dist/plugins/behaviors/Diagnostics.d.ts +1 -2
- package/dist/plugins/behaviors/extractors/Data.d.ts +1 -1
- package/dist/plugins/behaviors/extractors/Extractors.d.ts +1 -1
- package/dist/plugins/util/CallExpression.d.ts +1 -1
- package/dist/plugins/util/CallExpression.js +6 -32
- package/dist/plugins/util/CallExpression.js.map +1 -1
- package/dist/plugins/util/CodeTransformation.d.ts +12 -4
- package/dist/plugins/util/CodeTransformation.js +120 -56
- package/dist/plugins/util/CodeTransformation.js.map +1 -1
- package/dist/plugins/util/ConfigurationFunction.d.ts +3 -4
- package/dist/plugins/util/ConfigurationFunction.js +37 -37
- package/dist/plugins/util/ConfigurationFunction.js.map +1 -1
- package/dist/plugins/util/ObjectLiteral.d.ts +1 -1
- package/dist/plugins/util/ObjectLiteral.js +6 -29
- package/dist/plugins/util/ObjectLiteral.js.map +1 -1
- package/dist/util/Debug.js +5 -8
- package/dist/util/Debug.js.map +1 -1
- package/dist/util/Directive.d.ts +16 -0
- package/dist/util/Directive.js +107 -0
- package/dist/util/Directive.js.map +1 -0
- package/dist/util/Util.js +1 -25
- package/dist/util/Util.js.map +1 -1
- package/dist/util/index.d.ts +1 -0
- package/dist/util/index.js +1 -0
- package/dist/util/index.js.map +1 -1
- package/package.json +5 -10
- package/src/BuildOptions.ts +1 -3
- package/src/GUID.ts +3 -13
- package/src/Keys.ts +11 -12
- package/src/TypeScript.ts +3 -3
- package/src/XML.ts +1 -4
- package/src/index.ts +0 -1
- package/src/plugins/Context.ts +5 -9
- package/src/plugins/Diagnostic.ts +2 -3
- package/src/plugins/behaviors/Diagnostics.ts +1 -2
- package/src/plugins/behaviors/extractors/Data.ts +1 -1
- package/src/plugins/behaviors/extractors/Extractors.ts +1 -1
- package/src/plugins/util/CallExpression.ts +4 -7
- package/src/plugins/util/CodeTransformation.ts +92 -24
- package/src/plugins/util/ConfigurationFunction.ts +72 -81
- package/src/plugins/util/ObjectLiteral.ts +1 -1
- package/src/util/Debug.ts +7 -10
- package/src/util/Directive.ts +123 -0
- package/src/util/Util.ts +1 -2
- package/src/util/index.ts +1 -0
|
@@ -1,17 +1,4 @@
|
|
|
1
|
-
import { Logger } from '@servicenow/sdk-project'
|
|
2
|
-
import {
|
|
3
|
-
ArrowFunction,
|
|
4
|
-
CallExpression,
|
|
5
|
-
FunctionExpression,
|
|
6
|
-
Identifier,
|
|
7
|
-
Node,
|
|
8
|
-
ObjectLiteralExpression,
|
|
9
|
-
PropertyAccessExpression,
|
|
10
|
-
PropertyAssignment,
|
|
11
|
-
SyntaxKind,
|
|
12
|
-
TemplateExpression,
|
|
13
|
-
ts,
|
|
14
|
-
} from 'ts-morph'
|
|
1
|
+
import { Logger, ts } from '@servicenow/sdk-project'
|
|
15
2
|
import { Context } from '../Context'
|
|
16
3
|
import { EntityData, ObjectData } from '../behaviors'
|
|
17
4
|
import { getCallExpressionName } from './CallExpression'
|
|
@@ -45,7 +32,7 @@ export type ComposerClass = {
|
|
|
45
32
|
export class ConfigurationFunctionEntityData extends EntityData {
|
|
46
33
|
constructor(
|
|
47
34
|
private readonly config: ConfigEntity,
|
|
48
|
-
node: CallExpression
|
|
35
|
+
node: ts.CallExpression
|
|
49
36
|
) {
|
|
50
37
|
super(
|
|
51
38
|
'test',
|
|
@@ -73,10 +60,10 @@ export class ConfigurationFunctionEntityData extends EntityData {
|
|
|
73
60
|
* ```
|
|
74
61
|
*/
|
|
75
62
|
export class ConfigurationFunctionExtractor {
|
|
76
|
-
private rootNode: CallExpression
|
|
63
|
+
private rootNode: ts.CallExpression
|
|
77
64
|
private context: Context
|
|
78
65
|
private composerClass: ComposerClass
|
|
79
|
-
private identifiers: (Identifier | null)[]
|
|
66
|
+
private identifiers: (ts.Identifier | null)[]
|
|
80
67
|
|
|
81
68
|
/**
|
|
82
69
|
*
|
|
@@ -84,7 +71,7 @@ export class ConfigurationFunctionExtractor {
|
|
|
84
71
|
* @param context context from the plugin this is called in
|
|
85
72
|
* @param composerClass A class whose prototype will be used to validate the allowed functions within the configuration function
|
|
86
73
|
*/
|
|
87
|
-
constructor(rootNode: CallExpression, context: Context, composerClass: ComposerClass) {
|
|
74
|
+
constructor(rootNode: ts.CallExpression, context: Context, composerClass: ComposerClass) {
|
|
88
75
|
this.rootNode = rootNode
|
|
89
76
|
this.context = context
|
|
90
77
|
this.composerClass = composerClass
|
|
@@ -94,11 +81,11 @@ export class ConfigurationFunctionExtractor {
|
|
|
94
81
|
/**
|
|
95
82
|
* Grabs the property access expression chain of a call expression, and protects against accidentally grabbing property access expressions in arguments of the call expression
|
|
96
83
|
*/
|
|
97
|
-
private getPropChain(ce: CallExpression): PropertyAccessExpression[] {
|
|
84
|
+
private getPropChain(ce: ts.CallExpression): ts.PropertyAccessExpression[] {
|
|
98
85
|
// Do this to ensure we are only considering property access expressions that are apart of the chain and not potentially in the arguments of the function
|
|
99
|
-
const props = [ce.getFirstDescendantByKindOrThrow(SyntaxKind.PropertyAccessExpression)]
|
|
100
|
-
const childProps = (props[0] as PropertyAccessExpression).getDescendantsOfKind(
|
|
101
|
-
SyntaxKind.PropertyAccessExpression
|
|
86
|
+
const props = [ce.getFirstDescendantByKindOrThrow(ts.SyntaxKind.PropertyAccessExpression)]
|
|
87
|
+
const childProps = (props[0] as ts.PropertyAccessExpression).getDescendantsOfKind(
|
|
88
|
+
ts.SyntaxKind.PropertyAccessExpression
|
|
102
89
|
)
|
|
103
90
|
if (childProps.length > 0) {
|
|
104
91
|
props.push(...childProps)
|
|
@@ -111,15 +98,15 @@ export class ConfigurationFunctionExtractor {
|
|
|
111
98
|
* v
|
|
112
99
|
* a.b.c.d({})
|
|
113
100
|
*/
|
|
114
|
-
private getFirstProp(ce: CallExpression): Identifier {
|
|
101
|
+
private getFirstProp(ce: ts.CallExpression): ts.Identifier {
|
|
115
102
|
// Need to use this instead of just grabbing descendents cause the arguments of the call expression can also potentially have property access expressions which we don't want to consider
|
|
116
103
|
const props = this.getPropChain(ce)
|
|
117
104
|
if (props.length === 1) {
|
|
118
|
-
const ids = props[0]?.getChildrenOfKind(SyntaxKind.Identifier) as Identifier[]
|
|
119
|
-
return ids[0] as Identifier
|
|
105
|
+
const ids = props[0]?.getChildrenOfKind(ts.SyntaxKind.Identifier) as ts.Identifier[]
|
|
106
|
+
return ids[0] as ts.Identifier
|
|
120
107
|
}
|
|
121
|
-
const lastProp = props[props.length - 1] as PropertyAccessExpression
|
|
122
|
-
return lastProp.getChildrenOfKind(SyntaxKind.Identifier)[0] as Identifier
|
|
108
|
+
const lastProp = props[props.length - 1] as ts.PropertyAccessExpression
|
|
109
|
+
return lastProp.getChildrenOfKind(ts.SyntaxKind.Identifier)[0] as ts.Identifier
|
|
123
110
|
}
|
|
124
111
|
|
|
125
112
|
/**
|
|
@@ -128,11 +115,11 @@ export class ConfigurationFunctionExtractor {
|
|
|
128
115
|
* v
|
|
129
116
|
* a.b.c.d({})
|
|
130
117
|
*/
|
|
131
|
-
private getLastProp(ce: CallExpression): Identifier {
|
|
118
|
+
private getLastProp(ce: ts.CallExpression): ts.Identifier {
|
|
132
119
|
// Do not need special chain handling here like in getFirstProp cause we are always grabbing the property access expression from the top level regardless of chain length
|
|
133
|
-
const props = ce.getFirstDescendantByKindOrThrow(SyntaxKind.PropertyAccessExpression)
|
|
134
|
-
const ids = props.getChildrenOfKind(SyntaxKind.Identifier) as Identifier[]
|
|
135
|
-
return ids[ids.length - 1] as Identifier // Identifier is either the only one present or is the last of 2 so this should fetch it in either scenario
|
|
120
|
+
const props = ce.getFirstDescendantByKindOrThrow(ts.SyntaxKind.PropertyAccessExpression)
|
|
121
|
+
const ids = props.getChildrenOfKind(ts.SyntaxKind.Identifier) as ts.Identifier[]
|
|
122
|
+
return ids[ids.length - 1] as ts.Identifier // Identifier is either the only one present or is the last of 2 so this should fetch it in either scenario
|
|
136
123
|
}
|
|
137
124
|
|
|
138
125
|
/**
|
|
@@ -140,7 +127,7 @@ export class ConfigurationFunctionExtractor {
|
|
|
140
127
|
* @param ce
|
|
141
128
|
* @param parameterName
|
|
142
129
|
*/
|
|
143
|
-
private isValidCallExpression(ce: CallExpression, paramId: Identifier) {
|
|
130
|
+
private isValidCallExpression(ce: ts.CallExpression, paramId: ts.Identifier) {
|
|
144
131
|
if (!paramId) {
|
|
145
132
|
throw Error('No parameter provided to configuration function')
|
|
146
133
|
}
|
|
@@ -165,7 +152,7 @@ export class ConfigurationFunctionExtractor {
|
|
|
165
152
|
}
|
|
166
153
|
|
|
167
154
|
// Verify that call expression has the expected number of arguments
|
|
168
|
-
const funcArgs = ce.getFirstDescendantByKind(SyntaxKind.SyntaxList)?.getChildren() as Node[]
|
|
155
|
+
const funcArgs = ce.getFirstDescendantByKind(ts.SyntaxKind.SyntaxList)?.getChildren() as ts.Node[]
|
|
169
156
|
if (!funcArgs) {
|
|
170
157
|
throw Error('Call expression had no arguments at all')
|
|
171
158
|
}
|
|
@@ -174,7 +161,7 @@ export class ConfigurationFunctionExtractor {
|
|
|
174
161
|
throw Error('Call expressions only support a single argument')
|
|
175
162
|
}
|
|
176
163
|
|
|
177
|
-
if ((funcArgs[0] as Node).getKind() != SyntaxKind.ObjectLiteralExpression) {
|
|
164
|
+
if ((funcArgs[0] as ts.Node).getKind() != ts.SyntaxKind.ObjectLiteralExpression) {
|
|
178
165
|
throw Error('Call expression must have an object as its argument')
|
|
179
166
|
}
|
|
180
167
|
}
|
|
@@ -186,7 +173,7 @@ export class ConfigurationFunctionExtractor {
|
|
|
186
173
|
* @param identifier
|
|
187
174
|
* @param data
|
|
188
175
|
*/
|
|
189
|
-
private findReferencedIdentifier(identifier: Identifier) {
|
|
176
|
+
private findReferencedIdentifier(identifier: ts.Identifier) {
|
|
190
177
|
const idName = identifier.getSymbol()?.getName()
|
|
191
178
|
// Identifier index lines up with step index, removed from step object so identifiers are not returned in extracted object
|
|
192
179
|
for (let i = 0; i < this.identifiers.length; i++) {
|
|
@@ -200,29 +187,29 @@ export class ConfigurationFunctionExtractor {
|
|
|
200
187
|
return -1
|
|
201
188
|
}
|
|
202
189
|
|
|
203
|
-
private getRootIdentifier(prop: PropertyAccessExpression): Identifier {
|
|
204
|
-
const children = prop.getChildrenOfKind(SyntaxKind.PropertyAccessExpression)
|
|
190
|
+
private getRootIdentifier(prop: ts.PropertyAccessExpression): ts.Identifier {
|
|
191
|
+
const children = prop.getChildrenOfKind(ts.SyntaxKind.PropertyAccessExpression)
|
|
205
192
|
if (children.length == 0) {
|
|
206
|
-
const id = prop.getFirstChildByKind(SyntaxKind.Identifier)
|
|
193
|
+
const id = prop.getFirstChildByKind(ts.SyntaxKind.Identifier)
|
|
207
194
|
if (!id) {
|
|
208
195
|
throw Error('Could not find identifier in property access expression')
|
|
209
196
|
}
|
|
210
197
|
return id
|
|
211
198
|
}
|
|
212
|
-
return this.getRootIdentifier(children[0] as PropertyAccessExpression)
|
|
199
|
+
return this.getRootIdentifier(children[0] as ts.PropertyAccessExpression)
|
|
213
200
|
}
|
|
214
201
|
|
|
215
|
-
private parseValue(valueNode: Node): any {
|
|
216
|
-
if (valueNode.getKind() == SyntaxKind.ArrayLiteralExpression) {
|
|
202
|
+
private parseValue(valueNode: ts.Node): any {
|
|
203
|
+
if (valueNode.getKind() == ts.SyntaxKind.ArrayLiteralExpression) {
|
|
217
204
|
const values: any[] = []
|
|
218
|
-
const syntaxList = valueNode.getFirstDescendantByKind(SyntaxKind.SyntaxList)
|
|
205
|
+
const syntaxList = valueNode.getFirstDescendantByKind(ts.SyntaxKind.SyntaxList)
|
|
219
206
|
if (!syntaxList) {
|
|
220
207
|
return
|
|
221
208
|
}
|
|
222
209
|
const children = syntaxList.getChildren()
|
|
223
210
|
|
|
224
211
|
for (const child of children) {
|
|
225
|
-
if (child.getKind() == SyntaxKind.CommaToken) {
|
|
212
|
+
if (child.getKind() == ts.SyntaxKind.CommaToken) {
|
|
226
213
|
continue
|
|
227
214
|
}
|
|
228
215
|
const value = this.parseValue(child)
|
|
@@ -231,13 +218,13 @@ export class ConfigurationFunctionExtractor {
|
|
|
231
218
|
return values
|
|
232
219
|
}
|
|
233
220
|
|
|
234
|
-
if (valueNode.getKind() == SyntaxKind.ObjectLiteralExpression) {
|
|
235
|
-
const objNode = valueNode as ObjectLiteralExpression
|
|
221
|
+
if (valueNode.getKind() == ts.SyntaxKind.ObjectLiteralExpression) {
|
|
222
|
+
const objNode = valueNode as ts.ObjectLiteralExpression
|
|
236
223
|
return this.objNodeToJSON(objNode)
|
|
237
224
|
}
|
|
238
225
|
|
|
239
|
-
if (valueNode.getKind() == SyntaxKind.PropertyAccessExpression) {
|
|
240
|
-
const propNode = valueNode as PropertyAccessExpression
|
|
226
|
+
if (valueNode.getKind() == ts.SyntaxKind.PropertyAccessExpression) {
|
|
227
|
+
const propNode = valueNode as ts.PropertyAccessExpression
|
|
241
228
|
const identifier = this.getRootIdentifier(propNode)
|
|
242
229
|
const refIdentifierIndex = this.findReferencedIdentifier(identifier)
|
|
243
230
|
if (refIdentifierIndex == -1) {
|
|
@@ -249,9 +236,9 @@ export class ConfigurationFunctionExtractor {
|
|
|
249
236
|
return { __references: refIdentifierIndex, __value: parsedValue[parsedValue.length - 1] }
|
|
250
237
|
}
|
|
251
238
|
|
|
252
|
-
if (valueNode.getKind() == SyntaxKind.TemplateExpression) {
|
|
253
|
-
// console.info(`literal: ${(valueNode as TemplateExpression).getVal}`)
|
|
254
|
-
const templateNode = valueNode as TemplateExpression
|
|
239
|
+
if (valueNode.getKind() == ts.SyntaxKind.TemplateExpression) {
|
|
240
|
+
// console.info(`literal: ${(valueNode as ts.TemplateExpression).getVal}`)
|
|
241
|
+
const templateNode = valueNode as ts.TemplateExpression
|
|
255
242
|
const templateValue = [templateNode.getHead().getLiteralText()]
|
|
256
243
|
templateNode.getTemplateSpans().forEach((s) => {
|
|
257
244
|
templateValue.push(this.parseValue(s.getExpression()))
|
|
@@ -262,13 +249,13 @@ export class ConfigurationFunctionExtractor {
|
|
|
262
249
|
|
|
263
250
|
// A variety of Identifiers. Will be handled here
|
|
264
251
|
// TODO: This is swallowing diagnostics and not handling the case where no data was extracted
|
|
265
|
-
return this.context.extractAst(valueNode)['data']
|
|
252
|
+
return this.context.extractAst(valueNode)['data']?.getValue()
|
|
266
253
|
}
|
|
267
254
|
|
|
268
|
-
private getKVPair(prop: PropertyAssignment) {
|
|
255
|
+
private getKVPair(prop: ts.PropertyAssignment) {
|
|
269
256
|
const props = prop.getChildren()
|
|
270
|
-
const keyNode = props[0] as
|
|
271
|
-
const valueNode = props[2] as
|
|
257
|
+
const keyNode = props[0] as ts.Node
|
|
258
|
+
const valueNode = props[2] as ts.Node
|
|
272
259
|
|
|
273
260
|
const key = (keyNode as any).getLiteralValue ? (keyNode as any).getLiteralValue() : keyNode.getText()
|
|
274
261
|
const value = this.parseValue(valueNode)
|
|
@@ -279,18 +266,18 @@ export class ConfigurationFunctionExtractor {
|
|
|
279
266
|
return { key: undefined, value: undefined }
|
|
280
267
|
}
|
|
281
268
|
|
|
282
|
-
private objNodeToJSON(obj: ObjectLiteralExpression | undefined): { [name: string]: any } {
|
|
269
|
+
private objNodeToJSON(obj: ts.ObjectLiteralExpression | undefined): { [name: string]: any } {
|
|
283
270
|
if (!obj) {
|
|
284
271
|
throw Error('objNodeToJSON received an undefined object node')
|
|
285
272
|
}
|
|
286
|
-
const syntaxList = obj.getFirstDescendantByKind(SyntaxKind.SyntaxList)
|
|
273
|
+
const syntaxList = obj.getFirstDescendantByKind(ts.SyntaxKind.SyntaxList)
|
|
287
274
|
|
|
288
275
|
if (!syntaxList) {
|
|
289
276
|
throw Error('objNodeToJSON could not find a syntax list in the ObjectLiteralExpression')
|
|
290
277
|
}
|
|
291
278
|
|
|
292
279
|
const json = {}
|
|
293
|
-
syntaxList.getChildrenOfKind(SyntaxKind.PropertyAssignment).forEach((arg) => {
|
|
280
|
+
syntaxList.getChildrenOfKind(ts.SyntaxKind.PropertyAssignment).forEach((arg) => {
|
|
294
281
|
const propArg = arg
|
|
295
282
|
const { key, value } = this.getKVPair(propArg)
|
|
296
283
|
// TODO: What if the value is actually undefined?
|
|
@@ -301,35 +288,35 @@ export class ConfigurationFunctionExtractor {
|
|
|
301
288
|
return json
|
|
302
289
|
}
|
|
303
290
|
|
|
304
|
-
private getName(node: CallExpression) {
|
|
291
|
+
private getName(node: ts.CallExpression) {
|
|
305
292
|
// This may not be robust but should be a good enough
|
|
306
293
|
const lastProp = this.getLastProp(node)
|
|
307
294
|
return lastProp.getText()
|
|
308
295
|
}
|
|
309
296
|
|
|
310
|
-
private getConfigFunctionComponents(kind: string, node:
|
|
297
|
+
private getConfigFunctionComponents(kind: string, node: ts.CallExpression) {
|
|
311
298
|
kind
|
|
312
299
|
const configArgs = node.getArguments()
|
|
313
300
|
if (configArgs.length != 2) {
|
|
314
301
|
throw Error('The plugin must have exactly 2 arguments')
|
|
315
302
|
}
|
|
316
303
|
|
|
317
|
-
if ((configArgs[0] as any).getKind() != SyntaxKind.ObjectLiteralExpression) {
|
|
304
|
+
if ((configArgs[0] as any).getKind() != ts.SyntaxKind.ObjectLiteralExpression) {
|
|
318
305
|
throw Error("The plugin's first argument was not an object")
|
|
319
306
|
}
|
|
320
307
|
|
|
321
308
|
if (
|
|
322
|
-
(configArgs[1] as any).getKind() != SyntaxKind.ArrowFunction &&
|
|
323
|
-
(configArgs[1] as any).getKind() != SyntaxKind.FunctionExpression
|
|
309
|
+
(configArgs[1] as any).getKind() != ts.SyntaxKind.ArrowFunction &&
|
|
310
|
+
(configArgs[1] as any).getKind() != ts.SyntaxKind.FunctionExpression
|
|
324
311
|
) {
|
|
325
312
|
throw Error("The plugin's second argument was not a function")
|
|
326
313
|
}
|
|
327
314
|
|
|
328
|
-
const objectArg = configArgs[0] as ObjectLiteralExpression
|
|
329
|
-
const configFunction = configArgs[1] as ArrowFunction | FunctionExpression
|
|
315
|
+
const objectArg = configArgs[0] as ts.ObjectLiteralExpression
|
|
316
|
+
const configFunction = configArgs[1] as ts.ArrowFunction | ts.FunctionExpression
|
|
330
317
|
|
|
331
318
|
// TODO: This is swallowing diagnostics and not handling the case where no data was extracted
|
|
332
|
-
const objectArgValue = this.context.extractAst(objectArg!)['data']
|
|
319
|
+
const objectArgValue = this.context.extractAst(objectArg!)['data']?.getValue()
|
|
333
320
|
|
|
334
321
|
if (!('$id' in objectArgValue)) {
|
|
335
322
|
throw Error('No $id defined in first argument')
|
|
@@ -337,25 +324,25 @@ export class ConfigurationFunctionExtractor {
|
|
|
337
324
|
|
|
338
325
|
const parameters = configFunction.getParameters()
|
|
339
326
|
// Checking the type is parameter is probably redundant but can not hurt
|
|
340
|
-
if (parameters.length != 1 || !parameters[0] || parameters[0].getKind() != SyntaxKind.Parameter) {
|
|
327
|
+
if (parameters.length != 1 || !parameters[0] || parameters[0].getKind() != ts.SyntaxKind.Parameter) {
|
|
341
328
|
throw Error('Configuration function must have an parameter as its only argument')
|
|
342
329
|
}
|
|
343
330
|
|
|
344
|
-
const paramId = parameters[0].getChildrenOfKind(SyntaxKind.Identifier)[0] as Identifier
|
|
345
|
-
const block = configFunction.getFirstChildByKind(SyntaxKind.Block)
|
|
331
|
+
const paramId = parameters[0].getChildrenOfKind(ts.SyntaxKind.Identifier)[0] as ts.Identifier
|
|
332
|
+
const block = configFunction.getFirstChildByKind(ts.SyntaxKind.Block)
|
|
346
333
|
if (!block) {
|
|
347
334
|
throw Error(`Failed to find block in configuration function`)
|
|
348
335
|
}
|
|
349
336
|
|
|
350
|
-
const syntaxList = block.getFirstChildByKind(SyntaxKind.SyntaxList)
|
|
337
|
+
const syntaxList = block.getFirstChildByKind(ts.SyntaxKind.SyntaxList)
|
|
351
338
|
if (!syntaxList) {
|
|
352
339
|
throw Error(`Failed to find syntax list in configuration function`)
|
|
353
340
|
}
|
|
354
341
|
return { paramId, syntaxList, objectArgValue }
|
|
355
342
|
}
|
|
356
343
|
|
|
357
|
-
private extractCallExpression(node: Node, paramId: Identifier) {
|
|
358
|
-
const callExpressions = node.getDescendantsOfKind(SyntaxKind.CallExpression)
|
|
344
|
+
private extractCallExpression(node: ts.Node, paramId: ts.Identifier) {
|
|
345
|
+
const callExpressions = node.getDescendantsOfKind(ts.SyntaxKind.CallExpression)
|
|
359
346
|
|
|
360
347
|
if (callExpressions.length == 0) {
|
|
361
348
|
throw Error(`Expression statement did not have any call expression`)
|
|
@@ -365,7 +352,7 @@ export class ConfigurationFunctionExtractor {
|
|
|
365
352
|
throw Error(`Found more than one call expression inside of an expression statement`)
|
|
366
353
|
}
|
|
367
354
|
|
|
368
|
-
const callExpression = callExpressions[0] as CallExpression
|
|
355
|
+
const callExpression = callExpressions[0] as ts.CallExpression
|
|
369
356
|
this.isValidCallExpression(callExpression, paramId)
|
|
370
357
|
return callExpression
|
|
371
358
|
}
|
|
@@ -410,7 +397,7 @@ export class ConfigurationFunctionExtractor {
|
|
|
410
397
|
syntaxList.getChildren().forEach((statement) => {
|
|
411
398
|
try {
|
|
412
399
|
switch (statement.getKind()) {
|
|
413
|
-
case SyntaxKind.ExpressionStatement: {
|
|
400
|
+
case ts.SyntaxKind.ExpressionStatement: {
|
|
414
401
|
/**
|
|
415
402
|
* (param) => {
|
|
416
403
|
* param.foo({arg: 'value'}) <- Expression statement
|
|
@@ -422,41 +409,45 @@ export class ConfigurationFunctionExtractor {
|
|
|
422
409
|
const ce = this.extractCallExpression(statement, paramId)
|
|
423
410
|
data[stepNumber++] = {
|
|
424
411
|
name: this.getName(ce),
|
|
425
|
-
info: this.objNodeToJSON(
|
|
412
|
+
info: this.objNodeToJSON(
|
|
413
|
+
ce.getFirstDescendantByKind(ts.SyntaxKind.ObjectLiteralExpression)
|
|
414
|
+
),
|
|
426
415
|
}
|
|
427
416
|
this.identifiers.push(null)
|
|
428
417
|
break
|
|
429
418
|
}
|
|
430
|
-
case SyntaxKind.VariableStatement: {
|
|
419
|
+
case ts.SyntaxKind.VariableStatement: {
|
|
431
420
|
/**
|
|
432
421
|
* (param) => {
|
|
433
422
|
* const output = param.foo({arg: 'value'}) <- Variable statement
|
|
434
423
|
* }
|
|
435
424
|
*/
|
|
436
425
|
const ce = this.extractCallExpression(statement, paramId)
|
|
437
|
-
const variableDeclaration = statement.getFirstDescendantByKind(
|
|
426
|
+
const variableDeclaration = statement.getFirstDescendantByKind(
|
|
427
|
+
ts.SyntaxKind.VariableDeclaration
|
|
428
|
+
)
|
|
438
429
|
|
|
439
430
|
if (!variableDeclaration) {
|
|
440
431
|
throw Error('Could not find variable declaration in variable statement')
|
|
441
432
|
}
|
|
442
433
|
|
|
443
434
|
const assignment = variableDeclaration.getChildren() // Format: identifier, =, value
|
|
444
|
-
const identifier = assignment[0] as Identifier
|
|
445
|
-
const value = assignment[2] as CallExpression // Already been validated above to be a valid call expression
|
|
435
|
+
const identifier = assignment[0] as ts.Identifier
|
|
436
|
+
const value = assignment[2] as ts.CallExpression // Already been validated above to be a valid call expression
|
|
446
437
|
|
|
447
438
|
data[stepNumber++] = {
|
|
448
439
|
name: this.getName(ce),
|
|
449
440
|
info: this.objNodeToJSON(
|
|
450
|
-
value.getFirstDescendantByKind(SyntaxKind.ObjectLiteralExpression)
|
|
441
|
+
value.getFirstDescendantByKind(ts.SyntaxKind.ObjectLiteralExpression)
|
|
451
442
|
),
|
|
452
443
|
}
|
|
453
444
|
this.identifiers.push(identifier)
|
|
454
445
|
break
|
|
455
446
|
}
|
|
456
|
-
case SyntaxKind.MultiLineCommentTrivia:
|
|
447
|
+
case ts.SyntaxKind.MultiLineCommentTrivia:
|
|
457
448
|
/** This is a multiline comment */
|
|
458
449
|
break
|
|
459
|
-
case SyntaxKind.SingleLineCommentTrivia:
|
|
450
|
+
case ts.SyntaxKind.SingleLineCommentTrivia:
|
|
460
451
|
// This is a single line comment
|
|
461
452
|
break
|
|
462
453
|
default:
|
package/src/util/Debug.ts
CHANGED
|
@@ -11,9 +11,8 @@ export function inspect(val: unknown, depth = 2) {
|
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
export function debugData(data: ({ data: unknown } | Data)[], logger: Logger, message = 'DATA:') {
|
|
14
|
-
logger.
|
|
15
|
-
|
|
16
|
-
inspect(
|
|
14
|
+
logger.debug(
|
|
15
|
+
`${message} ${inspect(
|
|
17
16
|
data.map((d) => {
|
|
18
17
|
if (d instanceof Data) {
|
|
19
18
|
return d.getValue()
|
|
@@ -22,25 +21,23 @@ export function debugData(data: ({ data: unknown } | Data)[], logger: Logger, me
|
|
|
22
21
|
}
|
|
23
22
|
}),
|
|
24
23
|
5
|
|
25
|
-
)
|
|
24
|
+
)}`
|
|
26
25
|
)
|
|
27
26
|
}
|
|
28
27
|
|
|
29
28
|
export function debugDocuments(documents: Document[], logger: Logger, message = 'DOCUMENTS:') {
|
|
30
|
-
logger.
|
|
31
|
-
|
|
32
|
-
inspect(
|
|
29
|
+
logger.debug(
|
|
30
|
+
`${message} ${inspect(
|
|
33
31
|
documents.map((d) => {
|
|
34
32
|
const { node, ...rest } = d
|
|
35
33
|
node
|
|
36
34
|
return rest
|
|
37
35
|
}),
|
|
38
36
|
5
|
|
39
|
-
)
|
|
37
|
+
)}`
|
|
40
38
|
)
|
|
41
39
|
}
|
|
42
40
|
|
|
43
41
|
export function debugFiles(files: File[], logger: Logger, message = 'FILES:') {
|
|
44
|
-
logger.
|
|
45
|
-
logger.info(inspect(files, 5))
|
|
42
|
+
logger.debug(`${message}: ${inspect(files, 5)}`)
|
|
46
43
|
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { ts, tsc, Diagnostic } from '@servicenow/sdk-project'
|
|
2
|
+
import { Context } from '../plugins/Context'
|
|
3
|
+
import { FluentDiagnostic } from '../plugins'
|
|
4
|
+
|
|
5
|
+
const FluentDisableSyncDirective = '@fluent-disable-sync'
|
|
6
|
+
const FluentDisableSyncForFileDirective = '@fluent-disable-sync-for-file'
|
|
7
|
+
const fluentCommentDirectiveRegEx = /^\/\/\/?\s*@fluent-ignore\b/
|
|
8
|
+
|
|
9
|
+
enum FluentDirectiveType {
|
|
10
|
+
Ignore = 'ignore',
|
|
11
|
+
}
|
|
12
|
+
export type FluentDirective = {
|
|
13
|
+
filePath: string
|
|
14
|
+
start: number
|
|
15
|
+
type: FluentDirectiveType
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function getDirectiveFromCommentText(text: string) {
|
|
19
|
+
const directiveRegex = /^.*(\/{2,}|\/\*{1,})*\s*(@fluent-[-_a-zA-Z0-9]+).*$/m
|
|
20
|
+
return text.match(directiveRegex)?.[2]
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function getDirectivesFromAncestors(node: ts.Node) {
|
|
24
|
+
return [node].concat(node.getAncestors()).flatMap(
|
|
25
|
+
(ancestor) =>
|
|
26
|
+
ancestor
|
|
27
|
+
.getLeadingCommentRanges()
|
|
28
|
+
.map((comment) => getDirectiveFromCommentText(comment.getText()))
|
|
29
|
+
.filter((directive) => directive) as string[]
|
|
30
|
+
)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function isFluentDirective(text: string, kind: tsc.CommentKind) {
|
|
34
|
+
text = text.trim()
|
|
35
|
+
if (kind === tsc.SyntaxKind.SingleLineCommentTrivia) {
|
|
36
|
+
return fluentCommentDirectiveRegEx.test(text)
|
|
37
|
+
}
|
|
38
|
+
text = text.substring(2, text.length - 2).trim()
|
|
39
|
+
return /^@fluent-ignore\b/.test(text)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function parseFluentDirectives(filePath: string, context: Context) {
|
|
43
|
+
const fluentDirectives: FluentDirective[] = []
|
|
44
|
+
const visitedRange = new Set<number>()
|
|
45
|
+
const sourceFile = context.compiler.getSourceFile(filePath)
|
|
46
|
+
if (sourceFile) {
|
|
47
|
+
const sourceCode = sourceFile.getFullText()
|
|
48
|
+
context.compiler.visitNodeTree(sourceFile, (node) => {
|
|
49
|
+
;[
|
|
50
|
+
...(tsc.getLeadingCommentRanges(sourceCode, node.getFullStart()) ?? []),
|
|
51
|
+
...(tsc.getTrailingCommentRanges(sourceCode, node.getFullStart()) ?? []),
|
|
52
|
+
].forEach((range) => {
|
|
53
|
+
if (
|
|
54
|
+
!visitedRange.has(range.pos) &&
|
|
55
|
+
isFluentDirective(sourceCode.substring(range.pos, range.end), range.kind)
|
|
56
|
+
) {
|
|
57
|
+
fluentDirectives.push({
|
|
58
|
+
filePath,
|
|
59
|
+
start: range.pos,
|
|
60
|
+
type: FluentDirectiveType.Ignore,
|
|
61
|
+
})
|
|
62
|
+
visitedRange.add(range.pos)
|
|
63
|
+
}
|
|
64
|
+
})
|
|
65
|
+
})
|
|
66
|
+
}
|
|
67
|
+
return fluentDirectives
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function syncDisabledForNode(node: ts.Node) {
|
|
71
|
+
return getDirectivesFromAncestors(node).some((directive) => directive === FluentDisableSyncDirective)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function syncDisabledForFile(sourceFile: ts.SourceFile) {
|
|
75
|
+
return sourceFile
|
|
76
|
+
.getStatements()?.[0]
|
|
77
|
+
?.getLeadingCommentRanges()
|
|
78
|
+
.map((comment) => getDirectiveFromCommentText(comment.getText()))
|
|
79
|
+
.some((directive) => directive === FluentDisableSyncForFileDirective)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function applyFluentDirectives(context: Context, diagnostics: Diagnostic[]) {
|
|
83
|
+
const directiveCache = new Map<string, FluentDirective[]>()
|
|
84
|
+
const filteredDiagnostics = diagnostics.filter((diagnostic) => {
|
|
85
|
+
const filePath = diagnostic.file.getFilePath()
|
|
86
|
+
let fluentDirectives = directiveCache.get(filePath)
|
|
87
|
+
if (!fluentDirectives) {
|
|
88
|
+
fluentDirectives = parseFluentDirectives(filePath, context)
|
|
89
|
+
directiveCache.set(filePath, fluentDirectives)
|
|
90
|
+
}
|
|
91
|
+
let allowDiagnostic = true
|
|
92
|
+
for (const directive of fluentDirectives) {
|
|
93
|
+
const { line: direcLine } = diagnostic.file.getLineAndColumnAtPos(directive.start)
|
|
94
|
+
const { line: diagLine } = diagnostic.file.getLineAndColumnAtPos(diagnostic.position.start)
|
|
95
|
+
if (direcLine + 1 === diagLine) {
|
|
96
|
+
allowDiagnostic = false
|
|
97
|
+
break
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return allowDiagnostic
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
return filteredDiagnostics
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export function getDirectiveDiagnostics(node: ts.Node): FluentDiagnostic[] {
|
|
107
|
+
// Currently, the @fluent-disable-sync directive is only allowed before a CallExpression
|
|
108
|
+
// If we see it, within one (say, in a PropertyAssignment), we should flag it
|
|
109
|
+
if (node.isKind(ts.SyntaxKind.CallExpression)) {
|
|
110
|
+
return node
|
|
111
|
+
.getDescendantsOfKind(ts.SyntaxKind.SingleLineCommentTrivia)
|
|
112
|
+
.filter((commentNode) => getDirectiveFromCommentText(commentNode.getText()) === FluentDisableSyncDirective)
|
|
113
|
+
.map((n) => {
|
|
114
|
+
return new FluentDiagnostic(
|
|
115
|
+
n,
|
|
116
|
+
`${FluentDisableSyncDirective} directive only allowed before a call expression`,
|
|
117
|
+
{ level: Diagnostic.Level.Warn }
|
|
118
|
+
)
|
|
119
|
+
})
|
|
120
|
+
} else {
|
|
121
|
+
return []
|
|
122
|
+
}
|
|
123
|
+
}
|
package/src/util/Util.ts
CHANGED
package/src/util/index.ts
CHANGED