@servicenow/sdk-build-core 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/BuildOptions.d.ts +50 -0
- package/dist/BuildOptions.js +46 -0
- package/dist/BuildOptions.js.map +1 -0
- package/dist/GUID.d.ts +2 -0
- package/dist/GUID.js +48 -0
- package/dist/GUID.js.map +1 -0
- package/dist/Keys.d.ts +29 -0
- package/dist/Keys.js +258 -0
- package/dist/Keys.js.map +1 -0
- package/dist/TypeScript.d.ts +5 -0
- package/dist/TypeScript.js +81 -0
- package/dist/TypeScript.js.map +1 -0
- package/dist/XML.d.ts +25 -0
- package/dist/XML.js +72 -0
- package/dist/XML.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +38 -0
- package/dist/index.js.map +1 -0
- package/dist/plugins/Context.d.ts +198 -0
- package/dist/plugins/Context.js +3 -0
- package/dist/plugins/Context.js.map +1 -0
- package/dist/plugins/Diagnostic.d.ts +10 -0
- package/dist/plugins/Diagnostic.js +52 -0
- package/dist/plugins/Diagnostic.js.map +1 -0
- package/dist/plugins/Plugin.d.ts +175 -0
- package/dist/plugins/Plugin.js +15 -0
- package/dist/plugins/Plugin.js.map +1 -0
- package/dist/plugins/behaviors/Arranger.d.ts +26 -0
- package/dist/plugins/behaviors/Arranger.js +3 -0
- package/dist/plugins/behaviors/Arranger.js.map +1 -0
- package/dist/plugins/behaviors/Composer.d.ts +101 -0
- package/dist/plugins/behaviors/Composer.js +15 -0
- package/dist/plugins/behaviors/Composer.js.map +1 -0
- package/dist/plugins/behaviors/Diagnostics.d.ts +8 -0
- package/dist/plugins/behaviors/Diagnostics.js +3 -0
- package/dist/plugins/behaviors/Diagnostics.js.map +1 -0
- package/dist/plugins/behaviors/Generator.d.ts +21 -0
- package/dist/plugins/behaviors/Generator.js +3 -0
- package/dist/plugins/behaviors/Generator.js.map +1 -0
- package/dist/plugins/behaviors/OwnedTables.d.ts +6 -0
- package/dist/plugins/behaviors/OwnedTables.js +3 -0
- package/dist/plugins/behaviors/OwnedTables.js.map +1 -0
- package/dist/plugins/behaviors/PostProcessor.d.ts +5 -0
- package/dist/plugins/behaviors/PostProcessor.js +3 -0
- package/dist/plugins/behaviors/PostProcessor.js.map +1 -0
- package/dist/plugins/behaviors/Serializer.d.ts +29 -0
- package/dist/plugins/behaviors/Serializer.js +3 -0
- package/dist/plugins/behaviors/Serializer.js.map +1 -0
- package/dist/plugins/behaviors/Transformer.d.ts +23 -0
- package/dist/plugins/behaviors/Transformer.js +3 -0
- package/dist/plugins/behaviors/Transformer.js.map +1 -0
- package/dist/plugins/behaviors/extractors/Data.d.ts +107 -0
- package/dist/plugins/behaviors/extractors/Data.js +191 -0
- package/dist/plugins/behaviors/extractors/Data.js.map +1 -0
- package/dist/plugins/behaviors/extractors/Extractors.d.ts +41 -0
- package/dist/plugins/behaviors/extractors/Extractors.js +3 -0
- package/dist/plugins/behaviors/extractors/Extractors.js.map +1 -0
- package/dist/plugins/behaviors/extractors/index.d.ts +2 -0
- package/dist/plugins/behaviors/extractors/index.js +19 -0
- package/dist/plugins/behaviors/extractors/index.js.map +1 -0
- package/dist/plugins/behaviors/index.d.ts +9 -0
- package/dist/plugins/behaviors/index.js +26 -0
- package/dist/plugins/behaviors/index.js.map +1 -0
- package/dist/plugins/index.d.ts +5 -0
- package/dist/plugins/index.js +23 -0
- package/dist/plugins/index.js.map +1 -0
- package/dist/plugins/util/CallExpression.d.ts +6 -0
- package/dist/plugins/util/CallExpression.js +93 -0
- package/dist/plugins/util/CallExpression.js.map +1 -0
- package/dist/plugins/util/CodeTransformation.d.ts +74 -0
- package/dist/plugins/util/CodeTransformation.js +421 -0
- package/dist/plugins/util/CodeTransformation.js.map +1 -0
- package/dist/plugins/util/ConfigurationFunction.d.ts +106 -0
- package/dist/plugins/util/ConfigurationFunction.js +377 -0
- package/dist/plugins/util/ConfigurationFunction.js.map +1 -0
- package/dist/plugins/util/ObjectLiteral.d.ts +9 -0
- package/dist/plugins/util/ObjectLiteral.js +60 -0
- package/dist/plugins/util/ObjectLiteral.js.map +1 -0
- package/dist/plugins/util/index.d.ts +4 -0
- package/dist/plugins/util/index.js +21 -0
- package/dist/plugins/util/index.js.map +1 -0
- package/dist/util/Debug.d.ts +8 -0
- package/dist/util/Debug.js +39 -0
- package/dist/util/Debug.js.map +1 -0
- package/dist/util/Util.d.ts +4 -0
- package/dist/util/Util.js +41 -0
- package/dist/util/Util.js.map +1 -0
- package/dist/util/XMLJsonBuilder.d.ts +18 -0
- package/dist/util/XMLJsonBuilder.js +59 -0
- package/dist/util/XMLJsonBuilder.js.map +1 -0
- package/dist/util/XMLUploadParser.d.ts +22 -0
- package/dist/util/XMLUploadParser.js +67 -0
- package/dist/util/XMLUploadParser.js.map +1 -0
- package/dist/util/index.d.ts +4 -0
- package/dist/util/index.js +21 -0
- package/dist/util/index.js.map +1 -0
- package/license +9 -0
- package/package.json +42 -0
- package/src/BuildOptions.ts +27 -0
- package/src/GUID.ts +26 -0
- package/src/Keys.ts +287 -0
- package/src/TypeScript.ts +65 -0
- package/src/XML.ts +85 -0
- package/src/index.ts +8 -0
- package/src/plugins/Context.ts +249 -0
- package/src/plugins/Diagnostic.ts +31 -0
- package/src/plugins/Plugin.ts +246 -0
- package/src/plugins/behaviors/Arranger.ts +42 -0
- package/src/plugins/behaviors/Composer.ts +124 -0
- package/src/plugins/behaviors/Diagnostics.ts +13 -0
- package/src/plugins/behaviors/Generator.ts +31 -0
- package/src/plugins/behaviors/OwnedTables.ts +5 -0
- package/src/plugins/behaviors/PostProcessor.ts +6 -0
- package/src/plugins/behaviors/Serializer.ts +39 -0
- package/src/plugins/behaviors/Transformer.ts +32 -0
- package/src/plugins/behaviors/extractors/Data.ts +247 -0
- package/src/plugins/behaviors/extractors/Extractors.ts +57 -0
- package/src/plugins/behaviors/extractors/index.ts +2 -0
- package/src/plugins/behaviors/index.ts +9 -0
- package/src/plugins/index.ts +5 -0
- package/src/plugins/util/CallExpression.ts +83 -0
- package/src/plugins/util/CodeTransformation.ts +500 -0
- package/src/plugins/util/ConfigurationFunction.ts +477 -0
- package/src/plugins/util/ObjectLiteral.ts +37 -0
- package/src/plugins/util/index.ts +4 -0
- package/src/util/Debug.ts +46 -0
- package/src/util/Util.ts +21 -0
- package/src/util/XMLJsonBuilder.ts +64 -0
- package/src/util/XMLUploadParser.ts +90 -0
- package/src/util/index.ts +4 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Document, DocumentPointer, LinkedDocument } from './Composer'
|
|
2
|
+
import { Context } from '../Context'
|
|
3
|
+
|
|
4
|
+
export type Arranged<Status extends 'unresolved' | 'resolved' = 'resolved'> = {
|
|
5
|
+
parent?: Status extends 'unresolved' ? DocumentPointer & Arranged<'unresolved'> : LinkedDocument & Arranged // Parent is always linked because document trees are processed from top to bottom
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
// TODO: Use this return type for all behaviors. It solves the ambiguity
|
|
9
|
+
// between `undefined` as a valid return value and `undefined` as an indicator
|
|
10
|
+
// that the input was not handled.
|
|
11
|
+
export type Result<T> =
|
|
12
|
+
| {
|
|
13
|
+
handled: false
|
|
14
|
+
result?: never
|
|
15
|
+
}
|
|
16
|
+
| {
|
|
17
|
+
handled: true
|
|
18
|
+
result: T
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* An arranger function is a function which accepts a document of a known
|
|
23
|
+
* kind as input and returns a pointer to its parent, if applicable.
|
|
24
|
+
*
|
|
25
|
+
* @see {@linkcode Document}
|
|
26
|
+
* @see {@linkcode DocumentPointer}
|
|
27
|
+
*/
|
|
28
|
+
export type ArrangerFunction<DocumentKind extends string = string> = (
|
|
29
|
+
document: Document<DocumentKind>,
|
|
30
|
+
context: Context
|
|
31
|
+
) => Result<DocumentPointer | undefined>
|
|
32
|
+
|
|
33
|
+
// This is only imported so it can be referenced in the JS doc below
|
|
34
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
35
|
+
import type { Plugin } from '../Plugin'
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @see {@linkcode Plugin#arrangers}
|
|
39
|
+
*/
|
|
40
|
+
export type Arrangers<DocumentKinds extends string = string> = {
|
|
41
|
+
[K in DocumentKinds]: ArrangerFunction<K>
|
|
42
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { SupportedNode } from '@servicenow/sdk-project'
|
|
2
|
+
import { XmlData, PrimitiveData, Action, EntityData } from './extractors'
|
|
3
|
+
import { Context } from '../Context'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* An unlinked document is a document that does not have an
|
|
7
|
+
* association with any AST node.
|
|
8
|
+
*
|
|
9
|
+
* @see {@linkcode Document}
|
|
10
|
+
*/
|
|
11
|
+
export type UnlinkedDocument<DocumentKind extends string = string> = Omit<Document<DocumentKind>, 'node'>
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* A linked document is a document that has an association
|
|
15
|
+
* with an AST node.
|
|
16
|
+
*
|
|
17
|
+
* @see {@linkcode Document}
|
|
18
|
+
*/
|
|
19
|
+
export type LinkedDocument<DocumentKind extends string = string, Node extends SupportedNode = SupportedNode> = Document<
|
|
20
|
+
DocumentKind,
|
|
21
|
+
Node
|
|
22
|
+
> & {
|
|
23
|
+
entity?: EntityData
|
|
24
|
+
node: Node
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* A document is a data structure that has a known kind, an ID,
|
|
29
|
+
* and an action (insert/update or delete). It may also have an
|
|
30
|
+
* associated AST node if the data originated from source code.
|
|
31
|
+
*
|
|
32
|
+
* @see {@linkcode LinkedDocument}
|
|
33
|
+
* @see {@linkcode UnlinkedDocument}
|
|
34
|
+
*/
|
|
35
|
+
export type Document<DocumentKind extends string = string, Node extends SupportedNode = SupportedNode> = {
|
|
36
|
+
guid: string
|
|
37
|
+
kind: DocumentKind
|
|
38
|
+
data: unknown
|
|
39
|
+
changedData?: unknown
|
|
40
|
+
xmlData?: unknown
|
|
41
|
+
node?: Node
|
|
42
|
+
action?: Action
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* A document pointer is an object that represents a document
|
|
47
|
+
* via its ID and kind. Document pointers can be resolved to
|
|
48
|
+
* actual documents after all documents have been composed.
|
|
49
|
+
*
|
|
50
|
+
* @see {@linkcode Document}
|
|
51
|
+
*/
|
|
52
|
+
export type DocumentPointer<DocumentKind extends string = string> = {
|
|
53
|
+
guid: string
|
|
54
|
+
kind: DocumentKind
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* A document map is an object where documents are accessible
|
|
59
|
+
* by their kind and ID. The keys of the object are document
|
|
60
|
+
* kinds, and the values are sub-objects where the keys are
|
|
61
|
+
* document IDs and the values are the corresponding documents.
|
|
62
|
+
*
|
|
63
|
+
* @see {@linkcode Document}
|
|
64
|
+
*/
|
|
65
|
+
export type DocumentMap = {
|
|
66
|
+
[kinds: string]: {
|
|
67
|
+
[guids: string]: Document
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* An entity composer function is a function that accepts a
|
|
73
|
+
* piece of entity data from the source code and returns one
|
|
74
|
+
* or more linked documents derived from that entity, or returns
|
|
75
|
+
* undefined to indicate that it did not handle the data.
|
|
76
|
+
*
|
|
77
|
+
* @see {@linkcode Entity}
|
|
78
|
+
* @see {@linkcode EntityData}
|
|
79
|
+
*/
|
|
80
|
+
export type EntityComposerFunction<Data extends Record<string, unknown> = Record<string, unknown>> = (
|
|
81
|
+
entityData: EntityData<Data>,
|
|
82
|
+
context: Context
|
|
83
|
+
) => LinkedDocument | LinkedDocument[] | undefined
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* An XML composer function is a function that accepts a piece
|
|
87
|
+
* of data from an XML file and returns one or more unlinked
|
|
88
|
+
* documents derived from that data, or returns undefined to
|
|
89
|
+
* indicate that it did not handle the data.
|
|
90
|
+
*
|
|
91
|
+
* @see {@linkcode PrimitiveData}
|
|
92
|
+
* @see {@linkcode XmlData}
|
|
93
|
+
*/
|
|
94
|
+
export type XmlComposerFunction<Data extends PrimitiveData = PrimitiveData> = (
|
|
95
|
+
xmlData: XmlData<Data>,
|
|
96
|
+
context: Context
|
|
97
|
+
) => UnlinkedDocument | UnlinkedDocument[] | undefined
|
|
98
|
+
|
|
99
|
+
// This is only imported so it can be referenced in the JS doc below
|
|
100
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
101
|
+
import type { Plugin } from '../Plugin'
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* @see {@linkcode Plugin#composers}
|
|
105
|
+
*/
|
|
106
|
+
export type Composers = {
|
|
107
|
+
entity?: { [kind: string]: EntityComposerFunction }
|
|
108
|
+
xml?: { [kind: string]: XmlComposerFunction }
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Utility which takes an unlinked document and a node and returns the
|
|
113
|
+
* same document linked to the provided node.
|
|
114
|
+
*
|
|
115
|
+
* @param document The {@linkcode UnlinkedDocument} to link
|
|
116
|
+
* @param node The AST node to link the document to
|
|
117
|
+
* @returns A {@linkcode LinkedDocument}
|
|
118
|
+
*/
|
|
119
|
+
export function linkDocument<const K extends string, const N extends SupportedNode>(
|
|
120
|
+
document: UnlinkedDocument<K>,
|
|
121
|
+
node: N
|
|
122
|
+
): LinkedDocument<K, N> {
|
|
123
|
+
return { ...document, node }
|
|
124
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import * as ts from 'ts-morph'
|
|
2
|
+
import { SupportedKindName, SupportedNodeByKindName } from '@servicenow/sdk-project'
|
|
3
|
+
import { Context } from '../Context'
|
|
4
|
+
import { FluentDiagnostic } from '../Diagnostic'
|
|
5
|
+
|
|
6
|
+
export type DiagnosticsFunction<K extends SupportedKindName | 'Node' = SupportedKindName> = (
|
|
7
|
+
node: K extends SupportedKindName ? SupportedNodeByKindName<K> : K extends 'Node' ? ts.Node : any,
|
|
8
|
+
context: Context
|
|
9
|
+
) => FluentDiagnostic[]
|
|
10
|
+
|
|
11
|
+
export type Diagnostics<NodeKinds extends SupportedKindName | 'Node'> = {
|
|
12
|
+
[K in NodeKinds]: DiagnosticsFunction<K>
|
|
13
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { LinkedDocument, UnlinkedDocument } from './Composer'
|
|
2
|
+
import { Arranged } from './Arranger'
|
|
3
|
+
import { Context } from '../Context'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* A generator function is a function that accepts an unlinked document of
|
|
7
|
+
* a known kind as input and returns the same document as a linked document.
|
|
8
|
+
* In practice, this means the generator's job is to create new AST nodes
|
|
9
|
+
* for documents that are not linked to any node. Documents without nodes
|
|
10
|
+
* are usually from XML files containing records that aren't defined in the
|
|
11
|
+
* source code yet.
|
|
12
|
+
*
|
|
13
|
+
* @see {@linkcode UnlinkedDocument}
|
|
14
|
+
* @see {@linkcode LinkedDocument}
|
|
15
|
+
*/
|
|
16
|
+
export type GeneratorFunction<DocumentKind extends string = string> = (
|
|
17
|
+
document: UnlinkedDocument<DocumentKind> & Arranged,
|
|
18
|
+
context: Context,
|
|
19
|
+
linkedDocuments: LinkedDocument[]
|
|
20
|
+
) => LinkedDocument<DocumentKind> | undefined
|
|
21
|
+
|
|
22
|
+
// This is only imported so it can be referenced in the JS doc below
|
|
23
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
24
|
+
import type { Plugin } from '../Plugin'
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @see {@linkcode Plugin#generators}
|
|
28
|
+
*/
|
|
29
|
+
export type Generators<DocumentKinds extends string = string> = {
|
|
30
|
+
[K in DocumentKinds]: GeneratorFunction<K>
|
|
31
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Document } from './Composer'
|
|
2
|
+
import { Arranged } from './Arranger'
|
|
3
|
+
import { Context } from '../Context'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* A file is a data structure with a name, a target directory, and content
|
|
7
|
+
* as a string. The target directory must be the name of one of the magic
|
|
8
|
+
* directories that exist within a ServiceNow deployable app package.
|
|
9
|
+
*/
|
|
10
|
+
export type File = {
|
|
11
|
+
name: `${string}.xml`
|
|
12
|
+
directory: 'dictionary' | 'unload' | 'unload.demo' | 'update' | 'apply_once' | ''
|
|
13
|
+
content: string
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* A serializer function is a function which accepts a document of a known
|
|
18
|
+
* kind as input and returns one or more files derived from that document,
|
|
19
|
+
* or returns undefined to indicate it did not handle the document. In practice,
|
|
20
|
+
* this means generating the XML content that the build system will write to
|
|
21
|
+
* the filesystem during the final stages of a build.
|
|
22
|
+
*
|
|
23
|
+
* @see {@linkcode Document}
|
|
24
|
+
*/
|
|
25
|
+
export type SerializerFunction<DocumentKind extends string = string> = (
|
|
26
|
+
document: Document<DocumentKind> & Arranged,
|
|
27
|
+
context: Context
|
|
28
|
+
) => File | File[] | undefined
|
|
29
|
+
|
|
30
|
+
// This is only imported so it can be referenced in the JS doc below
|
|
31
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
32
|
+
import type { Plugin } from '../Plugin'
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @see {@linkcode Plugin#serializers}
|
|
36
|
+
*/
|
|
37
|
+
export type Serializers<DocumentKinds extends string = string> = {
|
|
38
|
+
[K in DocumentKinds]: SerializerFunction<K>
|
|
39
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { SupportedKindName, SupportedNode, SupportedNodeByKindName } from '@servicenow/sdk-project'
|
|
2
|
+
import { LinkedDocument } from './Composer'
|
|
3
|
+
import { Arranged } from './Arranger'
|
|
4
|
+
import { Context } from '../Context'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* A transformer function is a function which accepts a linked document of
|
|
8
|
+
* a known kind as input and returns a boolean indicating whether or not it
|
|
9
|
+
* handled the document. The implementation of a transformer function, if it
|
|
10
|
+
* chooses to handle the document, should perform the necessary transformations
|
|
11
|
+
* on the document's linked node to ensure the document's data is fully
|
|
12
|
+
* represented in the source code.
|
|
13
|
+
*
|
|
14
|
+
* @see {@linkcode LinkedDocument}
|
|
15
|
+
*/
|
|
16
|
+
export type TransformerFunction<DocumentKind extends string = string, Node extends SupportedNode = SupportedNode> = (
|
|
17
|
+
document: LinkedDocument<DocumentKind, Node> & Arranged,
|
|
18
|
+
context: Context
|
|
19
|
+
) => boolean
|
|
20
|
+
|
|
21
|
+
// This is only imported so it can be referenced in the JS doc below
|
|
22
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
23
|
+
import type { Plugin } from '../Plugin'
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @see {@linkcode Plugin#transformers}
|
|
27
|
+
*/
|
|
28
|
+
export type Transformers<DocumentKinds extends string = string> = {
|
|
29
|
+
[DK in DocumentKinds]: {
|
|
30
|
+
[NK in SupportedKindName]?: TransformerFunction<DK, SupportedNodeByKindName<NK>>
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
import { SupportedNode } from '@servicenow/sdk-project'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Actions indicate what should take place in the database when the XML file
|
|
5
|
+
* is loaded. The platform understands these three actions: insert/update,
|
|
6
|
+
* delete, and delete multiple.
|
|
7
|
+
*/
|
|
8
|
+
export type Action = 'INSERT_OR_UPDATE' | 'DELETE' | 'delete_multiple'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Utility type for data passed to XML extractors for processing.
|
|
12
|
+
*/
|
|
13
|
+
export type Xml = {
|
|
14
|
+
filePath: string
|
|
15
|
+
data: any
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Utility type to represent a simple object structure with primitive values.
|
|
20
|
+
*/
|
|
21
|
+
export type PrimitiveData = {
|
|
22
|
+
[x: string]: PrimitiveData | PrimitiveData[] | string | number | boolean | undefined
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* XML data is data from XML files (such as the parsed content of a record_update)
|
|
27
|
+
* which is not associated with any AST node.
|
|
28
|
+
*/
|
|
29
|
+
export class XmlData<D extends PrimitiveData = PrimitiveData> {
|
|
30
|
+
constructor(
|
|
31
|
+
public data: D,
|
|
32
|
+
readonly filePath: string,
|
|
33
|
+
readonly kind: string,
|
|
34
|
+
readonly action: Action = 'INSERT_OR_UPDATE'
|
|
35
|
+
) {}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export type WrappedData<D> = {
|
|
39
|
+
[K in keyof D]: D[K] extends string
|
|
40
|
+
? StringData<D[K]>
|
|
41
|
+
: D[K] extends number
|
|
42
|
+
? NumberData<D[K]>
|
|
43
|
+
: D[K] extends boolean
|
|
44
|
+
? BooleanData<D[K]>
|
|
45
|
+
: D[K] extends Array<unknown>
|
|
46
|
+
? ArrayData<D[K]>
|
|
47
|
+
: D[K] extends Record<string, unknown>
|
|
48
|
+
? ObjectData<D[K]>
|
|
49
|
+
: Data<D[K]>
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export abstract class Data<D = unknown> {
|
|
53
|
+
constructor(private readonly node: SupportedNode) {}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* @deprecated Using this for an array or object is bad practice because all of the elements/properties
|
|
57
|
+
* will be assigned the same node as the array/object itself. This makes it difficult to bidrectionally
|
|
58
|
+
* sync data created this way because you don't have the granularity required to know where each of the
|
|
59
|
+
* element/property values (and any nested values) came from.
|
|
60
|
+
*/
|
|
61
|
+
static fromValue<const D>(value: D, node: SupportedNode): Data<D> {
|
|
62
|
+
if (value === undefined || value === null) {
|
|
63
|
+
return new UndefinedData(node) as Data<D> // TODO: How can we avoid this silly cast?
|
|
64
|
+
} else if (typeof value === 'string') {
|
|
65
|
+
return new StringData(value, node)
|
|
66
|
+
} else if (typeof value === 'number') {
|
|
67
|
+
return new NumberData(value, node)
|
|
68
|
+
} else if (typeof value === 'boolean') {
|
|
69
|
+
return new BooleanData(value, node)
|
|
70
|
+
} else if (Array.isArray(value)) {
|
|
71
|
+
return ArrayData.fromArrayValue(value, node)
|
|
72
|
+
} else if (!!value && typeof value === 'object') {
|
|
73
|
+
const obj = Object.fromEntries(Object.entries(value).filter(([key]) => typeof key === 'string'))
|
|
74
|
+
return ObjectData.fromObjectValue(obj as typeof obj & D, node)
|
|
75
|
+
} else {
|
|
76
|
+
throw new Error(
|
|
77
|
+
`Unsupported data type: ${value} (Type: ${typeof value}, Class: ${value?.constructor?.name})`
|
|
78
|
+
)
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
static isUndefined(data?: Data): data is UndefinedData {
|
|
83
|
+
return data instanceof UndefinedData
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
static isString(data?: Data): data is StringData {
|
|
87
|
+
return data instanceof StringData
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
static isNumber(data?: Data): data is NumberData {
|
|
91
|
+
return data instanceof NumberData
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
static isBoolean(data?: Data): data is BooleanData {
|
|
95
|
+
return data instanceof BooleanData
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
static isArray(data?: Data): data is ArrayData {
|
|
99
|
+
return data instanceof ArrayData
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
static isObject(data?: Data): data is ObjectData {
|
|
103
|
+
return data instanceof ObjectData
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
static isEntity(data?: Data): data is EntityData {
|
|
107
|
+
return data instanceof EntityData
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
abstract getValue(): D
|
|
111
|
+
|
|
112
|
+
getNode() {
|
|
113
|
+
return this.node
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export class UndefinedData extends Data<undefined> {
|
|
118
|
+
constructor(node: SupportedNode) {
|
|
119
|
+
super(node)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
getValue() {
|
|
123
|
+
return undefined
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export class StringData<const D extends string = string> extends Data<D> {
|
|
128
|
+
constructor(
|
|
129
|
+
private readonly value: D,
|
|
130
|
+
node: SupportedNode
|
|
131
|
+
) {
|
|
132
|
+
super(node)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
getValue() {
|
|
136
|
+
return this.value
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export class NumberData<const D extends number = number> extends Data<D> {
|
|
141
|
+
constructor(
|
|
142
|
+
private readonly value: D,
|
|
143
|
+
node: SupportedNode
|
|
144
|
+
) {
|
|
145
|
+
super(node)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
getValue() {
|
|
149
|
+
return this.value
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export class BooleanData<const D extends boolean = boolean> extends Data<D> {
|
|
154
|
+
constructor(
|
|
155
|
+
private readonly value: D,
|
|
156
|
+
node: SupportedNode
|
|
157
|
+
) {
|
|
158
|
+
super(node)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
getValue() {
|
|
162
|
+
return this.value
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export class ArrayData<const D extends unknown[] = unknown[]> extends Data<D> {
|
|
167
|
+
constructor(
|
|
168
|
+
private readonly elements: WrappedData<D>,
|
|
169
|
+
node: SupportedNode
|
|
170
|
+
) {
|
|
171
|
+
super(node)
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* @deprecated Using this for arrays is bad practice because all of the array elements will be
|
|
176
|
+
* assigned the same node as the array itself. This makes it difficult to bidrectionally sync
|
|
177
|
+
* data created this way because you don't have the granularity required to know where each of
|
|
178
|
+
* the element values (and any nested values) came from.
|
|
179
|
+
*/
|
|
180
|
+
static fromArrayValue<const D extends unknown[]>(value: D, node: SupportedNode): ArrayData<D> {
|
|
181
|
+
const elements = value.map((value) => Data.fromValue(value, node)) as WrappedData<D>
|
|
182
|
+
|
|
183
|
+
return new ArrayData(elements, node)
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
getValue() {
|
|
187
|
+
return this.elements.map((element) => element.getValue()) as D
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
getElements() {
|
|
191
|
+
return this.elements
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export class ObjectData<const D extends Record<string, unknown> = Record<string, unknown>> extends Data<D> {
|
|
196
|
+
constructor(
|
|
197
|
+
private readonly properties: WrappedData<D>,
|
|
198
|
+
node: SupportedNode
|
|
199
|
+
) {
|
|
200
|
+
super(node)
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* @deprecated Using this for objects is bad practice because all of the object properties will
|
|
205
|
+
* be assigned the same node as the object itself. This makes it difficult to bidrectionally sync
|
|
206
|
+
* data created this way because you don't have the granularity required to know where each of
|
|
207
|
+
* the property values (and any nested values) came from.
|
|
208
|
+
*/
|
|
209
|
+
static fromObjectValue<const D extends Record<string, unknown>>(value: D, node: SupportedNode): ObjectData<D> {
|
|
210
|
+
const properties = Object.fromEntries(
|
|
211
|
+
Object.entries(value).map(([key, value]) => [key, Data.fromValue(value, node)])
|
|
212
|
+
) as WrappedData<D>
|
|
213
|
+
|
|
214
|
+
return new ObjectData(properties, node)
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
getValue() {
|
|
218
|
+
return Object.fromEntries(Object.entries(this.properties).map(([key, value]) => [key, value.getValue()])) as D
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
getProperty<const K extends keyof D>(name: K) {
|
|
222
|
+
return this.properties[name]
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
getProperties() {
|
|
226
|
+
return this.properties
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export class EntityData<const D extends Record<string, unknown> = Record<string, unknown>> extends ObjectData<D> {
|
|
231
|
+
constructor(
|
|
232
|
+
private readonly kind: string,
|
|
233
|
+
private readonly guid: string,
|
|
234
|
+
entity: ObjectData<D>,
|
|
235
|
+
node: SupportedNode
|
|
236
|
+
) {
|
|
237
|
+
super(entity.getProperties(), node)
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
getKind() {
|
|
241
|
+
return this.kind
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
getGuid() {
|
|
245
|
+
return this.guid
|
|
246
|
+
}
|
|
247
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { SupportedKindName, SupportedNodeByKindName } from '@servicenow/sdk-project'
|
|
2
|
+
import { Data, EntityData, Xml, XmlData } from './Data'
|
|
3
|
+
import { Context } from '../../Context'
|
|
4
|
+
import { FluentDiagnostic } from '../../Diagnostic'
|
|
5
|
+
|
|
6
|
+
export type ExtractionResult<D extends Data = Data> =
|
|
7
|
+
| {
|
|
8
|
+
handled: false
|
|
9
|
+
}
|
|
10
|
+
| {
|
|
11
|
+
handled: true
|
|
12
|
+
data: D[]
|
|
13
|
+
diagnostics: FluentDiagnostic[]
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* An XML extractor function accepts an {@linkcode Xml} object and returns one or
|
|
18
|
+
* more pieces of {@linkcode XmlData} extracted from that object. The function may
|
|
19
|
+
* also return undefined to indicate that it did not handle the object.
|
|
20
|
+
*/
|
|
21
|
+
export type XmlExtractorFunction = (xml: Xml, context: Context) => XmlData | XmlData[] | undefined
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* A raw extractor function accepts an AST node and returns one or more pieces of
|
|
25
|
+
* {@linkcode Data} extracted from that node which cannot be composed into documents
|
|
26
|
+
* on their own but could be part of an entity.
|
|
27
|
+
*/
|
|
28
|
+
export type RawExtractorFunction<N extends SupportedKindName | 'any' = SupportedKindName> = (
|
|
29
|
+
node: N extends SupportedKindName ? SupportedNodeByKindName<N> : any,
|
|
30
|
+
context: Context
|
|
31
|
+
) => ExtractionResult<Data>
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* An entity extractor function accepts an AST node and returns one or more pieces
|
|
35
|
+
* of {@linkcode EntityData} extracted from that node which can then be composed
|
|
36
|
+
* into documents.
|
|
37
|
+
*/
|
|
38
|
+
export type EntityExtractorFunction<N extends SupportedKindName | 'any' = SupportedKindName> = (
|
|
39
|
+
node: N extends SupportedKindName ? SupportedNodeByKindName<N> : any,
|
|
40
|
+
context: Context
|
|
41
|
+
) => ExtractionResult<EntityData>
|
|
42
|
+
|
|
43
|
+
// This is only imported so it can be referenced in the JS doc below
|
|
44
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
45
|
+
import type { Plugin } from '../../Plugin'
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* @see {@linkcode Plugin#extractors}
|
|
49
|
+
*/
|
|
50
|
+
export type Extractors<
|
|
51
|
+
RawNodeKinds extends SupportedKindName | 'any',
|
|
52
|
+
EntityNodeKinds extends SupportedKindName | 'any',
|
|
53
|
+
> = {
|
|
54
|
+
xml?: XmlExtractorFunction
|
|
55
|
+
raw?: { [K in RawNodeKinds]: RawExtractorFunction<K> }
|
|
56
|
+
entity?: { [K in EntityNodeKinds]: EntityExtractorFunction<K> }
|
|
57
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export * from './extractors'
|
|
2
|
+
export * from './Composer'
|
|
3
|
+
export * from './Arranger'
|
|
4
|
+
export * from './Serializer'
|
|
5
|
+
export * from './Generator'
|
|
6
|
+
export * from './Transformer'
|
|
7
|
+
export * from './PostProcessor'
|
|
8
|
+
export * from './Diagnostics'
|
|
9
|
+
export * from './OwnedTables'
|