@servicenow/sdk-build-core 3.0.2 → 4.0.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.
Files changed (252) hide show
  1. package/dist/app.d.ts +25 -0
  2. package/dist/app.js +8 -0
  3. package/dist/app.js.map +1 -0
  4. package/dist/compiler.d.ts +60 -0
  5. package/dist/compiler.js +320 -0
  6. package/dist/compiler.js.map +1 -0
  7. package/dist/compression.d.ts +7 -0
  8. package/dist/compression.js +79 -0
  9. package/dist/compression.js.map +1 -0
  10. package/dist/crypto.d.ts +1 -0
  11. package/dist/crypto.js +9 -0
  12. package/dist/crypto.js.map +1 -0
  13. package/dist/diagnostic.d.ts +41 -0
  14. package/dist/diagnostic.js +130 -0
  15. package/dist/diagnostic.js.map +1 -0
  16. package/dist/{plugins/Diagnostic.d.ts → fluent-diagnostic.d.ts} +3 -2
  17. package/dist/fluent-diagnostic.js +23 -0
  18. package/dist/fluent-diagnostic.js.map +1 -0
  19. package/dist/fluent-directive.d.ts +8 -0
  20. package/dist/fluent-directive.js +54 -0
  21. package/dist/fluent-directive.js.map +1 -0
  22. package/dist/fluent-file.d.ts +5 -0
  23. package/dist/fluent-file.js +15 -0
  24. package/dist/fluent-file.js.map +1 -0
  25. package/dist/formatter.d.ts +11 -0
  26. package/dist/formatter.js +77 -0
  27. package/dist/formatter.js.map +1 -0
  28. package/dist/fs.d.ts +174 -0
  29. package/dist/fs.js +313 -0
  30. package/dist/fs.js.map +1 -0
  31. package/dist/guid.d.ts +2 -0
  32. package/dist/{GUID.js → guid.js} +3 -6
  33. package/dist/guid.js.map +1 -0
  34. package/dist/index.d.ts +19 -5
  35. package/dist/index.js +19 -5
  36. package/dist/index.js.map +1 -1
  37. package/dist/json.d.ts +5 -0
  38. package/dist/json.js +43 -0
  39. package/dist/json.js.map +1 -0
  40. package/dist/keys-registry.d.ts +64 -0
  41. package/dist/keys-registry.js +339 -0
  42. package/dist/keys-registry.js.map +1 -0
  43. package/dist/logger.d.ts +8 -0
  44. package/dist/logger.js +17 -0
  45. package/dist/logger.js.map +1 -0
  46. package/dist/now-config.d.ts +348 -0
  47. package/dist/now-config.js +283 -0
  48. package/dist/now-config.js.map +1 -0
  49. package/dist/path.d.ts +3 -0
  50. package/dist/path.js +12 -0
  51. package/dist/path.js.map +1 -0
  52. package/dist/plugins/cache.d.ts +20 -0
  53. package/dist/plugins/cache.js +46 -0
  54. package/dist/plugins/cache.js.map +1 -0
  55. package/dist/plugins/context.d.ts +85 -0
  56. package/dist/plugins/{Context.js → context.js} +1 -1
  57. package/dist/plugins/context.js.map +1 -0
  58. package/dist/plugins/database.d.ts +27 -0
  59. package/dist/plugins/database.js +102 -0
  60. package/dist/plugins/database.js.map +1 -0
  61. package/dist/plugins/file.d.ts +10 -0
  62. package/dist/plugins/{behaviors/Arranger.js → file.js} +1 -1
  63. package/dist/plugins/file.js.map +1 -0
  64. package/dist/plugins/index.d.ts +9 -5
  65. package/dist/plugins/index.js +9 -6
  66. package/dist/plugins/index.js.map +1 -1
  67. package/dist/plugins/plugin.d.ts +478 -0
  68. package/dist/plugins/plugin.js +533 -0
  69. package/dist/plugins/plugin.js.map +1 -0
  70. package/dist/plugins/product.d.ts +15 -0
  71. package/dist/plugins/product.js +38 -0
  72. package/dist/plugins/product.js.map +1 -0
  73. package/dist/plugins/project.d.ts +25 -0
  74. package/dist/plugins/{behaviors/Generator.js → project.js} +1 -1
  75. package/dist/plugins/project.js.map +1 -0
  76. package/dist/plugins/shape.d.ts +424 -0
  77. package/dist/plugins/shape.js +1181 -0
  78. package/dist/plugins/shape.js.map +1 -0
  79. package/dist/plugins/time.d.ts +12 -0
  80. package/dist/plugins/time.js +84 -0
  81. package/dist/plugins/time.js.map +1 -0
  82. package/dist/plugins/usage.d.ts +11 -0
  83. package/dist/plugins/usage.js +26 -0
  84. package/dist/plugins/usage.js.map +1 -0
  85. package/dist/prettier/config-loader.d.ts +13 -0
  86. package/dist/prettier/config-loader.js +105 -0
  87. package/dist/prettier/config-loader.js.map +1 -0
  88. package/dist/telemetry/index.d.ts +25 -0
  89. package/dist/telemetry/index.js +18 -0
  90. package/dist/telemetry/index.js.map +1 -0
  91. package/dist/typescript.d.ts +293 -0
  92. package/dist/typescript.js +454 -0
  93. package/dist/typescript.js.map +1 -0
  94. package/dist/util/get-file-type.d.ts +2 -0
  95. package/dist/util/get-file-type.js +13 -0
  96. package/dist/util/get-file-type.js.map +1 -0
  97. package/dist/util/index.d.ts +2 -6
  98. package/dist/util/index.js +2 -6
  99. package/dist/util/index.js.map +1 -1
  100. package/dist/util/{Scope.js → is-sn-scope.js} +1 -1
  101. package/dist/util/is-sn-scope.js.map +1 -0
  102. package/dist/xml.d.ts +24 -0
  103. package/dist/xml.js +71 -0
  104. package/dist/xml.js.map +1 -0
  105. package/now.config.schema.json +336 -0
  106. package/package.json +22 -12
  107. package/src/app.ts +33 -0
  108. package/src/compiler.ts +384 -0
  109. package/src/compression.ts +93 -0
  110. package/src/crypto.ts +5 -0
  111. package/src/diagnostic.ts +108 -0
  112. package/src/{plugins/Diagnostic.ts → fluent-diagnostic.ts} +3 -10
  113. package/src/fluent-directive.ts +63 -0
  114. package/src/fluent-file.ts +13 -0
  115. package/src/formatter.ts +58 -0
  116. package/src/fs.ts +438 -0
  117. package/src/{GUID.ts → guid.ts} +2 -6
  118. package/src/index.ts +19 -5
  119. package/src/json.ts +20 -0
  120. package/src/keys-registry.ts +384 -0
  121. package/src/logger.ts +20 -0
  122. package/src/now-config.ts +337 -0
  123. package/src/path.ts +9 -0
  124. package/src/plugins/cache.ts +45 -0
  125. package/src/plugins/context.ts +93 -0
  126. package/src/plugins/database.ts +121 -0
  127. package/src/plugins/file.ts +19 -0
  128. package/src/plugins/index.ts +9 -5
  129. package/src/plugins/plugin.ts +995 -0
  130. package/src/plugins/product.ts +44 -0
  131. package/src/plugins/project.ts +39 -0
  132. package/src/plugins/shape.ts +1532 -0
  133. package/src/plugins/time.ts +108 -0
  134. package/src/plugins/usage.ts +26 -0
  135. package/src/prettier/config-loader.ts +130 -0
  136. package/src/telemetry/index.ts +27 -0
  137. package/src/typescript.ts +502 -0
  138. package/src/util/get-file-type.ts +11 -0
  139. package/src/util/index.ts +2 -6
  140. package/src/xml.ts +86 -0
  141. package/dist/GUID.d.ts +0 -2
  142. package/dist/GUID.js.map +0 -1
  143. package/dist/IncludePaths.d.ts +0 -25
  144. package/dist/IncludePaths.js +0 -97
  145. package/dist/IncludePaths.js.map +0 -1
  146. package/dist/Keys.d.ts +0 -32
  147. package/dist/Keys.js +0 -245
  148. package/dist/Keys.js.map +0 -1
  149. package/dist/TypeScript.d.ts +0 -5
  150. package/dist/TypeScript.js +0 -58
  151. package/dist/TypeScript.js.map +0 -1
  152. package/dist/XML.d.ts +0 -32
  153. package/dist/XML.js +0 -77
  154. package/dist/XML.js.map +0 -1
  155. package/dist/plugins/Context.d.ts +0 -190
  156. package/dist/plugins/Context.js.map +0 -1
  157. package/dist/plugins/Diagnostic.js +0 -28
  158. package/dist/plugins/Diagnostic.js.map +0 -1
  159. package/dist/plugins/Plugin.d.ts +0 -175
  160. package/dist/plugins/Plugin.js +0 -15
  161. package/dist/plugins/Plugin.js.map +0 -1
  162. package/dist/plugins/behaviors/Arranger.d.ts +0 -26
  163. package/dist/plugins/behaviors/Arranger.js.map +0 -1
  164. package/dist/plugins/behaviors/Composer.d.ts +0 -102
  165. package/dist/plugins/behaviors/Composer.js +0 -15
  166. package/dist/plugins/behaviors/Composer.js.map +0 -1
  167. package/dist/plugins/behaviors/Diagnostics.d.ts +0 -7
  168. package/dist/plugins/behaviors/Diagnostics.js +0 -3
  169. package/dist/plugins/behaviors/Diagnostics.js.map +0 -1
  170. package/dist/plugins/behaviors/Generator.d.ts +0 -21
  171. package/dist/plugins/behaviors/Generator.js.map +0 -1
  172. package/dist/plugins/behaviors/OwnedTables.d.ts +0 -6
  173. package/dist/plugins/behaviors/OwnedTables.js +0 -3
  174. package/dist/plugins/behaviors/OwnedTables.js.map +0 -1
  175. package/dist/plugins/behaviors/PostProcessor.d.ts +0 -5
  176. package/dist/plugins/behaviors/PostProcessor.js +0 -3
  177. package/dist/plugins/behaviors/PostProcessor.js.map +0 -1
  178. package/dist/plugins/behaviors/Serializer.d.ts +0 -30
  179. package/dist/plugins/behaviors/Serializer.js +0 -3
  180. package/dist/plugins/behaviors/Serializer.js.map +0 -1
  181. package/dist/plugins/behaviors/Transformer.d.ts +0 -23
  182. package/dist/plugins/behaviors/Transformer.js +0 -3
  183. package/dist/plugins/behaviors/Transformer.js.map +0 -1
  184. package/dist/plugins/behaviors/extractors/Data.d.ts +0 -119
  185. package/dist/plugins/behaviors/extractors/Data.js +0 -244
  186. package/dist/plugins/behaviors/extractors/Data.js.map +0 -1
  187. package/dist/plugins/behaviors/extractors/Extractors.d.ts +0 -63
  188. package/dist/plugins/behaviors/extractors/Extractors.js +0 -3
  189. package/dist/plugins/behaviors/extractors/Extractors.js.map +0 -1
  190. package/dist/plugins/behaviors/extractors/index.d.ts +0 -2
  191. package/dist/plugins/behaviors/extractors/index.js +0 -19
  192. package/dist/plugins/behaviors/extractors/index.js.map +0 -1
  193. package/dist/plugins/behaviors/index.d.ts +0 -9
  194. package/dist/plugins/behaviors/index.js +0 -26
  195. package/dist/plugins/behaviors/index.js.map +0 -1
  196. package/dist/plugins/util/CallExpression.d.ts +0 -5
  197. package/dist/plugins/util/CallExpression.js +0 -88
  198. package/dist/plugins/util/CallExpression.js.map +0 -1
  199. package/dist/plugins/util/CodeTransformation.d.ts +0 -95
  200. package/dist/plugins/util/CodeTransformation.js +0 -624
  201. package/dist/plugins/util/CodeTransformation.js.map +0 -1
  202. package/dist/plugins/util/ObjectLiteral.d.ts +0 -9
  203. package/dist/plugins/util/ObjectLiteral.js +0 -37
  204. package/dist/plugins/util/ObjectLiteral.js.map +0 -1
  205. package/dist/plugins/util/index.d.ts +0 -3
  206. package/dist/plugins/util/index.js +0 -20
  207. package/dist/plugins/util/index.js.map +0 -1
  208. package/dist/util/Debug.d.ts +0 -4
  209. package/dist/util/Debug.js +0 -20
  210. package/dist/util/Debug.js.map +0 -1
  211. package/dist/util/Directive.d.ts +0 -16
  212. package/dist/util/Directive.js +0 -107
  213. package/dist/util/Directive.js.map +0 -1
  214. package/dist/util/RuntimeTableSchema.d.ts +0 -5
  215. package/dist/util/RuntimeTableSchema.js +0 -58
  216. package/dist/util/RuntimeTableSchema.js.map +0 -1
  217. package/dist/util/Scope.js.map +0 -1
  218. package/dist/util/Util.d.ts +0 -1
  219. package/dist/util/Util.js +0 -12
  220. package/dist/util/Util.js.map +0 -1
  221. package/dist/util/XMLUploadParser.d.ts +0 -22
  222. package/dist/util/XMLUploadParser.js +0 -67
  223. package/dist/util/XMLUploadParser.js.map +0 -1
  224. package/src/IncludePaths.ts +0 -122
  225. package/src/Keys.ts +0 -274
  226. package/src/TypeScript.ts +0 -65
  227. package/src/XML.ts +0 -92
  228. package/src/plugins/Context.ts +0 -239
  229. package/src/plugins/Plugin.ts +0 -278
  230. package/src/plugins/behaviors/Arranger.ts +0 -42
  231. package/src/plugins/behaviors/Composer.ts +0 -125
  232. package/src/plugins/behaviors/Diagnostics.ts +0 -12
  233. package/src/plugins/behaviors/Generator.ts +0 -31
  234. package/src/plugins/behaviors/OwnedTables.ts +0 -5
  235. package/src/plugins/behaviors/PostProcessor.ts +0 -6
  236. package/src/plugins/behaviors/Serializer.ts +0 -40
  237. package/src/plugins/behaviors/Transformer.ts +0 -32
  238. package/src/plugins/behaviors/extractors/Data.ts +0 -332
  239. package/src/plugins/behaviors/extractors/Extractors.ts +0 -73
  240. package/src/plugins/behaviors/extractors/index.ts +0 -2
  241. package/src/plugins/behaviors/index.ts +0 -9
  242. package/src/plugins/util/CallExpression.ts +0 -110
  243. package/src/plugins/util/CodeTransformation.ts +0 -731
  244. package/src/plugins/util/ObjectLiteral.ts +0 -37
  245. package/src/plugins/util/index.ts +0 -3
  246. package/src/util/Debug.ts +0 -24
  247. package/src/util/Directive.ts +0 -123
  248. package/src/util/RuntimeTableSchema.ts +0 -44
  249. package/src/util/Util.ts +0 -7
  250. package/src/util/XMLUploadParser.ts +0 -90
  251. /package/dist/util/{Scope.d.ts → is-sn-scope.d.ts} +0 -0
  252. /package/src/util/{Scope.ts → is-sn-scope.ts} +0 -0
