@servicenow/sdk-build-core 4.6.0 → 4.7.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/compiler.d.ts +2 -0
- package/dist/compiler.js +13 -7
- package/dist/compiler.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/now-config.d.ts +51 -3
- package/dist/now-config.js +44 -1
- package/dist/now-config.js.map +1 -1
- package/dist/package-inventory.d.ts +15 -0
- package/dist/package-inventory.js +59 -0
- package/dist/package-inventory.js.map +1 -0
- package/dist/plugins/context.d.ts +2 -2
- package/dist/plugins/file.d.ts +1 -0
- package/dist/plugins/index.d.ts +0 -1
- package/dist/plugins/index.js +0 -1
- package/dist/plugins/index.js.map +1 -1
- package/dist/plugins/plugin.d.ts +41 -53
- package/dist/plugins/plugin.js +517 -162
- package/dist/plugins/plugin.js.map +1 -1
- package/dist/plugins/shape.d.ts +13 -2
- package/dist/plugins/shape.js +96 -15
- package/dist/plugins/shape.js.map +1 -1
- package/dist/taxonomy.js +7 -2
- package/dist/taxonomy.js.map +1 -1
- package/dist/telemetry/clients/detect-agent.d.ts +4 -0
- package/dist/telemetry/clients/detect-agent.js +84 -0
- package/dist/telemetry/clients/detect-agent.js.map +1 -0
- package/dist/telemetry/clients/node-client.d.ts +2 -0
- package/dist/telemetry/clients/node-client.js +10 -9
- package/dist/telemetry/clients/node-client.js.map +1 -1
- package/dist/telemetry/index.d.ts +1 -1
- package/dist/xml.d.ts +2 -2
- package/dist/xml.js +2 -2
- package/dist/xml.js.map +1 -1
- package/now.config.schema.json +54 -0
- package/package.json +9 -5
- package/src/compiler.ts +14 -7
- package/src/index.ts +1 -0
- package/src/now-config.ts +56 -1
- package/src/package-inventory.ts +75 -0
- package/src/plugins/context.ts +2 -2
- package/src/plugins/file.ts +1 -0
- package/src/plugins/index.ts +0 -1
- package/src/plugins/plugin.ts +704 -231
- package/src/plugins/shape.ts +115 -24
- package/src/taxonomy.ts +8 -2
- package/src/telemetry/clients/detect-agent.ts +88 -0
- package/src/telemetry/clients/node-client.ts +12 -8
- package/src/telemetry/index.ts +1 -1
- package/src/xml.ts +11 -2
- package/dist/plugins/cache.d.ts +0 -15
- package/dist/plugins/cache.js +0 -22
- package/dist/plugins/cache.js.map +0 -1
- package/dist/plugins/usage.d.ts +0 -11
- package/dist/plugins/usage.js +0 -26
- package/dist/plugins/usage.js.map +0 -1
- package/src/plugins/cache.ts +0 -23
- package/src/plugins/usage.ts +0 -26
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@servicenow/sdk-build-core",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.7.0",
|
|
4
4
|
"description": "ServiceNow SDK Build System Core Libraries",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -10,7 +10,11 @@
|
|
|
10
10
|
"now.config.schema.json"
|
|
11
11
|
],
|
|
12
12
|
"exports": {
|
|
13
|
-
".": "./dist/index.js"
|
|
13
|
+
".": "./dist/index.js",
|
|
14
|
+
"./telemetry": {
|
|
15
|
+
"types": "./dist/telemetry/index.d.ts",
|
|
16
|
+
"default": "./dist/telemetry/index.js"
|
|
17
|
+
}
|
|
14
18
|
},
|
|
15
19
|
"dependencies": {
|
|
16
20
|
"ci-info": "4.4.0",
|
|
@@ -18,7 +22,7 @@
|
|
|
18
22
|
"fflate": "0.8.2",
|
|
19
23
|
"json5": "2.2.3",
|
|
20
24
|
"jsonschema": "1.5.0",
|
|
21
|
-
"lodash": "4.
|
|
25
|
+
"lodash": "4.18.1",
|
|
22
26
|
"pathe": "1.1.2",
|
|
23
27
|
"prettier": "3.6.1",
|
|
24
28
|
"readable-stream": "4.5.2",
|
|
@@ -27,7 +31,7 @@
|
|
|
27
31
|
"xml-js": "1.6.11",
|
|
28
32
|
"xmlbuilder2": "3.1.1",
|
|
29
33
|
"zod": "3.23.8",
|
|
30
|
-
"@servicenow/sdk-core": "4.
|
|
34
|
+
"@servicenow/sdk-core": "4.7.0"
|
|
31
35
|
},
|
|
32
36
|
"overrides": {
|
|
33
37
|
"micromatch": "4.0.7"
|
|
@@ -47,6 +51,6 @@
|
|
|
47
51
|
"bundle:production": "tsc -b && tsx esbuild.config.ts",
|
|
48
52
|
"clean": "tsc -b --clean",
|
|
49
53
|
"watch": "tsc -b -w",
|
|
50
|
-
"test": "export NODE_OPTIONS=\"--max-old-space-size=8192 --experimental-vm-modules\" && jest --colors --
|
|
54
|
+
"test": "export NODE_OPTIONS=\"--max-old-space-size=8192 --experimental-vm-modules\" && jest --colors --no-cache --logHeapUsage"
|
|
51
55
|
}
|
|
52
56
|
}
|
package/src/compiler.ts
CHANGED
|
@@ -40,6 +40,7 @@ export class Compiler extends ts.Project {
|
|
|
40
40
|
private readonly rootDir: string
|
|
41
41
|
private readonly sourceFileToRelativeModuleSpecifier: Record<string, string> = {}
|
|
42
42
|
private readonly generatedTableFilePath: string
|
|
43
|
+
private readonly generatedBootstrappedTablesFilePath: string
|
|
43
44
|
private moduleProject: ts.Project | undefined
|
|
44
45
|
|
|
45
46
|
constructor(
|
|
@@ -63,6 +64,7 @@ export class Compiler extends ts.Project {
|
|
|
63
64
|
|
|
64
65
|
this.rootDir = rootDir
|
|
65
66
|
this.generatedTableFilePath = path.join(this.rootDir, '$$GENERATED$$_common_table.ts')
|
|
67
|
+
this.generatedBootstrappedTablesFilePath = path.join(this.rootDir, '$$GENERATED$$_bootstrapped_tables.ts')
|
|
66
68
|
this.addGlobalTableDefinitionFile()
|
|
67
69
|
if (typesDir) {
|
|
68
70
|
this.addTypesTableDeclaration(typesDir)
|
|
@@ -89,7 +91,7 @@ export class Compiler extends ts.Project {
|
|
|
89
91
|
}
|
|
90
92
|
|
|
91
93
|
addGlobalTableDefinitionFile() {
|
|
92
|
-
const
|
|
94
|
+
const tableDefinitionContent = `
|
|
93
95
|
import '@servicenow/sdk/global'
|
|
94
96
|
import { Table } from '@servicenow/sdk/core'
|
|
95
97
|
|
|
@@ -105,10 +107,18 @@ declare global {
|
|
|
105
107
|
}
|
|
106
108
|
}
|
|
107
109
|
`
|
|
108
|
-
this.createSourceFile(this.generatedTableFilePath,
|
|
110
|
+
this.createSourceFile(this.generatedTableFilePath, tableDefinitionContent, {
|
|
109
111
|
overwrite: true,
|
|
110
112
|
scriptKind: ts.ScriptKind.TS,
|
|
111
113
|
})
|
|
114
|
+
this.createSourceFile(this.generatedBootstrappedTablesFilePath, tableDefinitionContent, {
|
|
115
|
+
overwrite: true,
|
|
116
|
+
scriptKind: ts.ScriptKind.TS,
|
|
117
|
+
})
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
getGeneratedBootstrappedTablesFile(): ts.SourceFile | undefined {
|
|
121
|
+
return this.getSourceFile(this.generatedBootstrappedTablesFilePath)
|
|
112
122
|
}
|
|
113
123
|
|
|
114
124
|
/**
|
|
@@ -332,16 +342,15 @@ declare module '*.html' {
|
|
|
332
342
|
return this.generatedTableFilePath === sourcePath
|
|
333
343
|
}
|
|
334
344
|
|
|
335
|
-
// Cache for table column types that need coercion (boolean/number only)
|
|
345
|
+
// Cache for table column types that need coercion (boolean/number only).
|
|
346
|
+
// Populated on first call to getTableColumnTypes(); subsequent calls return immediately.
|
|
336
347
|
private tableColumnTypesCache = new Map<string, Map<string, 'boolean' | 'number' | 'array' | 'array-optional'>>()
|
|
337
348
|
|
|
338
349
|
getTableColumnTypes(tableName: string): Map<string, 'boolean' | 'number' | 'array' | 'array-optional'> | undefined {
|
|
339
|
-
// Return cached value if available
|
|
340
350
|
if (this.tableColumnTypesCache.has(tableName)) {
|
|
341
351
|
return this.tableColumnTypesCache.get(tableName)
|
|
342
352
|
}
|
|
343
353
|
|
|
344
|
-
// Lazily resolve and cache on first access
|
|
345
354
|
const tempFilePath = path.join(this.rootDir, 'src', '$$TEMP_DATA_RESOLVER$$.ts')
|
|
346
355
|
const typeDeclaration = `type T = import('@servicenow/sdk/core').Data<'${tableName}'>`
|
|
347
356
|
|
|
@@ -367,10 +376,8 @@ declare module '*.html' {
|
|
|
367
376
|
if (typeText === 'boolean' || typeText === 'number') {
|
|
368
377
|
columnTypes.set(property.getName(), typeText)
|
|
369
378
|
} else if (typeText.match(/^\(.*\)\[\]$/)) {
|
|
370
|
-
// Matches `(...)[]` -> this field should always be an array
|
|
371
379
|
columnTypes.set(property.getName(), 'array')
|
|
372
380
|
} else if (typeText.match(/^.*\[\]$/)) {
|
|
373
|
-
// Matches `[]` -> this field may be an array or a single value
|
|
374
381
|
columnTypes.set(property.getName(), 'array-optional')
|
|
375
382
|
}
|
|
376
383
|
})
|
package/src/index.ts
CHANGED
package/src/now-config.ts
CHANGED
|
@@ -9,6 +9,7 @@ import { Compiler } from './compiler'
|
|
|
9
9
|
import { GUID } from './guid'
|
|
10
10
|
import { taxonomy } from './taxonomy'
|
|
11
11
|
import { dependenciesSchema } from './now-config-dependencies'
|
|
12
|
+
import { isSNScope } from './util'
|
|
12
13
|
|
|
13
14
|
export type NowConfig = z.output<typeof NowConfigSchema>
|
|
14
15
|
export type NowConfigOptions = z.input<typeof NowConfigSchema>
|
|
@@ -135,6 +136,15 @@ const NetworkPolicySchema = z
|
|
|
135
136
|
|
|
136
137
|
export type NetworkPolicy = z.infer<typeof NetworkPolicySchema>
|
|
137
138
|
|
|
139
|
+
/**
|
|
140
|
+
* Schema for Linter configuration options
|
|
141
|
+
*/
|
|
142
|
+
const LinterSchema = z
|
|
143
|
+
.object({
|
|
144
|
+
module: z.object({ enabled: z.boolean().default(true) }),
|
|
145
|
+
})
|
|
146
|
+
.default({ module: { enabled: true } })
|
|
147
|
+
|
|
138
148
|
/**
|
|
139
149
|
* Network Pillar Schema for Wildcard Policy
|
|
140
150
|
*/
|
|
@@ -247,7 +257,8 @@ const NowConfigSchema = z
|
|
|
247
257
|
trustedModules: z.array(z.string()).default([]),
|
|
248
258
|
tsconfigPath: z.string().optional(),
|
|
249
259
|
scripts: z.record(z.string(), z.string()).default({}),
|
|
250
|
-
|
|
260
|
+
linter: LinterSchema,
|
|
261
|
+
tableOutputFormat: z.enum(['bootstrap', 'component']).default('bootstrap').optional(),
|
|
251
262
|
defaultLanguage: z
|
|
252
263
|
.string()
|
|
253
264
|
.regex(/^[a-z]{2,3}(-[a-zA-Z0-9]{2,8})*$/)
|
|
@@ -296,6 +307,7 @@ const NowConfigSchema = z
|
|
|
296
307
|
packageResolverVersion: z.string().optional(),
|
|
297
308
|
type: z.enum(['configuration', 'package']).default('package'),
|
|
298
309
|
taxonomy,
|
|
310
|
+
hostedPlugins: z.record(z.string(), z.string()).optional(),
|
|
299
311
|
|
|
300
312
|
// Application Runtime Policy (ARP) fields
|
|
301
313
|
applicationRuntimePolicy: z.enum(['none', 'tracking', 'enforcing']).default('none'),
|
|
@@ -332,12 +344,14 @@ const NowConfigSchema = z
|
|
|
332
344
|
| 'description'
|
|
333
345
|
| 'installedAsDependency'
|
|
334
346
|
| 'scripts'
|
|
347
|
+
| 'linter'
|
|
335
348
|
| 'tableOutputFormat'
|
|
336
349
|
| 'defaultLanguage'
|
|
337
350
|
| 'tableDefaultLanguage'
|
|
338
351
|
| 'packageResolverVersion'
|
|
339
352
|
| 'type'
|
|
340
353
|
| 'taxonomy'
|
|
354
|
+
| 'hostedPlugins'
|
|
341
355
|
| 'applicationRuntimePolicy'
|
|
342
356
|
| 'networkPolicies'
|
|
343
357
|
| 'wildcardPolicy'
|
|
@@ -491,6 +505,46 @@ export namespace NowConfig {
|
|
|
491
505
|
|
|
492
506
|
return true
|
|
493
507
|
}
|
|
508
|
+
|
|
509
|
+
export function getRecordScope(config: NowConfig, filePath: string): { scope?: string; scopeId: string } {
|
|
510
|
+
if (!isSNScope(config.scope) || !config.hostedPlugins) {
|
|
511
|
+
return { scope: config.scope, scopeId: config.scopeId }
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
const matchingDir = Object.keys(config.hostedPlugins).find((pluginDirectory) =>
|
|
515
|
+
filePath.includes(path.join(config.fluentDir, 'hosted_plugins', pluginDirectory))
|
|
516
|
+
)
|
|
517
|
+
if (!matchingDir) {
|
|
518
|
+
return { scope: config.scope, scopeId: config.scopeId }
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
return { scopeId: config.hostedPlugins[matchingDir]! }
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
export function getHostedDirectory(config: NowConfig, filePath: string): string | undefined {
|
|
525
|
+
if (!isSNScope(config.scope) || !config.hostedPlugins) {
|
|
526
|
+
return
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
const normalizedPath = path.normalize(filePath)
|
|
530
|
+
const match = Object.keys(config.hostedPlugins).find((pluginDirectory) =>
|
|
531
|
+
normalizedPath.includes(path.join('hosted_plugins', pluginDirectory))
|
|
532
|
+
)
|
|
533
|
+
if (!match) {
|
|
534
|
+
return
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
return path.join('hosted_plugins', match)
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
export function getConditionalDirectory(config: NowConfig, filePath: string): string | undefined {
|
|
541
|
+
if (!isSNScope(config.scope)) {
|
|
542
|
+
return
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
const match = filePath.match(/[/\\]if[/\\][^/\\]+/)
|
|
546
|
+
return match ? match[0] : undefined
|
|
547
|
+
}
|
|
494
548
|
}
|
|
495
549
|
|
|
496
550
|
const NOW_CONFIG_SCHEMA = require('../now.config.schema.json')
|
|
@@ -576,6 +630,7 @@ const DEPRECATED_FIELDS: Record<string, DeprecatedField> = {
|
|
|
576
630
|
transpiledSourceDir: { replacedBy: 'modulePaths' },
|
|
577
631
|
sourceDir: {},
|
|
578
632
|
tableDefaultLanguage: { replacedBy: 'defaultLanguage', transfer: true },
|
|
633
|
+
tableOutputFormat: {},
|
|
579
634
|
}
|
|
580
635
|
|
|
581
636
|
function replaceDeprecatedFields(config: Record<string, unknown>, logger: Logger) {
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { crypto } from './crypto'
|
|
2
|
+
import { FileSystem } from './fs'
|
|
3
|
+
import { path } from './path'
|
|
4
|
+
|
|
5
|
+
export interface PackageInventoryConfig {
|
|
6
|
+
build: string
|
|
7
|
+
type: 'scoped' | 'global'
|
|
8
|
+
appVersion: string
|
|
9
|
+
version?: string
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Generate SHA-256 hash for file content (matches ServiceNow's package_inventory.csv format)
|
|
14
|
+
*/
|
|
15
|
+
export async function sha256(content: string | Uint8Array): Promise<string> {
|
|
16
|
+
const data = typeof content === 'string' ? new TextEncoder().encode(content) : content
|
|
17
|
+
const hashBuffer = await crypto.subtle.digest('SHA-256', data)
|
|
18
|
+
const hashArray = Array.from(new Uint8Array(hashBuffer))
|
|
19
|
+
return hashArray.map((b) => b.toString(16).padStart(2, '0')).join('')
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Recursively find all files in a directory
|
|
24
|
+
*/
|
|
25
|
+
function findAllFiles(fs: FileSystem, dir: string, baseDir: string): string[] {
|
|
26
|
+
const files: string[] = []
|
|
27
|
+
|
|
28
|
+
if (!FileSystem.existsSync(fs, dir)) {
|
|
29
|
+
return files
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
33
|
+
const fullPath = path.join(dir, entry.name)
|
|
34
|
+
if (entry.isDirectory()) {
|
|
35
|
+
files.push(...findAllFiles(fs, fullPath, baseDir))
|
|
36
|
+
} else {
|
|
37
|
+
files.push(path.relative(baseDir, fullPath))
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return files
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Generate package_inventory.csv from files in a directory on disk (for pack command)
|
|
46
|
+
*/
|
|
47
|
+
export async function generatePackageInventoryFromDirectory(
|
|
48
|
+
fs: FileSystem,
|
|
49
|
+
appOutputDir: string,
|
|
50
|
+
config: PackageInventoryConfig
|
|
51
|
+
): Promise<string> {
|
|
52
|
+
const headerLines: string[] = [
|
|
53
|
+
`#build=${config.build}`,
|
|
54
|
+
`#appVersion=${config.appVersion}`,
|
|
55
|
+
`#type=${config.type}`,
|
|
56
|
+
`#version=${config.version ?? '1.0.0'}`,
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
// Find all files in directory
|
|
60
|
+
const filePaths = findAllFiles(fs, appOutputDir, appOutputDir)
|
|
61
|
+
.filter((f) => !f.endsWith('package_inventory.csv'))
|
|
62
|
+
.sort()
|
|
63
|
+
|
|
64
|
+
// Hash all files in parallel for better performance
|
|
65
|
+
const hashResults = await Promise.all(
|
|
66
|
+
filePaths.map(async (relativePath) => {
|
|
67
|
+
const fullPath = path.join(appOutputDir, relativePath)
|
|
68
|
+
const content = fs.readFileSync(fullPath)
|
|
69
|
+
const hash = await sha256(content)
|
|
70
|
+
return `${relativePath};${hash}`
|
|
71
|
+
})
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
return `${[...headerLines, ...hashResults].join('\n')}\n`
|
|
75
|
+
}
|
package/src/plugins/context.ts
CHANGED
|
@@ -43,12 +43,12 @@ export interface Diagnostics {
|
|
|
43
43
|
|
|
44
44
|
export interface Transform {
|
|
45
45
|
toShape(node: ts.Node, ...plugins: Plugin[]): Promise<Result<Shape>>
|
|
46
|
-
|
|
47
|
-
toSubclass<const S extends Shape>(shape: S, ...plugins: Plugin[]): Promise<Result<S>>
|
|
46
|
+
toSubclass<const S extends Shape>(shape: S, ...plugins: Plugin[]): Promise<S>
|
|
48
47
|
toRecord(node: ts.Node, ...plugins: Plugin[]): Promise<Result<Record>>
|
|
49
48
|
toRecord(shape: Shape, ...plugins: Plugin[]): Promise<Result<Record>>
|
|
50
49
|
toRecord(file: File, ...plugins: Plugin[]): Promise<Result<Record>>
|
|
51
50
|
toRecord(source: ts.Node | Shape | File, ...plugins: Plugin[]): Promise<Result<Record>>
|
|
51
|
+
recordToShape(record: Record, database: Database, ...plugins: Plugin[]): Promise<Result<Shape>>
|
|
52
52
|
getUpdateName(record: Record, ...plugins: Plugin[]): Promise<string>
|
|
53
53
|
}
|
|
54
54
|
|
package/src/plugins/file.ts
CHANGED