@servicenow/sdk-build-core 3.0.3 → 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 -83
  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 -98
  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
@@ -0,0 +1,337 @@
1
+ import { parsePackageJson } from './app'
2
+ import * as z from 'zod'
3
+ import { path } from './path'
4
+ import { FileSystem } from './fs'
5
+ import type { Logger } from './logger'
6
+ import { Validator as JsonSchemaValidator, type ValidationError } from 'jsonschema'
7
+ import { readJson } from './json'
8
+ import { Compiler } from './compiler'
9
+ import { GUID } from './guid'
10
+
11
+ export type NowConfig = z.output<typeof NowConfigSchema>
12
+ export type NowConfigOptions = z.input<typeof NowConfigSchema>
13
+
14
+ type DeprecatedField = {
15
+ replacedBy?: string
16
+ transfer?: boolean
17
+ }
18
+
19
+ const NowConfigSchema = z
20
+ .object({
21
+ scope: z.string(),
22
+ scopeId: z.string(),
23
+ name: z.string().optional(),
24
+ serverModulesDir: z.string().default(path.join('src', 'server')),
25
+ modulePaths: z.record(z.string(), z.string()).default({}),
26
+ metadataDir: z.string().default('metadata'),
27
+ fluentDir: z.string().default(path.join('src', 'fluent')),
28
+ clientDir: z.string().default(path.join('src', 'client')),
29
+ typesDir: z.string().default(path.join('@types', 'servicenow')),
30
+ generatedDir: z.string().default(`generated`),
31
+ staticContentDir: z.string().default(path.join('dist', 'static')),
32
+ staticContentPaths: z.record(z.string(), z.string()).default({
33
+ 'src/client/*.html': 'dist/static/*.html',
34
+ }),
35
+ appOutputDir: z.string().default(path.join('dist', 'app')),
36
+ packOutputDir: z.string().default('target'),
37
+ npmUpdateCheck: z.literal(false).or(z.number()).default(10),
38
+ dependencies: z
39
+ .object({
40
+ applications: z
41
+ .record(
42
+ z.string(),
43
+ z.object({
44
+ tables: z.array(z.string()).or(z.literal('*')).optional(),
45
+ })
46
+ )
47
+ .optional(),
48
+ })
49
+ .optional(),
50
+ ignoreTransformTableList: z.array(z.string()).default([]),
51
+ tsconfigPath: z.string().optional(),
52
+ scripts: z.record(z.string(), z.string()).default({
53
+ prebuild: 'now.prebuild.mjs',
54
+ postbuild: 'now.postbuild.mjs',
55
+ }),
56
+ tableOutputFormat: z.enum(['bootstrap', 'component']).default('bootstrap'),
57
+
58
+ moduleDir: z.string().optional(), // Deprecated
59
+ compileOutputDir: z.string().optional(), // Deprecated
60
+ sourceDir: z.string().optional(), // Deprecated
61
+ transpiledSourceDir: z.string().optional(), // Deprecated
62
+
63
+ // SYS_APP UI values
64
+ active: z.boolean().optional(),
65
+ accessControls: z
66
+ .object({
67
+ scopedAdministration: z.boolean().optional(),
68
+ canEditInStudio: z.boolean().optional(),
69
+ runtimeAccessTracking: z.string().optional(),
70
+ restrictTableAccess: z.boolean().optional(),
71
+ userRole: z.string().optional(),
72
+ private: z.boolean().optional(),
73
+ trackable: z.boolean().optional(),
74
+ uninstallBlocked: z.boolean().optional(),
75
+ hideOnUI: z.boolean().optional(),
76
+ })
77
+ .optional(),
78
+ licensing: z
79
+ .object({
80
+ licensable: z.boolean().optional(),
81
+ enforceLicense: z.string().optional(),
82
+ licenseModel: z.string().optional(),
83
+ licenseCategory: z.string().optional(),
84
+ subscriptionEntitlement: z.string().optional(),
85
+ })
86
+ .optional(),
87
+ jsLevel: z.string().optional(),
88
+ menu: z.string().optional(),
89
+ description: z.string().optional(),
90
+ logo: z.string().optional(),
91
+ guidedSetupGuid: z.string().optional(),
92
+ installedAsDependency: z.boolean().optional(),
93
+ })
94
+ .refine((data) => {
95
+ if (!data.generatedDir.startsWith(data.fluentDir)) {
96
+ data.generatedDir = path.join(data.fluentDir, data.generatedDir)
97
+ }
98
+
99
+ const sdkDirectories: Array<
100
+ keyof Omit<
101
+ typeof data,
102
+ | 'scope'
103
+ | 'scopeId'
104
+ | 'npmUpdateCheck'
105
+ | 'dependencies'
106
+ | 'ignoreTransformTableList'
107
+ | 'modulePaths'
108
+ | 'staticContentPaths'
109
+ | 'tsconfigPath'
110
+ | 'active'
111
+ | 'licensing'
112
+ | 'accessControls'
113
+ | 'jsLevel'
114
+ | 'menu'
115
+ | 'logo'
116
+ | 'guidedSetupGuid'
117
+ | 'description'
118
+ | 'installedAsDependency'
119
+ | 'scripts'
120
+ | 'tableOutputFormat'
121
+ >
122
+ > = [
123
+ 'serverModulesDir',
124
+ 'metadataDir',
125
+ 'fluentDir',
126
+ 'clientDir',
127
+ 'generatedDir',
128
+ 'staticContentDir',
129
+ 'appOutputDir',
130
+ 'sourceDir',
131
+ 'transpiledSourceDir',
132
+ 'packOutputDir',
133
+ 'moduleDir',
134
+ 'compileOutputDir',
135
+ ]
136
+
137
+ sdkDirectories.forEach((dir) => {
138
+ if (data[dir]) {
139
+ data[dir] = path.normalize(data[dir])
140
+ }
141
+ })
142
+
143
+ return data
144
+ })
145
+
146
+ export namespace NowConfig {
147
+ export const FILE_NAME = 'now.config.json'
148
+
149
+ export const ERROR_ON_DEPRECATED_PROPS = {
150
+ transpiledSourceDir: `NowConfig: 'modulePaths' replaces 'transpiledSourceDir', please remove 'transpiledSourceDir'
151
+ and map original source files to transpiled output using 'modulePaths'
152
+
153
+ Ex:
154
+ "modulePaths": {
155
+ "src/server/*.js": "dist/modules/*.js",
156
+ "src/server/*.ts": "dist/modules/*.js",
157
+ }
158
+
159
+ If you are not intending to do custom module transpilation, please remove 'transpiledSourceDir'
160
+ and ensure 'serverModulesDir' is set to the directory containing modules `,
161
+ }
162
+
163
+ /**
164
+ *
165
+ * @param config Configuration Records read from now.config.json
166
+ * @param rootDir Root project directory used to parse tsconfig from tsconfigPath
167
+ * @param fs FileSystem
168
+ * @param logger
169
+ * @returns zod parsed NowConfig
170
+ */
171
+ export const parse = (config: Record<string, unknown>, logger: Logger): NowConfig => {
172
+ checkRemovedProperties(config)
173
+ replaceDeprecatedFields(config, logger)
174
+ return getParsedNowConfigData(config)
175
+ }
176
+
177
+ export const parseFromPath = (path: string, fsOrCompiler: FileSystem | Compiler, logger: Logger): NowConfig => {
178
+ const nowConfig = readNowConfigJsonFile(path, fsOrCompiler)
179
+ if (!nowConfig) {
180
+ throw new Error(`Failed to parse config file at path ${path}`)
181
+ }
182
+
183
+ return parse(nowConfig, logger)
184
+ }
185
+
186
+ export const parseFromDirectory = (dir: string, fs: FileSystem, logger: Logger): NowConfig => {
187
+ return parse(readNowConfigJsonFile(getFilePath(dir), fs) ?? parsePackageJson(dir, fs)['now'] ?? {}, logger)
188
+ }
189
+
190
+ export const exists = (dir: string, fs: FileSystem): boolean => {
191
+ if (FileSystem.existsSync(fs, getFilePath(dir))) {
192
+ return true
193
+ } else if (FileSystem.existsSync(fs, path.join(dir, 'package.json')) && parsePackageJson(dir, fs)['now']) {
194
+ return true
195
+ }
196
+ return false
197
+ }
198
+
199
+ export const getFilePath = (rootDir: string): string => {
200
+ return path.join(rootDir, FILE_NAME)
201
+ }
202
+
203
+ export function create({ scope, scopeId, ...rest }: Partial<NowConfigOptions> = {}): NowConfig {
204
+ return NowConfigSchema.parse({
205
+ scope: scope ?? 'global',
206
+ scopeId: scopeId ?? GUID(),
207
+ ...rest,
208
+ })
209
+ }
210
+
211
+ export function load({
212
+ rootDir,
213
+ compiler,
214
+ fileSystem,
215
+ logger,
216
+ }: {
217
+ rootDir: string
218
+ compiler: Compiler
219
+ fileSystem: FileSystem
220
+ logger: Logger
221
+ }): NowConfig {
222
+ const configFilePath = getFilePath(rootDir)
223
+ if (compiler.getSourceFile(configFilePath)) {
224
+ return NowConfig.parseFromPath(configFilePath, compiler, logger)
225
+ }
226
+
227
+ if (exists(rootDir, fileSystem)) {
228
+ return NowConfig.parseFromPath(configFilePath, fileSystem, logger)
229
+ }
230
+
231
+ return NowConfig.create()
232
+ }
233
+ }
234
+
235
+ const NOW_CONFIG_SCHEMA = require('../now.config.schema.json')
236
+
237
+ function getNowConfigFileValidationResults(json: unknown) {
238
+ const validator = new JsonSchemaValidator()
239
+ return validator.validate(json, NOW_CONFIG_SCHEMA)
240
+ }
241
+
242
+ function getParsedNowConfigData(config: Record<string, unknown>): NowConfig {
243
+ const parsedNowConfig = NowConfigSchema.safeParse(config)
244
+ if (!parsedNowConfig.success) {
245
+ let errMsg = `Invalid '${NowConfig.FILE_NAME}' file:\n`
246
+ parsedNowConfig.error.errors.map((err) => (errMsg += `${err.path}: ${err.message}\n`))
247
+ throw new Error(errMsg)
248
+ }
249
+
250
+ return parsedNowConfig.data
251
+ }
252
+
253
+ function validateNowConfigJsonFile(filePath: string, fsOrCompiler: FileSystem | Compiler) {
254
+ const json: unknown = readJson(filePath, '', fsOrCompiler)
255
+ if (!isObjectWithStringKeys(json)) {
256
+ throw new Error(`Config file '${NowConfig.FILE_NAME}' is empty or malformed`)
257
+ }
258
+
259
+ const result = getNowConfigFileValidationResults(json)
260
+ if (result.errors.length > 0) {
261
+ throw new Error(`${NowConfig.FILE_NAME} - error: ${formatValidationErrorMessage(result.errors)}`)
262
+ }
263
+
264
+ return json
265
+ }
266
+
267
+ function formatValidationErrorMessage(errors: ValidationError[]) {
268
+ return errors
269
+ .map((e) => {
270
+ if (!e.path.length) {
271
+ if (e.message === 'is of prohibited type [object Object]') {
272
+ return e.argument.message
273
+ }
274
+ return e.message
275
+ }
276
+
277
+ return `"${e.path.join('.')}" ${e.message}`
278
+ })
279
+ .join(', ')
280
+ }
281
+
282
+ function readNowConfigJsonFile(filePath: string, fsOrCompiler: FileSystem | Compiler) {
283
+ const exists =
284
+ fsOrCompiler instanceof Compiler
285
+ ? !!fsOrCompiler.getSourceFile(filePath)
286
+ : FileSystem.existsSync(fsOrCompiler, filePath)
287
+
288
+ if (exists) {
289
+ return validateNowConfigJsonFile(filePath, fsOrCompiler)
290
+ }
291
+
292
+ return null
293
+ }
294
+
295
+ function isObjectWithStringKeys(obj: unknown): obj is Record<string, unknown> {
296
+ if (!obj || typeof obj !== 'object' || Array.isArray(obj)) {
297
+ return false
298
+ }
299
+
300
+ for (const key in obj) {
301
+ if (typeof key !== 'string') {
302
+ return false
303
+ }
304
+ }
305
+
306
+ return true
307
+ }
308
+
309
+ const DEPRECATED_FIELDS: Record<string, DeprecatedField> = {
310
+ moduleDir: { replacedBy: 'serverModulesDir', transfer: true },
311
+ compileOutputDir: { replacedBy: 'appOutputDir', transfer: true },
312
+ entitiesDir: { replacedBy: 'fluentDir', transfer: true },
313
+ transpiledSourceDir: { replacedBy: 'modulePaths' },
314
+ sourceDir: {},
315
+ }
316
+
317
+ function replaceDeprecatedFields(config: Record<string, unknown>, logger: Logger) {
318
+ for (const [name, { replacedBy, transfer }] of Object.entries(DEPRECATED_FIELDS)) {
319
+ if (name in config) {
320
+ logger.warn(
321
+ `'${name}' is deprecated${replacedBy ? `, please replace with '${replacedBy}'` : ' and can be removed'}`
322
+ )
323
+
324
+ if (transfer && replacedBy) {
325
+ config[replacedBy] = config[name]
326
+ }
327
+ }
328
+ }
329
+ }
330
+
331
+ function checkRemovedProperties(config: Record<string, any>): void {
332
+ for (const [property, message] of Object.entries(NowConfig.ERROR_ON_DEPRECATED_PROPS)) {
333
+ if (property in config) {
334
+ throw new Error(message)
335
+ }
336
+ }
337
+ }
package/src/path.ts ADDED
@@ -0,0 +1,9 @@
1
+ import pathe from 'pathe'
2
+
3
+ export type PosixPathModule = Omit<typeof pathe, 'toNamespacedPath'>
4
+
5
+ const { toNamespacedPath, ...rest } = pathe
6
+
7
+ export const path: PosixPathModule = {
8
+ ...rest,
9
+ }
@@ -0,0 +1,45 @@
1
+ class SuccessEntry<T = unknown> {
2
+ constructor(private readonly value: T) {}
3
+
4
+ unwrap(): T {
5
+ return this.value
6
+ }
7
+
8
+ isError(): this is ErrorEntry {
9
+ return false
10
+ }
11
+ }
12
+
13
+ class ErrorEntry {
14
+ constructor(private readonly error: unknown) {}
15
+
16
+ unwrap(): unknown {
17
+ return this.error
18
+ }
19
+
20
+ isError(): this is ErrorEntry {
21
+ return true
22
+ }
23
+ }
24
+
25
+ export class Cache<K extends object, V> {
26
+ private cache = new WeakMap()
27
+
28
+ get(key: K): SuccessEntry<V> | ErrorEntry | undefined {
29
+ return this.cache.get(key)
30
+ }
31
+
32
+ put<const T extends V>(key: K, value: T): T {
33
+ this.cache.set(key, new SuccessEntry(value))
34
+ return value
35
+ }
36
+
37
+ error<const T>(key: K, error: T): T {
38
+ this.cache.set(key, new ErrorEntry(error))
39
+ return error
40
+ }
41
+
42
+ clear(): void {
43
+ this.cache = new WeakMap()
44
+ }
45
+ }
@@ -0,0 +1,93 @@
1
+ import type { Compiler } from '../compiler'
2
+ import type { Diagnostic } from '../diagnostic'
3
+ import type { FileSystem } from '../fs'
4
+ import type { Logger } from '../logger'
5
+ import type { Package } from '../app'
6
+ import type { ts } from '../typescript'
7
+ import type { Plugin, Plugins, Result } from './plugin'
8
+ import type { Product, Source } from './product'
9
+ import type { Project } from './project'
10
+ import type { Action, CoalesceKeys, ObjectShape, Record, RecordId, Shape, StringShape } from './shape'
11
+ import type { File, InstallCategory } from './file'
12
+ import type { Formatter } from '../formatter'
13
+ import type { NowConfig } from '../now-config'
14
+ import type { Database } from './database'
15
+
16
+ export interface Keys {
17
+ queryExplicitId(table: string, key: string | number | Shape): string | undefined
18
+ registerExplicitId(table: string, key: string | number | Shape, guidOverride?: string): string
19
+ deleteExplicitId(table: string, key: string | number, guidOverride?: string): string
20
+ queryCoalesceId(table: string, key: CoalesceKeys): string | undefined
21
+ registerCoalesceId(table: string, key: CoalesceKeys, guidOverride?: string): string
22
+ deleteCoalesceId(table: string, key: CoalesceKeys, guidOverride?: string): string
23
+ getEffectiveDeletedKeys(): Now.Internal.AnyKey[]
24
+ getSourceFile(): ts.SourceFile
25
+ getFilePath(): string
26
+ getValue(): Now.Internal.KeysRegistry
27
+ commit(formatter?: Formatter): Promise<void>
28
+ reload(): void
29
+ }
30
+
31
+ export interface Diagnostics {
32
+ error(source: Product | ts.Node, message: string): void
33
+ warn(source: Product | ts.Node, message: string): void
34
+ info(source: Product | ts.Node, message: string): void
35
+ hint(source: Product | ts.Node, message: string): void
36
+ add(diagnostic: Diagnostic): void
37
+ getAll(file?: string): Diagnostic[]
38
+ clear(file?: string): void
39
+ getWarnings(file?: string): Diagnostic[]
40
+ hasErrors(file?: string): boolean
41
+ getErrors(file?: string): Diagnostic[]
42
+ }
43
+
44
+ export interface Transform {
45
+ toShape(node: ts.Node, ...plugins: Plugin[]): Promise<Result<Shape>>
46
+ recordToShape(record: Record, database: Database, ...plugins: Plugin[]): Promise<Result<Shape>>
47
+ toSubclass<const S extends Shape>(shape: S, ...plugins: Plugin[]): Result<S>
48
+ toRecord(node: ts.Node, ...plugins: Plugin[]): Promise<Result<Record>>
49
+ toRecord(shape: Shape, ...plugins: Plugin[]): Promise<Result<Record>>
50
+ toRecord(file: File, ...plugins: Plugin[]): Promise<Result<Record>>
51
+ toRecord(source: ts.Node | Shape | File, ...plugins: Plugin[]): Promise<Result<Record>>
52
+ }
53
+
54
+ export interface Factory {
55
+ createShape<const S extends Shape>(shape: S): S
56
+
57
+ createRecord(args: {
58
+ source: Source
59
+ table: string
60
+ explicitId?: string | Shape
61
+ guidOverride?: string
62
+ properties: NonNullable<object>
63
+ action?: Action
64
+ installCategory?: InstallCategory
65
+ }): Record
66
+
67
+ createReference(args: {
68
+ source: Source
69
+ table: string | StringShape
70
+ guid?: string | StringShape | undefined
71
+ keys?: globalThis.Record<string, string | Shape> | ObjectShape | undefined
72
+ }): RecordId
73
+ }
74
+
75
+ export interface Parser {
76
+ parsePayload(file: File): Record[]
77
+ }
78
+
79
+ export type Context = {
80
+ readonly self: Plugin
81
+ readonly fs: FileSystem
82
+ readonly logger: Logger
83
+ readonly packageJson: Package
84
+ readonly config: NowConfig
85
+ readonly project: Project
86
+ readonly compiler: Compiler
87
+ readonly plugins: Plugins
88
+ readonly keys: Keys
89
+ readonly diagnostics: Diagnostics
90
+ readonly transform: Transform
91
+ readonly factory: Factory
92
+ readonly parser: Parser
93
+ }
@@ -0,0 +1,121 @@
1
+ import type { Record, RecordId } from './shape'
2
+
3
+ type Query = { [column: string]: unknown }
4
+
5
+ export class Database implements Iterable<Record> {
6
+ private readonly database: { [table: string]: { [guid: string]: Record } } = {}
7
+
8
+ constructor(records: Record[] = []) {
9
+ this.insert(...records)
10
+ }
11
+
12
+ insert(...records: Record[]): void {
13
+ for (const record of records) {
14
+ const table = (this.database[record.getTable()] ??= {})
15
+ const guid = record.getId().getValue()
16
+ table[guid] = record
17
+ }
18
+ }
19
+
20
+ resolve(id: RecordId): Record | undefined {
21
+ const table = id.getTable()
22
+ const guid = id.getValue()
23
+
24
+ const record = this.database[table]?.[guid]
25
+ if (record) {
26
+ return record
27
+ }
28
+
29
+ const keys = id.getKeys()
30
+ if (!keys) {
31
+ return undefined
32
+ }
33
+
34
+ const matches = this.query(table, keys)
35
+ if (matches.length > 1) {
36
+ throw new Error(`Multiple records found for table "${table}" with coalesce keys: ${JSON.stringify(keys)}`)
37
+ }
38
+
39
+ return matches[0]
40
+ }
41
+ get(table: string, guid: string): Record | undefined
42
+ get(table: string, query: Query): Record | undefined
43
+ get(table: string, guidOrQuery: string | Query): Record | undefined {
44
+ if (typeof guidOrQuery === 'string') {
45
+ return this.database[table]?.[guidOrQuery]
46
+ }
47
+
48
+ const [record, ...rest] = this.query(table, guidOrQuery)
49
+ if (rest.length > 0) {
50
+ throw new Error(`Expected get() to return no more than 1 match, but ${rest.length + 1} matches were found.`)
51
+ }
52
+
53
+ return record
54
+ }
55
+
56
+ query(table?: string, query: Query = {}): Record[] {
57
+ if (!table) {
58
+ return Object.values(this.database).flatMap((table) => Object.values(table))
59
+ }
60
+
61
+ const records: Record[] = []
62
+ outer: for (const record of Object.values(this.database[table] ?? {})) {
63
+ for (const [column, value] of Object.entries(query)) {
64
+ if (!record.get(column).equals(value)) {
65
+ continue outer
66
+ }
67
+ }
68
+
69
+ records.push(record)
70
+ }
71
+
72
+ return records
73
+ }
74
+
75
+ compare(other: Database | Record[]): DiffDatabase {
76
+ const diff = new DiffDatabase(this.query())
77
+ diff.insert(...(other instanceof Database ? other.query() : other))
78
+ return diff
79
+ }
80
+
81
+ [Symbol.iterator](): IterableIterator<Record> {
82
+ return this.query()[Symbol.iterator]()
83
+ }
84
+ }
85
+
86
+ /**
87
+ * The initial set of records passed into the constructor is treated as the baseline. Any record
88
+ * inserted after that will be tracked as "changed" unless it is equal to its baseline counterpart.
89
+ * Useful for getting a diff/delta between two databases.
90
+ */
91
+ export class DiffDatabase extends Database {
92
+ private readonly changedGuids: string[] = []
93
+
94
+ constructor(records: Record[] = []) {
95
+ super(records)
96
+ }
97
+
98
+ override insert(...records: Record[]): void {
99
+ if (!this.changedGuids) {
100
+ // This will happen when called from the super constructor
101
+ super.insert(...records)
102
+ return
103
+ }
104
+
105
+ for (const record of records) {
106
+ const id = record.getId()
107
+ const existing = this.resolve(id)
108
+ if (existing && !existing.strictEquals(record)) {
109
+ this.changedGuids.push(id.getValue())
110
+ super.insert(existing.merge(record))
111
+ } else if (!existing) {
112
+ this.changedGuids.push(id.getValue())
113
+ super.insert(record)
114
+ }
115
+ }
116
+ }
117
+
118
+ isChanged(record: Record): boolean {
119
+ return this.changedGuids.includes(record.getId().getValue())
120
+ }
121
+ }
@@ -0,0 +1,19 @@
1
+ export type File = {
2
+ path: string
3
+ content: string
4
+ }
5
+
6
+ export type InstallCategory =
7
+ | 'dictionary'
8
+ | 'unload'
9
+ | 'unload.demo'
10
+ | 'update'
11
+ | 'apply_once'
12
+ | 'scope'
13
+ | 'author_elective_update'
14
+
15
+ export type OutputFile = {
16
+ name: string
17
+ category: InstallCategory
18
+ content: string
19
+ }
@@ -1,5 +1,9 @@
1
- export { Plugin } from './Plugin'
2
- export { type Context, type HandledStates, type HandledInfo } from './Context'
3
- export * from './behaviors'
4
- export * from './util'
5
- export * from './Diagnostic'
1
+ export * from './shape'
2
+ export * from './file'
3
+ export * from './context'
4
+ export * from './plugin'
5
+ export * from './product'
6
+ export * from './project'
7
+ export * from './database'
8
+ export * from './time'
9
+ export * from './usage'