@@ -1,731 +0,0 @@
1
- import { Logger, NOW_FILE_EXTENSION, SupportedNode, path, ts, tsc } from '@servicenow/sdk-project'
2
- const { format, resolve } = path
3
- import { Context } from '../Context'
4
- import { getCallExpressionName } from './CallExpression'
5
- import { isArray, isEmpty, isObject, isPlainObject } from 'lodash'
6
- import * as z from 'zod'
7
- import { Action, Document } from '../behaviors'
8
- import { isGUID } from '../../GUID'
9
- import { noThrow } from '../../util'
10
- import { getPropertyAssignment } from './ObjectLiteral'
11
-
12
- export function stringify(val: unknown) {
13
- if (typeof val === 'function') {
14
- return val.toString()
15
- }
16
- return JSON.stringify(val)
17
- }
18
-
19
- export type PartialElements<A extends unknown[]> = {
20
- [I in keyof A]: Partial<A[I]>
21
- }
22
-
23
- /**
24
- * Formats a source file name with the .now.ts extension.
25
- */
26
- export function formatSourceFileName(name: string) {
27
- return format({
28
- name,
29
- ext: NOW_FILE_EXTENSION,
30
- })
31
- }
32
-
33
- export function getSysUpdateName(document: Document & { xml?: string }, table: string) {
34
- if (document.xmlFilePath) {
35
- return path.basename(document.xmlFilePath, path.extname(document.xmlFilePath))
36
- }
37
- return `${table}_${document.guid}`
38
- }
39
-
40
- export function getOrCreateEntitySourceFile(context: Context, sysUpdateName: string) {
41
- const fullPath = resolve(context.app.rootDir, context.app.config.generatedDir, formatSourceFileName(sysUpdateName))
42
- const sourceFile = context.compiler.getSourceFile(fullPath)
43
- if (sourceFile) {
44
- return sourceFile
45
- }
46
-
47
- context.logger.info(`Generating new source file: ${fullPath}`)
48
- return context.compiler.createSourceFile(fullPath)
49
- }
50
-
51
- export function addDefaultImportIfAbsent(sourceFile: ts.SourceFile, moduleSpecifier: string, module: string) {
52
- const importDeclaration = sourceFile.getImportDeclaration((d) => d.getModuleSpecifierValue() === moduleSpecifier)
53
- if (!importDeclaration) {
54
- sourceFile.addImportDeclaration({
55
- moduleSpecifier,
56
- defaultImport: module,
57
- })
58
- return
59
- }
60
-
61
- const defaultImport = importDeclaration.getDefaultImport()?.getText()
62
- if (defaultImport && defaultImport === module) {
63
- return
64
- }
65
- importDeclaration.setDefaultImport(module)
66
- }
67
-
68
- export function addNamedImportIfAbsent(
69
- context: Context,
70
- sourceFile: ts.SourceFile,
71
- moduleSpecifier: string,
72
- module: { name: string } | string
73
- ): ts.ImportSpecifier {
74
- let importDeclaration = sourceFile.getImportDeclaration(
75
- (d) => d.getModuleSpecifierValue() === moduleSpecifier && !d.getNamespaceImport() // If it's a namespace import we cannot add named imports, so we have to create a new one
76
- )
77
-
78
- const importName = typeof module === 'string' ? module : module.name
79
- if (!importDeclaration) {
80
- importDeclaration = sourceFile.addImportDeclaration({
81
- moduleSpecifier,
82
- namedImports: [importName],
83
- })
84
- }
85
-
86
- const namedImports = importDeclaration.getNamedImports().find((n) => n.getName() === importName)
87
- if (namedImports) {
88
- return namedImports
89
- }
90
-
91
- context.logger.debug(
92
- `Adding named import '${importName}' from module '${moduleSpecifier}' to source file: ${sourceFile.getFilePath()}`
93
- )
94
-
95
- return importDeclaration.addNamedImport(importName)
96
- }
97
-
98
- /**
99
- * Generate an exported variable assignment initialized by a function call with
100
- * the provided arguments.
101
- */
102
- export function generateCallExpressionDefaultExport<const A extends unknown[]>(
103
- context: Context,
104
- sourceFile: ts.SourceFile,
105
- moduleSpecifier: string,
106
- fn: (...args: A) => unknown,
107
- ...args: PartialElements<A>
108
- ) {
109
- addNamedImportIfAbsent(context, sourceFile, moduleSpecifier, fn)
110
- const exportAssignment = sourceFile.addExportAssignment({
111
- isExportEquals: false,
112
- expression: `${fn.name}()`,
113
- })
114
-
115
- const callExpression = exportAssignment.getExpressionIfKindOrThrow(ts.SyntaxKind.CallExpression)
116
- transformFunctionArguments(callExpression, fn, ...args)
117
-
118
- return exportAssignment
119
- }
120
-
121
- export function generateCallExpressionExport<const A extends unknown[]>(
122
- context: Context,
123
- sourceFile: ts.SourceFile,
124
- moduleSpecifier: string,
125
- exportName: string,
126
- fn: (...args: A) => unknown,
127
- ...args: PartialElements<A>
128
- ) {
129
- addNamedImportIfAbsent(context, sourceFile, moduleSpecifier, fn)
130
- const variableDeclaration = sourceFile
131
- .addVariableStatement({
132
- isExported: true,
133
- declarationKind: ts.VariableDeclarationKind.Const,
134
- declarations: [
135
- {
136
- name: exportName,
137
- initializer: `${fn.name}()`, // Generate empty function call since we will add arguments later
138
- },
139
- ],
140
- })
141
- .getDeclarations()[0]!
142
-
143
- // Transform function call to add arguments
144
- const callExpression = variableDeclaration.getInitializerIfKindOrThrow(ts.SyntaxKind.CallExpression)
145
- transformFunctionArguments(callExpression, fn, ...args)
146
-
147
- return variableDeclaration
148
- }
149
-
150
- export function generateCallExpression<const A extends unknown[]>(
151
- context: Context,
152
- sourceFile: ts.SourceFile,
153
- moduleSpecifier: string,
154
- fn: (...args: A) => unknown,
155
- ...args: PartialElements<A>
156
- ) {
157
- addNamedImportIfAbsent(context, sourceFile, moduleSpecifier, fn)
158
- sourceFile.addStatements((writer) => writer.newLine())
159
- const [statement] = sourceFile.addStatements(`${fn.name}()`)
160
-
161
- const expression = statement!.getChildAtIndexIfKindOrThrow(0, ts.SyntaxKind.CallExpression)
162
-
163
- transformFunctionArguments(expression, fn, ...args)
164
-
165
- return expression
166
- }
167
-
168
- /**
169
- * Generate an exported variable assignment initialized by a function call with the
170
- * provided arguments. The exported variable name will be automatically determined
171
- * based on the function's name and the document's ID.
172
- */
173
- export function generateCallExpressionExportForDocument<const A extends unknown[]>(
174
- context: Context,
175
- info: {
176
- sourceFile: ts.SourceFile
177
- moduleSpecifier: string
178
- },
179
- fn: (...args: A) => unknown,
180
- ...args: PartialElements<A>
181
- ) {
182
- const { sourceFile, moduleSpecifier } = info
183
- return generateCallExpressionDefaultExport(context, sourceFile, moduleSpecifier, fn, ...args)
184
- }
185
-
186
- export function getOrCreatePropertyAssignment(
187
- obj: ts.ObjectLiteralExpression,
188
- name: string,
189
- initializer: string = 'undefined'
190
- ): ts.PropertyAssignment {
191
- const stringifiedName = stringify(name)
192
- const prop =
193
- obj.getProperty(name)?.asKind(ts.SyntaxKind.PropertyAssignment) ??
194
- obj.getProperty(stringifiedName)?.asKind(ts.SyntaxKind.PropertyAssignment)
195
-
196
- if (prop) {
197
- return prop
198
- }
199
-
200
- let propOrErr
201
- /**
202
- * Adding back the previous stringify regex check because property name with space when set without stringified works but later on throws error
203
- */
204
- if (/^[a-zA-Z0-9_$]*$/.test(name)) {
205
- propOrErr = noThrow(() => obj.addPropertyAssignment({ name, initializer }))
206
- }
207
-
208
- if (!propOrErr || propOrErr instanceof Error) {
209
- return obj.addPropertyAssignment({ name: stringifiedName, initializer })
210
- }
211
- return propOrErr
212
- }
213
-
214
- export function isEscapedPropertyAssignment(args: ts.ObjectLiteralExpression, name: string) {
215
- const prop = args.getProperty(name)
216
- if (!prop) {
217
- return false
218
- }
219
-
220
- const asExpression = prop.getChildAtIndexIfKind(2, ts.SyntaxKind.AsExpression)
221
- if (asExpression && asExpression.getFullText().indexOf('any') !== -1) {
222
- return true
223
- }
224
-
225
- return false
226
- }
227
-
228
- function isResolvablePropertyAssignment(args: ts.ObjectLiteralExpression, propertyName: string) {
229
- const prop = args.getProperty(propertyName)
230
- if (!prop) {
231
- return false
232
- }
233
-
234
- const identifierExp = prop.getChildAtIndexIfKind(2, ts.SyntaxKind.Identifier)
235
- if (!identifierExp) {
236
- return false
237
- }
238
-
239
- // Variable definition may be from other file
240
- identifierExp.getSourceFile().fixMissingImports()
241
-
242
- const definitions = identifierExp.getDefinitionNodes()
243
- if (definitions && definitions.length > 0) {
244
- return true
245
- }
246
- return false
247
- }
248
-
249
- /** utility function to get the $id value in a object literal node */
250
- export const getNodeId = (node: ts.ObjectLiteralExpression) => {
251
- const prop = node.getPropertyOrThrow('$id').asKindOrThrow(ts.SyntaxKind.PropertyAssignment)
252
-
253
- if (prop.getInitializerIfKind(ts.SyntaxKind.ElementAccessExpression)) {
254
- const expression = prop.getInitializerIfKind(ts.SyntaxKind.ElementAccessExpression)?.getArgumentExpression()
255
- return (
256
- expression?.asKind(ts.SyntaxKind.StringLiteral)?.getLiteralValue() ??
257
- expression?.asKind(ts.SyntaxKind.NumericLiteral)?.getLiteralValue().toString()
258
- )
259
- } else if (prop.getInitializerIfKind(ts.SyntaxKind.StringLiteral)) {
260
- return prop.getInitializerIfKind(ts.SyntaxKind.StringLiteral)?.getLiteralValue()
261
- }
262
- return `${prop.getInitializerIfKind(ts.SyntaxKind.NumericLiteral)?.getLiteralValue()}`
263
- }
264
-
265
- /** utility iterator for iterating array structures in rest api*/
266
- export class ArrayIterator {
267
- arrayExpression: ts.ArrayLiteralExpression
268
- elements: ts.Expression<tsc.Expression>[]
269
- idx: number
270
-
271
- constructor(private prop: ts.PropertyAssignment) {
272
- this.arrayExpression = this.prop.getInitializerIfKindOrThrow(ts.SyntaxKind.ArrayLiteralExpression)!
273
- this.elements = this.arrayExpression.getElements()
274
- this.idx = 0
275
- }
276
-
277
- hasNext() {
278
- return this.idx < this.elements.length
279
- }
280
-
281
- next() {
282
- return this.elements[this.idx++]!
283
- }
284
-
285
- getExpression() {
286
- return this.arrayExpression
287
- }
288
- }
289
-
290
- export function writeArrayPropertyAsReference(
291
- arg: ts.ObjectLiteralExpression,
292
- name: string,
293
- def: string,
294
- value: string[]
295
- ) {
296
- if (!value || !isArray(value)) {
297
- return
298
- }
299
-
300
- const propertyAssignment = getOrCreatePropertyAssignment(arg, name, def)
301
-
302
- const newValues = value.map((val) => {
303
- propertyAssignment.setInitializer((writer) => {
304
- writer.write(val)
305
- })
306
-
307
- return isResolvablePropertyAssignment(arg, name) ? val : `'${val}' as any`
308
- })
309
-
310
- propertyAssignment.setInitializer((writer) => {
311
- writer.write(`[${newValues}]`)
312
- })
313
- }
314
-
315
- export const recordSchema = z.object({
316
- $id: z.union([z.string(), z.number()]),
317
- data: z.record(z.any()),
318
- table: z.string(),
319
- })
320
-
321
- export function addCallExpressionToProperty(obj: ts.ObjectLiteralExpression, field: string, functionCall) {
322
- const property = getOrCreatePropertyAssignment(obj, field, functionCall)
323
- property.setInitializer((writer) => {
324
- writer.write(functionCall)
325
- })
326
- }
327
-
328
- export function writePropertyAsReference(
329
- logger: Logger,
330
- arg: ts.ObjectLiteralExpression,
331
- name: string,
332
- def: string,
333
- value: unknown
334
- ) {
335
- if (!value || isArray(value)) {
336
- return
337
- }
338
-
339
- // This value is already a reference that we shouldn't attempt to resolve
340
- if (recordSchema.safeParse(value).success) {
341
- return
342
- }
343
-
344
- const propertyAssignment = getOrCreatePropertyAssignment(arg, name, def)
345
-
346
- if (isEmpty(value)) {
347
- propertyAssignment.setInitializer((writer) => {
348
- writer.write(stringify(value))
349
- })
350
- }
351
-
352
- if (isPlainObject(value)) {
353
- const nestedArgs = propertyAssignment.getInitializerIfKindOrThrow(ts.SyntaxKind.ObjectLiteralExpression)
354
- for (const property in value) {
355
- if (isArray(value[property])) {
356
- writeArrayPropertyAsReference(nestedArgs, property, '[]', value[property])
357
- } else {
358
- writePropertyAsReference(logger, nestedArgs, property, '{}', value[property])
359
- }
360
- }
361
-
362
- return
363
- }
364
-
365
- const escapedPreTransform = isEscapedPropertyAssignment(arg, name)
366
-
367
- if (isGUID(value as string)) {
368
- propertyAssignment.setInitializer((writer) => {
369
- writer.write(stringify(value))
370
- })
371
- return
372
- }
373
-
374
- // This first write is to check whether the value is a resolvable idenfifier
375
- // We don't want to throw here if the property assignment would be malformed
376
- const maybeError = noThrow(() => {
377
- propertyAssignment.setInitializer((writer) => {
378
- if (value === 'default') {
379
- writer.write(stringify(value))
380
- } else {
381
- writer.write(value as string)
382
- }
383
- })
384
- })
385
- if (maybeError instanceof Error) {
386
- logger.warn(
387
- `Invalid reference value '${value}' for property '${name}' in file ${arg.getSourceFile().getFilePath()}`
388
- )
389
- }
390
- if (isResolvablePropertyAssignment(arg, name)) {
391
- return
392
- }
393
-
394
- value = `${stringify(value)} as any`
395
- if (!escapedPreTransform) {
396
- // Generate comment
397
- value = `${value} /*Generated*/` // comment like this '//comment' breaks the code in some occasion
398
- }
399
-
400
- propertyAssignment.setInitializer((writer) => {
401
- writer.write(value as string)
402
- })
403
- }
404
-
405
- export function writeCustomProperty(arg: ts.ObjectLiteralExpression, name: string, def: string, value: string) {
406
- if (!value) {
407
- return
408
- }
409
-
410
- const propertyAssignment = getOrCreatePropertyAssignment(arg, name, def)
411
- propertyAssignment.setInitializer((writer) => {
412
- writer.write(value)
413
- })
414
- }
415
-
416
- export function mergeDataIntoObjectLiteral(node: ts.ObjectLiteralExpression, data: object) {
417
- const properties = node
418
- .getProperties()
419
- .reduce((a, v) => ({ ...a, [getObjectPropertyAssignmentName(v as ts.PropertyAssignment)]: v }), {})
420
- for (const [key, value] of Object.entries(data)) {
421
- const array = isArray(value)
422
- if (!isEmpty(properties) && (value === '' || (array && value.length === 0))) {
423
- const existingAssignment = properties[key]
424
- if (existingAssignment) {
425
- removeNode(existingAssignment)
426
- }
427
- }
428
-
429
- if (isObject(value) && !Object.values(value).some((value) => value !== undefined)) {
430
- // Don't write an empty object literal
431
- continue
432
- }
433
-
434
- if (value !== '' && value !== undefined && !(array && value.length === 0)) {
435
- const propertyAssignment = properties[key]
436
- if (propertyAssignment) {
437
- if (isNowIncludeCall(propertyAssignment.getInitializerIfKind(ts.SyntaxKind.CallExpression))) {
438
- // Don't transform any updates to Now.includes calls
439
- continue
440
- }
441
- setPropertyAssignmentValue(propertyAssignment, value)
442
- } else {
443
- const newPropertyAssignment = getOrCreatePropertyAssignment(node, key, array ? '[]' : '{}')
444
- setPropertyAssignmentValue(newPropertyAssignment, value)
445
- }
446
- }
447
- }
448
- }
449
-
450
- /**
451
- * Merges an array of object literal data in to an existing array of object literal values
452
- * @param arrayNode Node with array to transform
453
- * @param data Array of object literals
454
- * @param comparisonProperty a property to be treated as the primary key of each object literal for comparison
455
- * @param action Should this item be deleted if found?
456
- */
457
- export function mergeDataIntoObjectLiteralArray(
458
- arrayNode: ts.ArrayLiteralExpression,
459
- data: any[],
460
- comparisonProperty: string,
461
- action?: Action
462
- ) {
463
- if (!data || data.length < 1) {
464
- return
465
- }
466
-
467
- const mappedData = data.reduce((map, obj) => ((map[obj[`${comparisonProperty}`]] = obj), map), {})
468
- arrayNode.getElements().forEach((element) => {
469
- const existingProperty =
470
- element
471
- .asKindOrThrow(ts.SyntaxKind.ObjectLiteralExpression)
472
- .getProperty(`${comparisonProperty}`)
473
- ?.getFirstChildByKind(ts.SyntaxKind.StringLiteral)
474
- ?.getLiteralValue() ?? undefined
475
- if (existingProperty && !mappedData[existingProperty]) {
476
- arrayNode.removeElement(element)
477
- }
478
- })
479
- const existingElements = arrayNode.getElements()
480
- data.forEach((obj) => {
481
- const transformElement = existingElements.find((element) => {
482
- const prop = element.asKindOrThrow(ts.SyntaxKind.ObjectLiteralExpression)
483
- const existingProperty = getPropertyAssignment(prop, `${comparisonProperty}`)?.getInitializerIfKind(
484
- ts.SyntaxKind.StringLiteral
485
- )
486
- return obj[`${comparisonProperty}`] === existingProperty?.getLiteralValue()
487
- })
488
-
489
- // Found existing element in arrays
490
- if (transformElement) {
491
- if (action && action === 'DELETE') {
492
- arrayNode.removeElement(transformElement)
493
- } else {
494
- mergeDataIntoObjectLiteral(transformElement.asKindOrThrow(ts.SyntaxKind.ObjectLiteralExpression), obj)
495
- }
496
- } else {
497
- arrayNode.addElement(stringify(filterEmpty(obj)))
498
- }
499
- })
500
- }
501
-
502
- // Remove default empty values
503
- export function filterEmpty(data: any) {
504
- return Object.entries(data).reduce((acc, [key, value]) => {
505
- if (value !== '') {
506
- acc[key] = value
507
- }
508
- return acc
509
- }, {})
510
- }
511
-
512
- export function escapeStringLiteralValues(str: string) {
513
- return str.replace(/[`\\]|\${/g, (char) => {
514
- switch (char) {
515
- case '`':
516
- return '\\`'
517
- case '\\':
518
- return '\\' + char
519
- case '${':
520
- return '\\${'
521
- default:
522
- return char
523
- }
524
- })
525
- }
526
-
527
- export function setPropertyAssignmentValue(
528
- property: ts.PropertyAssignment,
529
- value: string | ts.PropertyAssignmentStructure | ts.ImportSpecifierStructure | object
530
- ) {
531
- if (typeof value === 'object') {
532
- if (ts.Structure.isPropertyAssignment(value)) {
533
- property.setInitializer(value.initializer)
534
- } else if (ts.Structure.isImportSpecifier(value)) {
535
- property.setInitializer(value.name)
536
- } else if (isArray(value)) {
537
- property.setInitializer(stringify(value))
538
- } else {
539
- mergeDataIntoObjectLiteral(
540
- property.getInitializerIfKindOrThrow(ts.SyntaxKind.ObjectLiteralExpression),
541
- value
542
- )
543
- }
544
- return
545
- }
546
-
547
- //preserve any tagged template literals
548
- const taggedInitializer = property.getInitializerIfKind(ts.SyntaxKind.TaggedTemplateExpression)
549
- if (taggedInitializer) {
550
- const template = taggedInitializer.getTemplate()
551
-
552
- template.setLiteralValue(escapeStringLiteralValues(value))
553
- } else {
554
- const stringified =
555
- typeof value !== 'string' || value.indexOf('\n') < 0
556
- ? stringify(value)
557
- : `\`${escapeStringLiteralValues(value)}\``
558
- property.setInitializer(stringified)
559
- }
560
- }
561
-
562
- export function fixFunctionArgumentTypes(context: Context, node: ts.CallExpression) {
563
- if (node.wasForgotten()) {
564
- return
565
- }
566
- const typeChecker = context.compiler.getTypeChecker()
567
- const signature = typeChecker.getResolvedSignature(node)
568
- if (signature) {
569
- const callParams = signature.getParameters()
570
- for (let i = 0; i < callParams.length; i++) {
571
- const argType = callParams[i]?.getTypeAtLocation(node)
572
- const argNode = node.getArguments()[i]?.asKind(ts.SyntaxKind.ObjectLiteralExpression)
573
- if (!argType || !argNode) {
574
- break
575
- }
576
- fixNodeArgumentType(node, argNode, argType)
577
- }
578
- }
579
- }
580
-
581
- function fixNodeArgumentType(
582
- node: ts.CallExpression,
583
- argNode: ts.ObjectLiteralExpression | ts.PropertyAssignment,
584
- argType: ts.Type
585
- ) {
586
- if (argNode.getType().isObject()) {
587
- argType.getApparentProperties().forEach((prop) => {
588
- const propName = prop.getName()
589
- const propType = prop.getTypeAtLocation(node)
590
- let propNode: ts.PropertyAssignment | undefined
591
- if (argNode.isKind(ts.SyntaxKind.ObjectLiteralExpression)) {
592
- propNode = argNode.getProperty(propName)?.asKind(ts.SyntaxKind.PropertyAssignment)
593
- } else {
594
- propNode = argNode
595
- .getInitializerIfKind(ts.SyntaxKind.ObjectLiteralExpression)
596
- ?.getProperty(propName)
597
- ?.asKind(ts.SyntaxKind.PropertyAssignment)
598
- }
599
-
600
- if (!propNode) {
601
- return
602
- }
603
- fixNodeArgumentType(node, propNode, propType)
604
- })
605
- } else if (argNode.isKind(ts.SyntaxKind.PropertyAssignment)) {
606
- const nodeType = argNode.getType()
607
- if (nodeType.isAssignableTo(argType)) {
608
- return
609
- }
610
- // isAssignableTo doesnot play well with string literals in union types
611
- if (
612
- nodeType.isStringLiteral() &&
613
- argType.isUnion() &&
614
- argType.getUnionTypes().some((type) => type.getText() === nodeType.getText())
615
- ) {
616
- return
617
- }
618
-
619
- // fix types for string
620
- if (isStringType(argType)) {
621
- const argValue = argNode.getInitializer()?.getText()
622
- argNode.setInitializer(`'${argValue}'`)
623
- return
624
- }
625
-
626
- // cast 'as any' for other types
627
- const argValue = argNode.getInitializer()?.getText()
628
- argNode.setInitializer(`${argValue} as any`)
629
- }
630
- }
631
-
632
- function isStringType(argType: ts.Type) {
633
- if (argType.isUnion()) {
634
- return argType.getUnionTypes().some((type) => type.isString())
635
- }
636
- return argType.isString()
637
- }
638
-
639
- export function transformFunctionArguments<const A extends unknown[]>(
640
- node: ts.CallExpression,
641
- fn: (...args: A) => unknown,
642
- ...args: PartialElements<A>
643
- ) {
644
- if (getCallExpressionName(node) !== fn.name) {
645
- return false
646
- }
647
-
648
- for (let i = 0; i < args.length; i++) {
649
- const argValue = args[i]
650
- const argNode = node.getArguments()[i] ?? node.insertArgument(i, '{}')
651
-
652
- if (argValue && typeof argValue === 'object') {
653
- mergeDataIntoObjectLiteral(argNode.asKindOrThrow(ts.SyntaxKind.ObjectLiteralExpression), argValue)
654
- } else {
655
- argNode.replaceWithText(stringify(argValue))
656
- }
657
- }
658
-
659
- return true
660
- }
661
-
662
- export function removeNode(node: SupportedNode) {
663
- if ('remove' in node) {
664
- return node.remove()
665
- } else if (ts.Node.isCallExpression(node)) {
666
- const parent = node.getParent()
667
- if (ts.Node.isExpressionStatement(parent) || ts.Node.isVariableDeclaration(parent)) {
668
- return removeNode(parent)
669
- }
670
- } else if (ts.Node.isStatement(node)) {
671
- removeNode(node)
672
- }
673
-
674
- // TODO: Nodes that aren't complete statements can't be arbitrarily removed because it
675
- // will almost always result in broken code. Replacing with 'undefined' works pretty
676
- // much anywhere, but isn't very elegant. We should revisit this and perhaps make the
677
- // behavior configurable.
678
- node.replaceWithText('undefined')
679
- }
680
-
681
- /**
682
- * Re-extracts CallExpression property names for transform to check for customized properties on Plugin APIs.
683
- * If CallExpression properties don't match don't match schema expected by fluent this function will tranform updates
684
- * only to those properties (not new properties)
685
- * @param fn type of CallExpression to extract
686
- * @param node Node
687
- * @param dataForTransform Document Data passed to a transformer function
688
- * @param cleanedData Document data cleaned/parsed by a Zod step that has filtered out properties not handled by fluent
689
- */
690
- export function transformCustomizedProperties<
691
- const A extends unknown[],
692
- const E extends A extends [infer T extends Record<string, unknown>] ? T : never,
693
- >(fn: (...args: A) => E, node, dataForTransform, cleanedData) {
694
- if (!dataForTransform || !cleanedData) {
695
- return
696
- }
697
-
698
- const [arg] = node.getArguments()
699
- const properties = arg?.asKind(ts.SyntaxKind.ObjectLiteralExpression)?.getProperties()
700
-
701
- if (!properties) {
702
- return
703
- }
704
-
705
- const customizedProperties = {}
706
- Object.values(properties).forEach((prop) => {
707
- const propName = getObjectPropertyAssignmentName(prop as ts.PropertyAssignment)
708
- if (dataForTransform[propName] !== undefined && cleanedData[propName] === undefined) {
709
- customizedProperties[propName] = dataForTransform[propName]
710
- }
711
- })
712
-
713
- if (!isEmpty(customizedProperties)) {
714
- transformFunctionArguments(node, fn, ...([customizedProperties] as PartialElements<A>))
715
- }
716
- }
717
-
718
- export function isNowIncludeCall(callExpression?: ts.CallExpression) {
719
- if (!callExpression) {
720
- return false
721
- }
722
- const propertyAccessExp = callExpression.getExpressionIfKind(ts.SyntaxKind.PropertyAccessExpression)
723
- const nowNamespace = propertyAccessExp?.getExpressionIfKind(ts.SyntaxKind.Identifier)?.getText()
724
- const functionName = propertyAccessExp?.getName()
725
- return nowNamespace === 'Now' && functionName === 'include'
726
- }
727
-
728
- export function getObjectPropertyAssignmentName(objectProperty: ts.PropertyAssignment) {
729
- const nameNode = objectProperty.getNameNode()
730
- return nameNode.isKind(ts.SyntaxKind.StringLiteral) ? nameNode.getLiteralValue() : objectProperty.getName()
731
- }