@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.
- package/dist/app.d.ts +25 -0
- package/dist/app.js +8 -0
- package/dist/app.js.map +1 -0
- package/dist/compiler.d.ts +60 -0
- package/dist/compiler.js +320 -0
- package/dist/compiler.js.map +1 -0
- package/dist/compression.d.ts +7 -0
- package/dist/compression.js +79 -0
- package/dist/compression.js.map +1 -0
- package/dist/crypto.d.ts +1 -0
- package/dist/crypto.js +9 -0
- package/dist/crypto.js.map +1 -0
- package/dist/diagnostic.d.ts +41 -0
- package/dist/diagnostic.js +130 -0
- package/dist/diagnostic.js.map +1 -0
- package/dist/{plugins/Diagnostic.d.ts → fluent-diagnostic.d.ts} +3 -2
- package/dist/fluent-diagnostic.js +23 -0
- package/dist/fluent-diagnostic.js.map +1 -0
- package/dist/fluent-directive.d.ts +8 -0
- package/dist/fluent-directive.js +54 -0
- package/dist/fluent-directive.js.map +1 -0
- package/dist/fluent-file.d.ts +5 -0
- package/dist/fluent-file.js +15 -0
- package/dist/fluent-file.js.map +1 -0
- package/dist/formatter.d.ts +11 -0
- package/dist/formatter.js +77 -0
- package/dist/formatter.js.map +1 -0
- package/dist/fs.d.ts +174 -0
- package/dist/fs.js +313 -0
- package/dist/fs.js.map +1 -0
- package/dist/guid.d.ts +2 -0
- package/dist/{GUID.js → guid.js} +3 -6
- package/dist/guid.js.map +1 -0
- package/dist/index.d.ts +19 -5
- package/dist/index.js +19 -5
- package/dist/index.js.map +1 -1
- package/dist/json.d.ts +5 -0
- package/dist/json.js +43 -0
- package/dist/json.js.map +1 -0
- package/dist/keys-registry.d.ts +64 -0
- package/dist/keys-registry.js +339 -0
- package/dist/keys-registry.js.map +1 -0
- package/dist/logger.d.ts +8 -0
- package/dist/logger.js +17 -0
- package/dist/logger.js.map +1 -0
- package/dist/now-config.d.ts +348 -0
- package/dist/now-config.js +283 -0
- package/dist/now-config.js.map +1 -0
- package/dist/path.d.ts +3 -0
- package/dist/path.js +12 -0
- package/dist/path.js.map +1 -0
- package/dist/plugins/cache.d.ts +20 -0
- package/dist/plugins/cache.js +46 -0
- package/dist/plugins/cache.js.map +1 -0
- package/dist/plugins/context.d.ts +85 -0
- package/dist/plugins/{Context.js → context.js} +1 -1
- package/dist/plugins/context.js.map +1 -0
- package/dist/plugins/database.d.ts +27 -0
- package/dist/plugins/database.js +102 -0
- package/dist/plugins/database.js.map +1 -0
- package/dist/plugins/file.d.ts +10 -0
- package/dist/plugins/{behaviors/Arranger.js → file.js} +1 -1
- package/dist/plugins/file.js.map +1 -0
- package/dist/plugins/index.d.ts +9 -5
- package/dist/plugins/index.js +9 -6
- package/dist/plugins/index.js.map +1 -1
- package/dist/plugins/plugin.d.ts +478 -0
- package/dist/plugins/plugin.js +533 -0
- package/dist/plugins/plugin.js.map +1 -0
- package/dist/plugins/product.d.ts +15 -0
- package/dist/plugins/product.js +38 -0
- package/dist/plugins/product.js.map +1 -0
- package/dist/plugins/project.d.ts +25 -0
- package/dist/plugins/{behaviors/Generator.js → project.js} +1 -1
- package/dist/plugins/project.js.map +1 -0
- package/dist/plugins/shape.d.ts +424 -0
- package/dist/plugins/shape.js +1181 -0
- package/dist/plugins/shape.js.map +1 -0
- package/dist/plugins/time.d.ts +12 -0
- package/dist/plugins/time.js +84 -0
- package/dist/plugins/time.js.map +1 -0
- package/dist/plugins/usage.d.ts +11 -0
- package/dist/plugins/usage.js +26 -0
- package/dist/plugins/usage.js.map +1 -0
- package/dist/prettier/config-loader.d.ts +13 -0
- package/dist/prettier/config-loader.js +105 -0
- package/dist/prettier/config-loader.js.map +1 -0
- package/dist/telemetry/index.d.ts +25 -0
- package/dist/telemetry/index.js +18 -0
- package/dist/telemetry/index.js.map +1 -0
- package/dist/typescript.d.ts +293 -0
- package/dist/typescript.js +454 -0
- package/dist/typescript.js.map +1 -0
- package/dist/util/get-file-type.d.ts +2 -0
- package/dist/util/get-file-type.js +13 -0
- package/dist/util/get-file-type.js.map +1 -0
- package/dist/util/index.d.ts +2 -6
- package/dist/util/index.js +2 -6
- package/dist/util/index.js.map +1 -1
- package/dist/util/{Scope.js → is-sn-scope.js} +1 -1
- package/dist/util/is-sn-scope.js.map +1 -0
- package/dist/xml.d.ts +24 -0
- package/dist/xml.js +71 -0
- package/dist/xml.js.map +1 -0
- package/now.config.schema.json +336 -0
- package/package.json +22 -12
- package/src/app.ts +33 -0
- package/src/compiler.ts +384 -0
- package/src/compression.ts +93 -0
- package/src/crypto.ts +5 -0
- package/src/diagnostic.ts +108 -0
- package/src/{plugins/Diagnostic.ts → fluent-diagnostic.ts} +3 -10
- package/src/fluent-directive.ts +63 -0
- package/src/fluent-file.ts +13 -0
- package/src/formatter.ts +58 -0
- package/src/fs.ts +438 -0
- package/src/{GUID.ts → guid.ts} +2 -6
- package/src/index.ts +19 -5
- package/src/json.ts +20 -0
- package/src/keys-registry.ts +384 -0
- package/src/logger.ts +20 -0
- package/src/now-config.ts +337 -0
- package/src/path.ts +9 -0
- package/src/plugins/cache.ts +45 -0
- package/src/plugins/context.ts +93 -0
- package/src/plugins/database.ts +121 -0
- package/src/plugins/file.ts +19 -0
- package/src/plugins/index.ts +9 -5
- package/src/plugins/plugin.ts +995 -0
- package/src/plugins/product.ts +44 -0
- package/src/plugins/project.ts +39 -0
- package/src/plugins/shape.ts +1532 -0
- package/src/plugins/time.ts +108 -0
- package/src/plugins/usage.ts +26 -0
- package/src/prettier/config-loader.ts +130 -0
- package/src/telemetry/index.ts +27 -0
- package/src/typescript.ts +502 -0
- package/src/util/get-file-type.ts +11 -0
- package/src/util/index.ts +2 -6
- package/src/xml.ts +86 -0
- package/dist/GUID.d.ts +0 -2
- package/dist/GUID.js.map +0 -1
- package/dist/IncludePaths.d.ts +0 -25
- package/dist/IncludePaths.js +0 -97
- package/dist/IncludePaths.js.map +0 -1
- package/dist/Keys.d.ts +0 -32
- package/dist/Keys.js +0 -245
- package/dist/Keys.js.map +0 -1
- package/dist/TypeScript.d.ts +0 -5
- package/dist/TypeScript.js +0 -58
- package/dist/TypeScript.js.map +0 -1
- package/dist/XML.d.ts +0 -32
- package/dist/XML.js +0 -77
- package/dist/XML.js.map +0 -1
- package/dist/plugins/Context.d.ts +0 -190
- package/dist/plugins/Context.js.map +0 -1
- package/dist/plugins/Diagnostic.js +0 -28
- package/dist/plugins/Diagnostic.js.map +0 -1
- package/dist/plugins/Plugin.d.ts +0 -175
- package/dist/plugins/Plugin.js +0 -15
- package/dist/plugins/Plugin.js.map +0 -1
- package/dist/plugins/behaviors/Arranger.d.ts +0 -26
- package/dist/plugins/behaviors/Arranger.js.map +0 -1
- package/dist/plugins/behaviors/Composer.d.ts +0 -102
- package/dist/plugins/behaviors/Composer.js +0 -15
- package/dist/plugins/behaviors/Composer.js.map +0 -1
- package/dist/plugins/behaviors/Diagnostics.d.ts +0 -7
- package/dist/plugins/behaviors/Diagnostics.js +0 -3
- package/dist/plugins/behaviors/Diagnostics.js.map +0 -1
- package/dist/plugins/behaviors/Generator.d.ts +0 -21
- package/dist/plugins/behaviors/Generator.js.map +0 -1
- package/dist/plugins/behaviors/OwnedTables.d.ts +0 -6
- package/dist/plugins/behaviors/OwnedTables.js +0 -3
- package/dist/plugins/behaviors/OwnedTables.js.map +0 -1
- package/dist/plugins/behaviors/PostProcessor.d.ts +0 -5
- package/dist/plugins/behaviors/PostProcessor.js +0 -3
- package/dist/plugins/behaviors/PostProcessor.js.map +0 -1
- package/dist/plugins/behaviors/Serializer.d.ts +0 -30
- package/dist/plugins/behaviors/Serializer.js +0 -3
- package/dist/plugins/behaviors/Serializer.js.map +0 -1
- package/dist/plugins/behaviors/Transformer.d.ts +0 -23
- package/dist/plugins/behaviors/Transformer.js +0 -3
- package/dist/plugins/behaviors/Transformer.js.map +0 -1
- package/dist/plugins/behaviors/extractors/Data.d.ts +0 -119
- package/dist/plugins/behaviors/extractors/Data.js +0 -244
- package/dist/plugins/behaviors/extractors/Data.js.map +0 -1
- package/dist/plugins/behaviors/extractors/Extractors.d.ts +0 -63
- package/dist/plugins/behaviors/extractors/Extractors.js +0 -3
- package/dist/plugins/behaviors/extractors/Extractors.js.map +0 -1
- package/dist/plugins/behaviors/extractors/index.d.ts +0 -2
- package/dist/plugins/behaviors/extractors/index.js +0 -19
- package/dist/plugins/behaviors/extractors/index.js.map +0 -1
- package/dist/plugins/behaviors/index.d.ts +0 -9
- package/dist/plugins/behaviors/index.js +0 -26
- package/dist/plugins/behaviors/index.js.map +0 -1
- package/dist/plugins/util/CallExpression.d.ts +0 -5
- package/dist/plugins/util/CallExpression.js +0 -88
- package/dist/plugins/util/CallExpression.js.map +0 -1
- package/dist/plugins/util/CodeTransformation.d.ts +0 -95
- package/dist/plugins/util/CodeTransformation.js +0 -624
- package/dist/plugins/util/CodeTransformation.js.map +0 -1
- package/dist/plugins/util/ObjectLiteral.d.ts +0 -9
- package/dist/plugins/util/ObjectLiteral.js +0 -37
- package/dist/plugins/util/ObjectLiteral.js.map +0 -1
- package/dist/plugins/util/index.d.ts +0 -3
- package/dist/plugins/util/index.js +0 -20
- package/dist/plugins/util/index.js.map +0 -1
- package/dist/util/Debug.d.ts +0 -4
- package/dist/util/Debug.js +0 -20
- package/dist/util/Debug.js.map +0 -1
- package/dist/util/Directive.d.ts +0 -16
- package/dist/util/Directive.js +0 -107
- package/dist/util/Directive.js.map +0 -1
- package/dist/util/RuntimeTableSchema.d.ts +0 -5
- package/dist/util/RuntimeTableSchema.js +0 -58
- package/dist/util/RuntimeTableSchema.js.map +0 -1
- package/dist/util/Scope.js.map +0 -1
- package/dist/util/Util.d.ts +0 -1
- package/dist/util/Util.js +0 -12
- package/dist/util/Util.js.map +0 -1
- package/dist/util/XMLUploadParser.d.ts +0 -22
- package/dist/util/XMLUploadParser.js +0 -67
- package/dist/util/XMLUploadParser.js.map +0 -1
- package/src/IncludePaths.ts +0 -122
- package/src/Keys.ts +0 -274
- package/src/TypeScript.ts +0 -65
- package/src/XML.ts +0 -92
- package/src/plugins/Context.ts +0 -239
- package/src/plugins/Plugin.ts +0 -278
- package/src/plugins/behaviors/Arranger.ts +0 -42
- package/src/plugins/behaviors/Composer.ts +0 -125
- package/src/plugins/behaviors/Diagnostics.ts +0 -12
- package/src/plugins/behaviors/Generator.ts +0 -31
- package/src/plugins/behaviors/OwnedTables.ts +0 -5
- package/src/plugins/behaviors/PostProcessor.ts +0 -6
- package/src/plugins/behaviors/Serializer.ts +0 -40
- package/src/plugins/behaviors/Transformer.ts +0 -32
- package/src/plugins/behaviors/extractors/Data.ts +0 -332
- package/src/plugins/behaviors/extractors/Extractors.ts +0 -73
- package/src/plugins/behaviors/extractors/index.ts +0 -2
- package/src/plugins/behaviors/index.ts +0 -9
- package/src/plugins/util/CallExpression.ts +0 -110
- package/src/plugins/util/CodeTransformation.ts +0 -731
- package/src/plugins/util/ObjectLiteral.ts +0 -37
- package/src/plugins/util/index.ts +0 -3
- package/src/util/Debug.ts +0 -24
- package/src/util/Directive.ts +0 -123
- package/src/util/RuntimeTableSchema.ts +0 -44
- package/src/util/Util.ts +0 -7
- package/src/util/XMLUploadParser.ts +0 -90
- /package/dist/util/{Scope.d.ts → is-sn-scope.d.ts} +0 -0
- /package/src/util/{Scope.ts → is-sn-scope.ts} +0 -0
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
import { path } from './path'
|
|
2
|
+
import { ts, parseType } from './typescript'
|
|
3
|
+
import type { App } from './app'
|
|
4
|
+
import type { Compiler } from './compiler'
|
|
5
|
+
import { GUID, isGUID } from './guid'
|
|
6
|
+
import * as z from 'zod'
|
|
7
|
+
import type { CoalesceKeys } from './plugins'
|
|
8
|
+
import { JSON5 } from './json'
|
|
9
|
+
import { Formatter } from './formatter'
|
|
10
|
+
import type { FileSystem } from './fs'
|
|
11
|
+
|
|
12
|
+
export const KEYS_MODULE = '@servicenow/sdk/global'
|
|
13
|
+
export const KEYS_FILE_NAME = 'keys.ts'
|
|
14
|
+
|
|
15
|
+
const NestedCoalesceKeysSchema: z.ZodType<Now.Internal.KeysRegistry['composite'][number]['key']> = z.lazy(() =>
|
|
16
|
+
z.record(
|
|
17
|
+
z.string().or(
|
|
18
|
+
z.object({
|
|
19
|
+
id: z.string(),
|
|
20
|
+
key: NestedCoalesceKeysSchema,
|
|
21
|
+
})
|
|
22
|
+
)
|
|
23
|
+
)
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
const CompositeKeySchema = z.object({
|
|
27
|
+
table: z.string(),
|
|
28
|
+
id: z.string(),
|
|
29
|
+
deleted: z.boolean().optional(),
|
|
30
|
+
key: NestedCoalesceKeysSchema,
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
const KeysSchema = z.object({
|
|
34
|
+
explicit: z
|
|
35
|
+
.record(
|
|
36
|
+
z.string().or(z.number()),
|
|
37
|
+
z.object({
|
|
38
|
+
table: z.string(),
|
|
39
|
+
id: z.string(),
|
|
40
|
+
deleted: z.boolean().optional(),
|
|
41
|
+
})
|
|
42
|
+
)
|
|
43
|
+
.default({}),
|
|
44
|
+
composite: z.array(CompositeKeySchema).default([]),
|
|
45
|
+
deleted: z.record(z.string(), z.array(z.string())).default({}),
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
export class KeysRegistry {
|
|
49
|
+
private readonly formatter: Formatter
|
|
50
|
+
private readonly file: ts.SourceFile
|
|
51
|
+
private readonly usedIds: Set<string> = new Set()
|
|
52
|
+
private registry: Now.Internal.KeysRegistry
|
|
53
|
+
|
|
54
|
+
constructor(compiler: Compiler, project: App, fs: FileSystem) {
|
|
55
|
+
this.formatter = new Formatter(fs)
|
|
56
|
+
const keysFilePath = path.resolve(project.rootDir, project.config.generatedDir, KEYS_FILE_NAME)
|
|
57
|
+
const existingFile = compiler.addSourceFileAtPathIfExists(keysFilePath)
|
|
58
|
+
|
|
59
|
+
if (existingFile) {
|
|
60
|
+
this.registry = KeysRegistry.parseKeysFile(existingFile)
|
|
61
|
+
this.file = existingFile
|
|
62
|
+
} else {
|
|
63
|
+
this.registry = KeysSchema.parse({})
|
|
64
|
+
this.file = compiler.createSourceFile(keysFilePath, KeysRegistry.getCode({}), {
|
|
65
|
+
overwrite: true,
|
|
66
|
+
scriptKind: ts.ScriptKind.TS,
|
|
67
|
+
})
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
static parseKeysFile(keysFile: ts.SourceFile): Now.Internal.KeysRegistry {
|
|
72
|
+
const keysInterface = KeysRegistry.getKeysInterface(keysFile)
|
|
73
|
+
const parsedType = parseType(keysInterface.getType(), keysInterface, (unparsableType) => {
|
|
74
|
+
if (unparsableType.isArray()) {
|
|
75
|
+
return [] // If the keys file doesn't have composite keys, it will be an unparsable array so just return an empty one
|
|
76
|
+
} else {
|
|
77
|
+
throw `Unparsable type in keys.ts: ${unparsableType.getText()}`
|
|
78
|
+
}
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
const result = KeysSchema.safeParse(parsedType)
|
|
82
|
+
if (!result.success) {
|
|
83
|
+
throw new Error(`Keys registry is malformed: ${JSON5.stringify(result.error.format(), { space: 4 })}`)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return result.data
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
private static getKeysInterface(keysFile: ts.SourceFile) {
|
|
90
|
+
return keysFile
|
|
91
|
+
.getModuleOrThrow('global')
|
|
92
|
+
.getModuleOrThrow('Now')
|
|
93
|
+
.getModuleOrThrow('Internal')
|
|
94
|
+
.getInterfaceOrThrow('Keys')
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
private use<const K extends Now.Internal.ExplicitKey | Now.Internal.CompositeKey>(key: K): K {
|
|
98
|
+
if (key.deleted) {
|
|
99
|
+
key.deleted = false // If it was previously registered as deleted, reverse it
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
this.usedIds.add(key.id)
|
|
103
|
+
return key
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
getSourceFile(): ts.SourceFile {
|
|
107
|
+
return this.file
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
private queryExplicitKey(table: string, key: string | number): Now.Internal.ExplicitKey | undefined {
|
|
111
|
+
const existing = this.registry.explicit[key]
|
|
112
|
+
return existing?.table === table ? existing : undefined
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
queryExplicitId(table: string, key: string | number): string | undefined {
|
|
116
|
+
return this.queryExplicitKey(table, key)?.id
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
private registerExplicitKey(table: string, key: string | number, guidOverride?: string): Now.Internal.ExplicitKey {
|
|
120
|
+
const existing = this.queryExplicitKey(table, key)
|
|
121
|
+
if (existing) {
|
|
122
|
+
return this.use(existing)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
let id: string
|
|
126
|
+
if (guidOverride) {
|
|
127
|
+
id = guidOverride
|
|
128
|
+
} else if (typeof key === 'string' && isGUID(key)) {
|
|
129
|
+
id = key
|
|
130
|
+
} else {
|
|
131
|
+
id = GUID()
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const newKey = { table, id }
|
|
135
|
+
this.registry.explicit[key] = newKey
|
|
136
|
+
return this.use(newKey)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
registerExplicitId(table: string, key: string | number, guidOverride?: string): string {
|
|
140
|
+
return this.registerExplicitKey(table, key, guidOverride).id
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
private deleteExplicitKey(table: string, key: string | number, guidOverride?: string): Now.Internal.ExplicitKey {
|
|
144
|
+
const registeredKey = this.registerExplicitKey(table, key, guidOverride)
|
|
145
|
+
registeredKey.deleted = true
|
|
146
|
+
return registeredKey
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
deleteExplicitId(table: string, key: string | number, guidOverride?: string): string {
|
|
150
|
+
return this.deleteExplicitKey(table, key, guidOverride).id
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
private queryCompositeKey(
|
|
154
|
+
table: string,
|
|
155
|
+
query: CoalesceKeys,
|
|
156
|
+
guid?: string
|
|
157
|
+
): Now.Internal.CompositeKey | undefined {
|
|
158
|
+
const serializedQuery = this.serializeCoalesceKeys(query)
|
|
159
|
+
return this.registry.composite.find(
|
|
160
|
+
(existing) =>
|
|
161
|
+
existing.table === table &&
|
|
162
|
+
(existing.id === guid || this.coalesceKeysAreEqual(existing.key, serializedQuery, table))
|
|
163
|
+
)
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
queryCompositeId(table: string, query: CoalesceKeys): string | undefined {
|
|
167
|
+
return this.queryCompositeKey(table, query)?.id
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
private registerCompositeKey(table: string, key: CoalesceKeys, guidOverride?: string): Now.Internal.CompositeKey {
|
|
171
|
+
const existing = this.queryCompositeKey(table, key, guidOverride)
|
|
172
|
+
if (existing) {
|
|
173
|
+
return this.use(existing)
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const newKey = {
|
|
177
|
+
table,
|
|
178
|
+
id: guidOverride ?? GUID(),
|
|
179
|
+
key: this.serializeCoalesceKeys(key),
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const registry = (this.registry.composite ??= [])
|
|
183
|
+
registry.push(newKey)
|
|
184
|
+
return this.use(newKey)
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
registerCompositeId(table: string, key: CoalesceKeys, guidOverride?: string): string {
|
|
188
|
+
return this.registerCompositeKey(table, key, guidOverride).id
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
private deleteCompositeKey(table: string, key: CoalesceKeys, guidOverride?: string): Now.Internal.CompositeKey {
|
|
192
|
+
const registeredKey = this.registerCompositeKey(table, key, guidOverride)
|
|
193
|
+
registeredKey.deleted = true
|
|
194
|
+
return registeredKey
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
deleteCompositeId(table: string, key: CoalesceKeys, guidOverride?: string): string {
|
|
198
|
+
return this.deleteCompositeKey(table, key, guidOverride).id
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
private serializeCoalesceKeys(keys: CoalesceKeys): Now.Internal.KeysRegistry['composite'][number]['key'] {
|
|
202
|
+
if (Object.keys(keys).length <= 0) {
|
|
203
|
+
throw new Error('Coalesce keys object is empty.')
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
return Object.fromEntries(
|
|
207
|
+
Object.entries(keys).map(([k, v]) => {
|
|
208
|
+
if (!v) {
|
|
209
|
+
return [k, 'NULL'] // Nullish or empty values should be represented as "NULL" to be consistent with how the platform handles coalesce strategies
|
|
210
|
+
} else if (typeof v === 'string') {
|
|
211
|
+
return [k, v]
|
|
212
|
+
} else {
|
|
213
|
+
const nestedKeys = v.getKeys()
|
|
214
|
+
if (nestedKeys) {
|
|
215
|
+
return [k, { id: v.getValue(), key: this.serializeCoalesceKeys(nestedKeys) }]
|
|
216
|
+
} else {
|
|
217
|
+
return [k, v.getValue()]
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
})
|
|
221
|
+
)
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Checks if the coalesce keys from `left` are equal to those specified in `right`. If there
|
|
226
|
+
* are keys in `left` that aren't present in `right`, they are ignored. However, if there are
|
|
227
|
+
* keys in `right` that aren't present in `left`, the two are considered NOT equal.
|
|
228
|
+
*
|
|
229
|
+
* If any nested coalesce keys are present on either side, they are considered equal when any
|
|
230
|
+
* ONE of the following conditions are met:
|
|
231
|
+
*
|
|
232
|
+
* A) One of the values is a string that matches the nested key's ID
|
|
233
|
+
*
|
|
234
|
+
* { id: '123', key: { k: 'v' } } == '123' }
|
|
235
|
+
*
|
|
236
|
+
* B) Both values are nested keys with matching IDs
|
|
237
|
+
*
|
|
238
|
+
* { id: '123', key: { k: 'v' } } == { id: '123', key: { ... } }
|
|
239
|
+
*
|
|
240
|
+
* C) Both values are nested keys with matching coalesce values
|
|
241
|
+
*
|
|
242
|
+
* { id: '123', key: { k: 'v' } } == { id: '456', key: { k: 'v' } }
|
|
243
|
+
*
|
|
244
|
+
* For condition C, the nested keys are compared recursively, so if they contain any of their
|
|
245
|
+
* own nested keys, they will be compared in the same way.
|
|
246
|
+
*/
|
|
247
|
+
private coalesceKeysAreEqual(
|
|
248
|
+
leftOrig: Now.Internal.KeysRegistry['composite'][number]['key'],
|
|
249
|
+
rightOrig: Now.Internal.KeysRegistry['composite'][number]['key'],
|
|
250
|
+
table?: string
|
|
251
|
+
): boolean {
|
|
252
|
+
const left = table ? this.mapLegacyKeys(leftOrig, table) : leftOrig
|
|
253
|
+
const right = table ? this.mapLegacyKeys(rightOrig, table) : rightOrig
|
|
254
|
+
for (const [k, rightValue] of Object.entries(right)) {
|
|
255
|
+
const match = () => {
|
|
256
|
+
const leftValue = left[k]
|
|
257
|
+
switch (typeof leftValue) {
|
|
258
|
+
case 'string': {
|
|
259
|
+
// Left is a plain value or ID
|
|
260
|
+
const newLeft = this.queryExplicitId(k, leftValue) ?? leftValue // query if we have a legacy explicit ID and use that sys_Id if found
|
|
261
|
+
return typeof rightValue === 'string'
|
|
262
|
+
? newLeft === rightValue // Right is the same plain value or ID
|
|
263
|
+
: newLeft === rightValue.id // Right is a nested key with the same ID
|
|
264
|
+
}
|
|
265
|
+
case 'object': // Left is a nested key
|
|
266
|
+
return typeof rightValue === 'string'
|
|
267
|
+
? leftValue.id === rightValue // Right is the same ID
|
|
268
|
+
: leftValue.id === rightValue.id || // Right is a nested key with the same ID
|
|
269
|
+
this.coalesceKeysAreEqual(leftValue.key, rightValue.key) // Right is a nested key with matching coalesce values
|
|
270
|
+
default:
|
|
271
|
+
return false
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
if (!match()) {
|
|
276
|
+
return false // Give up as soon as we find any mismatch
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
return true // All keys matched
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
mapLegacyKeys(obj: NonNullable<object>, table?: string) {
|
|
284
|
+
// Copy to avoid messing up future iterations
|
|
285
|
+
const newObj = Object.assign({}, obj)
|
|
286
|
+
|
|
287
|
+
// Map old and new values to the table name in case we need to query explicit IDs
|
|
288
|
+
const legacyKeyMap = {
|
|
289
|
+
list: 'sys_ui_list',
|
|
290
|
+
list_id: 'sys_ui_list',
|
|
291
|
+
route: 'sys_ws_operation',
|
|
292
|
+
web_service_operation: 'sys_ws_operation',
|
|
293
|
+
web_service_header: 'sys_ws_header',
|
|
294
|
+
attr: table === 'sys_ws_query_parameter_map' ? 'sys_ws_query_parameter' : 'sys_ws_header', // attr maps to a different table depending on the type of record
|
|
295
|
+
web_service_query_parameter: 'sys_ws_query_parameter',
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// Legacy key equivalence for comparison
|
|
299
|
+
Object.entries(newObj).forEach(([key, value]) => {
|
|
300
|
+
if (legacyKeyMap[key]) {
|
|
301
|
+
newObj[legacyKeyMap[key]] = value
|
|
302
|
+
delete newObj[key]
|
|
303
|
+
}
|
|
304
|
+
})
|
|
305
|
+
if (newObj['rest']) {
|
|
306
|
+
delete newObj['rest']
|
|
307
|
+
}
|
|
308
|
+
return newObj
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
getEffectiveExplicitKeys(): Now.Internal.KeysRegistry['explicit'] {
|
|
312
|
+
return Object.fromEntries(
|
|
313
|
+
Object.entries(this.registry.explicit)
|
|
314
|
+
.sort(([a], [b]) => a.localeCompare(b))
|
|
315
|
+
.filter(([, v]) => !this.registry.composite.some((k) => k.table === v.table && k.id === v.id)) // Filter out any explicit IDs that became coalescing IDs later
|
|
316
|
+
.map(([k, v]) => [k, this.usedIds.has(v.id) ? v : { ...v, deleted: true }])
|
|
317
|
+
)
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
getEffectiveCompositeKeys(): Now.Internal.KeysRegistry['composite'] {
|
|
321
|
+
return this.registry.composite
|
|
322
|
+
.sort((a, b) => a.id.localeCompare(b.id))
|
|
323
|
+
.map((v) =>
|
|
324
|
+
this.usedIds.has(v.id)
|
|
325
|
+
? 'deleted' in v
|
|
326
|
+
? // Seems silly but this is to make sure the position of the "delete" prop is consistent
|
|
327
|
+
{ table: v.table, id: v.id, deleted: v.deleted, key: v.key }
|
|
328
|
+
: v
|
|
329
|
+
: { table: v.table, id: v.id, deleted: true, key: v.key }
|
|
330
|
+
)
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
getEffectiveDeletedKeys(): Now.Internal.AnyKey[] {
|
|
334
|
+
const explicit = Object.values(this.getEffectiveExplicitKeys()).filter((k) => k.deleted)
|
|
335
|
+
const composite = this.getEffectiveCompositeKeys().filter((k) => k.deleted)
|
|
336
|
+
const deleted = Object.entries(this.registry.deleted).flatMap(([table, keys]) =>
|
|
337
|
+
keys.map((id) => ({ table, id }))
|
|
338
|
+
)
|
|
339
|
+
|
|
340
|
+
return [...explicit, ...composite, ...deleted].sort((a, b) => a.id.localeCompare(b.id))
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
async commit(formatter: Formatter = this.formatter): Promise<void> {
|
|
344
|
+
const explicit = this.getEffectiveExplicitKeys()
|
|
345
|
+
const composite = this.getEffectiveCompositeKeys()
|
|
346
|
+
const deleted = this.registry.deleted
|
|
347
|
+
|
|
348
|
+
const registry: Partial<Now.Internal.KeysRegistry> = {
|
|
349
|
+
...(Object.keys(explicit).length > 0 ? { explicit } : {}),
|
|
350
|
+
...(composite.length > 0 ? { composite } : {}),
|
|
351
|
+
...(Object.keys(deleted).length > 0 ? { deleted } : {}),
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
const formatted = await formatter.format(KeysRegistry.getCode(registry), this.file.getFilePath())
|
|
355
|
+
this.file.replaceText([this.file.getPos(), this.file.getEnd()], formatted)
|
|
356
|
+
this.registry = KeysRegistry.parseKeysFile(this.file)
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
private static getCode(registry: Partial<Now.Internal.KeysRegistry>): string {
|
|
360
|
+
return `import '${KEYS_MODULE}'
|
|
361
|
+
|
|
362
|
+
declare global {
|
|
363
|
+
namespace Now {
|
|
364
|
+
namespace Internal {
|
|
365
|
+
interface Keys extends KeysRegistry ${JSON5.stringify(registry, { space: 4 })}
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
`
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
reload(): void {
|
|
373
|
+
this.registry = KeysRegistry.parseKeysFile(this.file)
|
|
374
|
+
this.usedIds.clear()
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
getValue(): Now.Internal.KeysRegistry {
|
|
378
|
+
return {
|
|
379
|
+
explicit: this.registry.explicit,
|
|
380
|
+
composite: this.registry.composite,
|
|
381
|
+
deleted: this.registry.deleted,
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}
|
package/src/logger.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export type Logger = {
|
|
2
|
+
info: (...data: any[]) => void
|
|
3
|
+
warn: (...data: any[]) => void
|
|
4
|
+
error: (...data: any[]) => void
|
|
5
|
+
debug: (...data: any[]) => void
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
// TODO: This is not needed, get rid of it
|
|
9
|
+
export function createConsoleLogger(): Logger {
|
|
10
|
+
return console
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function createSilentLogger(): Logger {
|
|
14
|
+
return {
|
|
15
|
+
info: () => {},
|
|
16
|
+
warn: () => {},
|
|
17
|
+
error: () => {},
|
|
18
|
+
debug: () => {},
|
|
19
|
+
}
|
|
20
|
+
}
|