@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.
Files changed (130) hide show
  1. package/dist/BuildOptions.d.ts +50 -0
  2. package/dist/BuildOptions.js +46 -0
  3. package/dist/BuildOptions.js.map +1 -0
  4. package/dist/GUID.d.ts +2 -0
  5. package/dist/GUID.js +48 -0
  6. package/dist/GUID.js.map +1 -0
  7. package/dist/Keys.d.ts +29 -0
  8. package/dist/Keys.js +258 -0
  9. package/dist/Keys.js.map +1 -0
  10. package/dist/TypeScript.d.ts +5 -0
  11. package/dist/TypeScript.js +81 -0
  12. package/dist/TypeScript.js.map +1 -0
  13. package/dist/XML.d.ts +25 -0
  14. package/dist/XML.js +72 -0
  15. package/dist/XML.js.map +1 -0
  16. package/dist/index.d.ts +8 -0
  17. package/dist/index.js +38 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/plugins/Context.d.ts +198 -0
  20. package/dist/plugins/Context.js +3 -0
  21. package/dist/plugins/Context.js.map +1 -0
  22. package/dist/plugins/Diagnostic.d.ts +10 -0
  23. package/dist/plugins/Diagnostic.js +52 -0
  24. package/dist/plugins/Diagnostic.js.map +1 -0
  25. package/dist/plugins/Plugin.d.ts +175 -0
  26. package/dist/plugins/Plugin.js +15 -0
  27. package/dist/plugins/Plugin.js.map +1 -0
  28. package/dist/plugins/behaviors/Arranger.d.ts +26 -0
  29. package/dist/plugins/behaviors/Arranger.js +3 -0
  30. package/dist/plugins/behaviors/Arranger.js.map +1 -0
  31. package/dist/plugins/behaviors/Composer.d.ts +101 -0
  32. package/dist/plugins/behaviors/Composer.js +15 -0
  33. package/dist/plugins/behaviors/Composer.js.map +1 -0
  34. package/dist/plugins/behaviors/Diagnostics.d.ts +8 -0
  35. package/dist/plugins/behaviors/Diagnostics.js +3 -0
  36. package/dist/plugins/behaviors/Diagnostics.js.map +1 -0
  37. package/dist/plugins/behaviors/Generator.d.ts +21 -0
  38. package/dist/plugins/behaviors/Generator.js +3 -0
  39. package/dist/plugins/behaviors/Generator.js.map +1 -0
  40. package/dist/plugins/behaviors/OwnedTables.d.ts +6 -0
  41. package/dist/plugins/behaviors/OwnedTables.js +3 -0
  42. package/dist/plugins/behaviors/OwnedTables.js.map +1 -0
  43. package/dist/plugins/behaviors/PostProcessor.d.ts +5 -0
  44. package/dist/plugins/behaviors/PostProcessor.js +3 -0
  45. package/dist/plugins/behaviors/PostProcessor.js.map +1 -0
  46. package/dist/plugins/behaviors/Serializer.d.ts +29 -0
  47. package/dist/plugins/behaviors/Serializer.js +3 -0
  48. package/dist/plugins/behaviors/Serializer.js.map +1 -0
  49. package/dist/plugins/behaviors/Transformer.d.ts +23 -0
  50. package/dist/plugins/behaviors/Transformer.js +3 -0
  51. package/dist/plugins/behaviors/Transformer.js.map +1 -0
  52. package/dist/plugins/behaviors/extractors/Data.d.ts +107 -0
  53. package/dist/plugins/behaviors/extractors/Data.js +191 -0
  54. package/dist/plugins/behaviors/extractors/Data.js.map +1 -0
  55. package/dist/plugins/behaviors/extractors/Extractors.d.ts +41 -0
  56. package/dist/plugins/behaviors/extractors/Extractors.js +3 -0
  57. package/dist/plugins/behaviors/extractors/Extractors.js.map +1 -0
  58. package/dist/plugins/behaviors/extractors/index.d.ts +2 -0
  59. package/dist/plugins/behaviors/extractors/index.js +19 -0
  60. package/dist/plugins/behaviors/extractors/index.js.map +1 -0
  61. package/dist/plugins/behaviors/index.d.ts +9 -0
  62. package/dist/plugins/behaviors/index.js +26 -0
  63. package/dist/plugins/behaviors/index.js.map +1 -0
  64. package/dist/plugins/index.d.ts +5 -0
  65. package/dist/plugins/index.js +23 -0
  66. package/dist/plugins/index.js.map +1 -0
  67. package/dist/plugins/util/CallExpression.d.ts +6 -0
  68. package/dist/plugins/util/CallExpression.js +93 -0
  69. package/dist/plugins/util/CallExpression.js.map +1 -0
  70. package/dist/plugins/util/CodeTransformation.d.ts +74 -0
  71. package/dist/plugins/util/CodeTransformation.js +421 -0
  72. package/dist/plugins/util/CodeTransformation.js.map +1 -0
  73. package/dist/plugins/util/ConfigurationFunction.d.ts +106 -0
  74. package/dist/plugins/util/ConfigurationFunction.js +377 -0
  75. package/dist/plugins/util/ConfigurationFunction.js.map +1 -0
  76. package/dist/plugins/util/ObjectLiteral.d.ts +9 -0
  77. package/dist/plugins/util/ObjectLiteral.js +60 -0
  78. package/dist/plugins/util/ObjectLiteral.js.map +1 -0
  79. package/dist/plugins/util/index.d.ts +4 -0
  80. package/dist/plugins/util/index.js +21 -0
  81. package/dist/plugins/util/index.js.map +1 -0
  82. package/dist/util/Debug.d.ts +8 -0
  83. package/dist/util/Debug.js +39 -0
  84. package/dist/util/Debug.js.map +1 -0
  85. package/dist/util/Util.d.ts +4 -0
  86. package/dist/util/Util.js +41 -0
  87. package/dist/util/Util.js.map +1 -0
  88. package/dist/util/XMLJsonBuilder.d.ts +18 -0
  89. package/dist/util/XMLJsonBuilder.js +59 -0
  90. package/dist/util/XMLJsonBuilder.js.map +1 -0
  91. package/dist/util/XMLUploadParser.d.ts +22 -0
  92. package/dist/util/XMLUploadParser.js +67 -0
  93. package/dist/util/XMLUploadParser.js.map +1 -0
  94. package/dist/util/index.d.ts +4 -0
  95. package/dist/util/index.js +21 -0
  96. package/dist/util/index.js.map +1 -0
  97. package/license +9 -0
  98. package/package.json +42 -0
  99. package/src/BuildOptions.ts +27 -0
  100. package/src/GUID.ts +26 -0
  101. package/src/Keys.ts +287 -0
  102. package/src/TypeScript.ts +65 -0
  103. package/src/XML.ts +85 -0
  104. package/src/index.ts +8 -0
  105. package/src/plugins/Context.ts +249 -0
  106. package/src/plugins/Diagnostic.ts +31 -0
  107. package/src/plugins/Plugin.ts +246 -0
  108. package/src/plugins/behaviors/Arranger.ts +42 -0
  109. package/src/plugins/behaviors/Composer.ts +124 -0
  110. package/src/plugins/behaviors/Diagnostics.ts +13 -0
  111. package/src/plugins/behaviors/Generator.ts +31 -0
  112. package/src/plugins/behaviors/OwnedTables.ts +5 -0
  113. package/src/plugins/behaviors/PostProcessor.ts +6 -0
  114. package/src/plugins/behaviors/Serializer.ts +39 -0
  115. package/src/plugins/behaviors/Transformer.ts +32 -0
  116. package/src/plugins/behaviors/extractors/Data.ts +247 -0
  117. package/src/plugins/behaviors/extractors/Extractors.ts +57 -0
  118. package/src/plugins/behaviors/extractors/index.ts +2 -0
  119. package/src/plugins/behaviors/index.ts +9 -0
  120. package/src/plugins/index.ts +5 -0
  121. package/src/plugins/util/CallExpression.ts +83 -0
  122. package/src/plugins/util/CodeTransformation.ts +500 -0
  123. package/src/plugins/util/ConfigurationFunction.ts +477 -0
  124. package/src/plugins/util/ObjectLiteral.ts +37 -0
  125. package/src/plugins/util/index.ts +4 -0
  126. package/src/util/Debug.ts +46 -0
  127. package/src/util/Util.ts +21 -0
  128. package/src/util/XMLJsonBuilder.ts +64 -0
  129. package/src/util/XMLUploadParser.ts +90 -0
  130. package/src/util/index.ts +4 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Debug.js","sourceRoot":"","sources":["../../src/util/Debug.ts"],"names":[],"mappings":";;AAIA,0BAMC;AAED,8BAcC;AAED,wCAYC;AAED,gCAGC;AA7CD,+BAA6C;AAC7C,oDAA2D;AAG3D,SAAgB,OAAO,CAAC,GAAY,EAAE,KAAK,GAAG,CAAC;IAC3C,OAAO,IAAA,cAAW,EAAC,GAAG,EAAE;QACpB,MAAM,EAAE,IAAI;QACZ,OAAO,EAAE,KAAK;QACd,KAAK;KACR,CAAC,CAAA;AACN,CAAC;AAED,SAAgB,SAAS,CAAC,IAAkC,EAAE,MAAc,EAAE,OAAO,GAAG,OAAO;IAC3F,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IACpB,MAAM,CAAC,IAAI,CACP,OAAO,CACH,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACX,IAAI,CAAC,YAAY,gBAAI,EAAE,CAAC;YACpB,OAAO,CAAC,CAAC,QAAQ,EAAE,CAAA;QACvB,CAAC;aAAM,CAAC;YACJ,OAAO,CAAC,CAAA;QACZ,CAAC;IACL,CAAC,CAAC,EACF,CAAC,CACJ,CACJ,CAAA;AACL,CAAC;AAED,SAAgB,cAAc,CAAC,SAAqB,EAAE,MAAc,EAAE,OAAO,GAAG,YAAY;IACxF,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IACpB,MAAM,CAAC,IAAI,CACP,OAAO,CACH,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QAChB,MAAM,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,GAAG,CAAC,CAAA;QAC3B,IAAI,CAAA;QACJ,OAAO,IAAI,CAAA;IACf,CAAC,CAAC,EACF,CAAC,CACJ,CACJ,CAAA;AACL,CAAC;AAED,SAAgB,UAAU,CAAC,KAAa,EAAE,MAAc,EAAE,OAAO,GAAG,QAAQ;IACxE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IACpB,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAA;AAClC,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { FileSystem } from '@servicenow/sdk-project';
2
+ export declare const NOW_DIR = ".now";
3
+ export declare function safeWriteFileToPath(fs: FileSystem, dirPath: string, fileName: string, content: string, encoding?: FileSystem.Encoding): void;
4
+ export declare function createDirIfNotExists(dirPath: string, fs: FileSystem): void;
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.NOW_DIR = void 0;
27
+ exports.safeWriteFileToPath = safeWriteFileToPath;
28
+ exports.createDirIfNotExists = createDirIfNotExists;
29
+ const path = __importStar(require("path"));
30
+ const sdk_project_1 = require("@servicenow/sdk-project");
31
+ exports.NOW_DIR = '.now';
32
+ function safeWriteFileToPath(fs, dirPath, fileName, content, encoding = 'utf-8') {
33
+ createDirIfNotExists(dirPath, fs);
34
+ fs.writeFileSync(path.join(dirPath, fileName), content, { encoding: encoding });
35
+ }
36
+ function createDirIfNotExists(dirPath, fs) {
37
+ if (!sdk_project_1.FileSystem.existsSync(fs, dirPath)) {
38
+ fs.mkdirSync(dirPath, { recursive: true });
39
+ }
40
+ }
41
+ //# sourceMappingURL=Util.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Util.js","sourceRoot":"","sources":["../../src/util/Util.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAKA,kDASC;AAED,oDAIC;AApBD,2CAA4B;AAC5B,yDAAoD;AAEvC,QAAA,OAAO,GAAG,MAAM,CAAA;AAE7B,SAAgB,mBAAmB,CAC/B,EAAc,EACd,OAAe,EACf,QAAgB,EAChB,OAAe,EACf,WAAgC,OAAO;IAEvC,oBAAoB,CAAC,OAAO,EAAE,EAAE,CAAC,CAAA;IACjC,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAA;AACnF,CAAC;AAED,SAAgB,oBAAoB,CAAC,OAAe,EAAE,EAAc;IAChE,IAAI,CAAC,wBAAU,CAAC,UAAU,CAAC,EAAE,EAAE,OAAO,CAAC,EAAE,CAAC;QACtC,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAC9C,CAAC;AACL,CAAC"}
@@ -0,0 +1,18 @@
1
+ export declare class XMLJsonBuilder {
2
+ private rootXmlElement;
3
+ constructor(version: string);
4
+ createRoot(element: string, text?: string, attrs?: Record<string, string | number | boolean>): XMLJsonElement;
5
+ buildJsonObj(): any;
6
+ }
7
+ export declare class XMLJsonElement {
8
+ private element;
9
+ private text;
10
+ private attrs;
11
+ private isCDATA;
12
+ private xmlEleMap;
13
+ constructor(element: string, text?: string, attrs?: Record<string, string | number | boolean>, isCDATA?: boolean);
14
+ addJsonObj(element: string, text?: string, attrs?: Record<string, string | number | boolean>, isCDATA?: boolean): XMLJsonElement;
15
+ getData(): {
16
+ [x: string]: any;
17
+ };
18
+ }
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.XMLJsonElement = exports.XMLJsonBuilder = void 0;
4
+ class XMLJsonBuilder {
5
+ rootXmlElement;
6
+ constructor(version) {
7
+ this.rootXmlElement = new XMLJsonElement('_root');
8
+ this.rootXmlElement.addJsonObj('?xml', undefined, { version });
9
+ }
10
+ createRoot(element, text = '', attrs = {}) {
11
+ return this.rootXmlElement.addJsonObj(element, text, attrs);
12
+ }
13
+ buildJsonObj() {
14
+ const { _root: { '#text': _rootText, ...jsonObj }, } = this.rootXmlElement.getData();
15
+ return jsonObj;
16
+ }
17
+ }
18
+ exports.XMLJsonBuilder = XMLJsonBuilder;
19
+ class XMLJsonElement {
20
+ element;
21
+ text;
22
+ attrs;
23
+ isCDATA;
24
+ xmlEleMap = new Map();
25
+ constructor(element, text = '', attrs = {}, isCDATA = false) {
26
+ this.element = element;
27
+ this.text = text;
28
+ this.attrs = attrs;
29
+ this.isCDATA = isCDATA;
30
+ }
31
+ addJsonObj(element, text = '', attrs = {}, isCDATA = false) {
32
+ const xmlJsonObj = new XMLJsonElement(element, text, attrs, isCDATA);
33
+ if (!this.xmlEleMap.has(element)) {
34
+ this.xmlEleMap.set(element, []);
35
+ }
36
+ this.xmlEleMap.get(element).push(xmlJsonObj);
37
+ return xmlJsonObj;
38
+ }
39
+ getData() {
40
+ const additionalElements = [];
41
+ this.xmlEleMap.forEach((value, key) => {
42
+ if (value.length === 1) {
43
+ additionalElements.push({ ...value[0].getData() });
44
+ return;
45
+ }
46
+ additionalElements.push({ [key]: value.map((value) => value.getData()[key]) });
47
+ });
48
+ const additionalObj = additionalElements.reduce((acc, ele) => ({ ...acc, ...ele }), {});
49
+ return {
50
+ [this.element]: {
51
+ ...(this.isCDATA ? { __cdata: this.text } : { '#text': this.text }),
52
+ ...Object.fromEntries(Object.entries(this.attrs).map(([k, v]) => [`@_${k}`, v])),
53
+ ...additionalObj,
54
+ },
55
+ };
56
+ }
57
+ }
58
+ exports.XMLJsonElement = XMLJsonElement;
59
+ //# sourceMappingURL=XMLJsonBuilder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"XMLJsonBuilder.js","sourceRoot":"","sources":["../../src/util/XMLJsonBuilder.ts"],"names":[],"mappings":";;;AAAA,MAAa,cAAc;IACf,cAAc,CAAgB;IACtC,YAAY,OAAe;QACvB,IAAI,CAAC,cAAc,GAAG,IAAI,cAAc,CAAC,OAAO,CAAC,CAAA;QACjD,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,OAAO,EAAE,CAAC,CAAA;IAClE,CAAC;IAED,UAAU,CAAC,OAAe,EAAE,OAAe,EAAE,EAAE,QAAmD,EAAE;QAChG,OAAO,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,CAAA;IAC/D,CAAC;IAED,YAAY;QACR,MAAM,EACF,KAAK,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,OAAO,EAAE,GAC5C,GAAG,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,CAAA;QACjC,OAAO,OAAO,CAAA;IAClB,CAAC;CACJ;AAjBD,wCAiBC;AAED,MAAa,cAAc;IAIX;IACA;IACA;IACA;IANJ,SAAS,GAAkC,IAAI,GAAG,EAAE,CAAA;IAE5D,YACY,OAAe,EACf,OAAe,EAAE,EACjB,QAAmD,EAAE,EACrD,UAAmB,KAAK;QAHxB,YAAO,GAAP,OAAO,CAAQ;QACf,SAAI,GAAJ,IAAI,CAAa;QACjB,UAAK,GAAL,KAAK,CAAgD;QACrD,YAAO,GAAP,OAAO,CAAiB;IACjC,CAAC;IAEJ,UAAU,CACN,OAAe,EACf,OAAe,EAAE,EACjB,QAAmD,EAAE,EACrD,UAAmB,KAAK;QAExB,MAAM,UAAU,GAAG,IAAI,cAAc,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,CAAA;QACpE,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;YAC/B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC,CAAA;QACnC,CAAC;QACD,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;QAC7C,OAAO,UAAU,CAAA;IACrB,CAAC;IAED,OAAO;QACH,MAAM,kBAAkB,GAAQ,EAAE,CAAA;QAClC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;YAClC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACrB,kBAAkB,CAAC,IAAI,CAAC,EAAE,GAAG,KAAK,CAAC,CAAC,CAAE,CAAC,OAAO,EAAE,EAAE,CAAC,CAAA;gBACnD,OAAM;YACV,CAAC;YACD,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAA;QAClF,CAAC,CAAC,CAAA;QAEF,MAAM,aAAa,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,GAAG,EAAE,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,CAAA;QAEvF,OAAO;YACH,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE;gBACZ,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC;gBACnE,GAAG,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;gBAChF,GAAG,aAAa;aACnB;SACJ,CAAA;IACL,CAAC;CACJ;AA5CD,wCA4CC"}
@@ -0,0 +1,22 @@
1
+ declare enum Action {
2
+ INSERT_OR_UPDATE = "INSERT_OR_UPDATE",
3
+ DELETE = "DELETE",
4
+ DELETE_MULTIPLE = "delete_multiple"
5
+ }
6
+ export type Record = {
7
+ table: string;
8
+ action: Action;
9
+ id: string;
10
+ data: {
11
+ [element: string]: string | undefined | boolean | number;
12
+ };
13
+ };
14
+ export declare class XMLUnloadParser {
15
+ readonly records: Record[];
16
+ static parse: (xml: string) => XMLUnloadParser;
17
+ private parse;
18
+ private processResult;
19
+ private parseRecord;
20
+ private parseAction;
21
+ }
22
+ export {};
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.XMLUnloadParser = void 0;
4
+ const fast_xml_parser_1 = require("fast-xml-parser");
5
+ var Action;
6
+ (function (Action) {
7
+ Action["INSERT_OR_UPDATE"] = "INSERT_OR_UPDATE";
8
+ Action["DELETE"] = "DELETE";
9
+ Action["DELETE_MULTIPLE"] = "delete_multiple";
10
+ })(Action || (Action = {}));
11
+ class XMLUnloadParser {
12
+ records = [];
13
+ static parse = (xml) => {
14
+ const parser = new XMLUnloadParser();
15
+ parser.parse(xml);
16
+ return parser;
17
+ };
18
+ parse = (xml) => {
19
+ const parsed = new fast_xml_parser_1.XMLParser({
20
+ ignoreAttributes: false,
21
+ alwaysCreateTextNode: false,
22
+ ignoreDeclaration: true,
23
+ }).parse(xml, true);
24
+ this.processResult(parsed);
25
+ };
26
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
27
+ processResult(result) {
28
+ const recordUpdate = result['record_update'];
29
+ for (const tag in recordUpdate) {
30
+ if (!tag.startsWith('@') && typeof recordUpdate[tag] === 'object') {
31
+ const records = recordUpdate[tag];
32
+ if (Array.isArray(records)) {
33
+ for (const record of records) {
34
+ this.parseRecord(tag, record);
35
+ }
36
+ }
37
+ else {
38
+ this.parseRecord(tag, recordUpdate[tag]);
39
+ }
40
+ }
41
+ }
42
+ }
43
+ parseRecord(table, record) {
44
+ const { '@_action': action, sys_id, ...data } = record;
45
+ const parsedAction = this.parseAction(action);
46
+ this.records.push({
47
+ table,
48
+ action: parsedAction,
49
+ id: sys_id || 'unknown',
50
+ data,
51
+ });
52
+ }
53
+ parseAction(actionStr) {
54
+ switch (actionStr) {
55
+ case 'INSERT_OR_UPDATE':
56
+ return Action.INSERT_OR_UPDATE;
57
+ case 'DELETE':
58
+ return Action.DELETE;
59
+ case 'delete_multiple':
60
+ return Action.DELETE_MULTIPLE;
61
+ default:
62
+ throw new Error(`Invalid action string: ${actionStr}`);
63
+ }
64
+ }
65
+ }
66
+ exports.XMLUnloadParser = XMLUnloadParser;
67
+ //# sourceMappingURL=XMLUploadParser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"XMLUploadParser.js","sourceRoot":"","sources":["../../src/util/XMLUploadParser.ts"],"names":[],"mappings":";;;AAAA,qDAA2C;AAE3C,IAAK,MAIJ;AAJD,WAAK,MAAM;IACP,+CAAqC,CAAA;IACrC,2BAAiB,CAAA;IACjB,6CAAmC,CAAA;AACvC,CAAC,EAJI,MAAM,KAAN,MAAM,QAIV;AASD,MAAa,eAAe;IACf,OAAO,GAAa,EAAE,CAAA;IAE/B,MAAM,CAAC,KAAK,GAAG,CAAC,GAAW,EAAE,EAAE;QAC3B,MAAM,MAAM,GAAG,IAAI,eAAe,EAAE,CAAA;QACpC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;QAEjB,OAAO,MAAM,CAAA;IACjB,CAAC,CAAA;IAEO,KAAK,GAAG,CAAC,GAAW,EAAE,EAAE;QAC5B,MAAM,MAAM,GAAG,IAAI,2BAAS,CAAC;YACzB,gBAAgB,EAAE,KAAK;YACvB,oBAAoB,EAAE,KAAK;YAC3B,iBAAiB,EAAE,IAAI;SAC1B,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC,CAAA;QAEnB,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,CAAA;IAC9B,CAAC,CAAA;IAED,8DAA8D;IACtD,aAAa,CAAC,MAAmD;QACrE,MAAM,YAAY,GAAG,MAAM,CAAC,eAAe,CAAC,CAAA;QAE5C,KAAK,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;YAC7B,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,OAAO,YAAY,CAAC,GAAG,CAAC,KAAK,QAAQ,EAAE,CAAC;gBAChE,MAAM,OAAO,GAAG,YAAY,CAAC,GAAG,CAAC,CAAA;gBACjC,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;oBACzB,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;wBAC3B,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,MAAM,CAAC,CAAA;oBACjC,CAAC;gBACL,CAAC;qBAAM,CAAC;oBACJ,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,YAAY,CAAC,GAAG,CAAC,CAAC,CAAA;gBAC5C,CAAC;YACL,CAAC;QACL,CAAC;IACL,CAAC;IAEO,WAAW,CAAC,KAAa,EAAE,MAA6B;QAC5D,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,MAAM,CAAA;QAEtD,MAAM,YAAY,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAA;QAE7C,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;YACd,KAAK;YACL,MAAM,EAAE,YAAY;YACpB,EAAE,EAAG,MAAiB,IAAI,SAAS;YACnC,IAAI;SACP,CAAC,CAAA;IACN,CAAC;IAEO,WAAW,CAAC,SAAiB;QACjC,QAAQ,SAAS,EAAE,CAAC;YAChB,KAAK,kBAAkB;gBACnB,OAAO,MAAM,CAAC,gBAAgB,CAAA;YAClC,KAAK,QAAQ;gBACT,OAAO,MAAM,CAAC,MAAM,CAAA;YACxB,KAAK,iBAAiB;gBAClB,OAAO,MAAM,CAAC,eAAe,CAAA;YACjC;gBACI,MAAM,IAAI,KAAK,CAAC,0BAA0B,SAAS,EAAE,CAAC,CAAA;QAC9D,CAAC;IACL,CAAC;;AA9DL,0CA+DC"}
@@ -0,0 +1,4 @@
1
+ export * from './Debug';
2
+ export * from './Util';
3
+ export * from './XMLUploadParser';
4
+ export * from './XMLJsonBuilder';
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./Debug"), exports);
18
+ __exportStar(require("./Util"), exports);
19
+ __exportStar(require("./XMLUploadParser"), exports);
20
+ __exportStar(require("./XMLJsonBuilder"), exports);
21
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/util/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,0CAAuB;AACvB,yCAAsB;AACtB,oDAAiC;AACjC,mDAAgC"}
package/license ADDED
@@ -0,0 +1,9 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 ServiceNow Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
+
7
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@servicenow/sdk-build-core",
3
+ "version": "2.0.1",
4
+ "description": "ServiceNow SDK Build System Core Libraries",
5
+ "license": "MIT",
6
+ "main": "./dist/index.js",
7
+ "files": [
8
+ "dist",
9
+ "src"
10
+ ],
11
+ "dependencies": {
12
+ "@ts-morph/common": "0.24.0",
13
+ "fast-xml-parser": "4.4.1",
14
+ "lodash": "4.17.21",
15
+ "ts-morph": "23.0.0",
16
+ "zod": "3.22.4",
17
+ "@servicenow/sdk-core": "2.0.1",
18
+ "@servicenow/sdk-project": "2.0.1",
19
+ "@servicenow/sdk-metrics": "2.0.1"
20
+ },
21
+ "overrides": {
22
+ "micromatch": "^4.0.7"
23
+ },
24
+ "devDependencies": {
25
+ "@types/lodash": "4.14.195",
26
+ "junk": "3.1.0",
27
+ "memfs": "^4.8.1"
28
+ },
29
+ "engines": {
30
+ "node": ">=18.16.1",
31
+ "pnpm": ">=9.4.0"
32
+ },
33
+ "scripts": {
34
+ "build": "tsc -b",
35
+ "clean": "tsc -b --clean",
36
+ "lint": "eslint . --ext .ts",
37
+ "prettier:check": "prettier --check --ignore-path=../../.prettierignore .",
38
+ "prettier:write": "prettier --write --ignore-path=../../.prettierignore .",
39
+ "watch": "tsc -b -w",
40
+ "test": "tsc -b tsconfig.test.json && export NODE_OPTIONS=\"--max-old-space-size=8192 --experimental-vm-modules\" && jest --colors --reporters=default --no-cache --logHeapUsage"
41
+ }
42
+ }
@@ -0,0 +1,27 @@
1
+ import * as path from 'path'
2
+ import * as z from 'zod'
3
+
4
+ const BuildOptionsSchema = z
5
+ .object({
6
+ mode: z.string(),
7
+ release: z.string().default('default'),
8
+ debug: z.boolean().default(false),
9
+ dontSaveFiles: z.boolean().default(false),
10
+ })
11
+ .and(
12
+ z
13
+ .object({
14
+ mode: z.literal('serialize'),
15
+ })
16
+ .or(
17
+ z.object({
18
+ mode: z.literal('transform'),
19
+ clean: z.boolean().default(false),
20
+ transformDirectory: z.string().default(path.resolve(process.cwd(), 'incoming')),
21
+ })
22
+ )
23
+ )
24
+
25
+ export type BuildOptionsInput = z.input<typeof BuildOptionsSchema>
26
+ export type BuildOptions = z.output<typeof BuildOptionsSchema>
27
+ export const parseBuildOptions = BuildOptionsSchema.parse
package/src/GUID.ts ADDED
@@ -0,0 +1,26 @@
1
+ import * as crypto from 'crypto'
2
+
3
+ const HASH_ALGORITHM = 'md5'
4
+ const HASH_DIGEST = 'hex'
5
+ const HASH_SEPARATOR = ':'
6
+
7
+ export function GUID(...parts: unknown[]) {
8
+ if (parts.length === 0) {
9
+ return crypto.randomUUID().replaceAll('-', '')
10
+ }
11
+
12
+ const hash = crypto.createHash(HASH_ALGORITHM)
13
+ hash.update(parts.join(HASH_SEPARATOR))
14
+ return hash.digest(HASH_DIGEST)
15
+ }
16
+
17
+ // Matches a hex string exactly 32 characters long
18
+ const snIDRegex = /^[a-f0-9]{32}$/i
19
+
20
+ export function isGUID(guid: string | number): guid is string {
21
+ if (typeof guid !== 'string') {
22
+ return false
23
+ }
24
+
25
+ return snIDRegex.test(guid)
26
+ }
package/src/Keys.ts ADDED
@@ -0,0 +1,287 @@
1
+ import { SourceFile, ModuleDeclarationKind, PropertySignatureStructure, OptionalKind } from 'ts-morph'
2
+ import * as path from 'path'
3
+ import { parseType } from './TypeScript'
4
+ import { GUID, isGUID } from './GUID'
5
+ import * as z from 'zod'
6
+ import * as _ from 'lodash'
7
+ import { Context } from './plugins'
8
+ import { FileSystem } from '@servicenow/sdk-project'
9
+
10
+ export const KEYS_MODULE = '@servicenow/sdk/global'
11
+ export const KEYS_FILE_NAME = 'keys.ts'
12
+
13
+ const KeysSchema = z.object({
14
+ explicit: z
15
+ .record(
16
+ z.string().or(z.number()),
17
+ z.object({
18
+ table: z.string(),
19
+ id: z.string(),
20
+ })
21
+ )
22
+ .default({}),
23
+ composite: z
24
+ .array(
25
+ z.object({
26
+ table: z.string(),
27
+ id: z.string(),
28
+ key: z.record(z.string(), z.string().or(z.number())),
29
+ })
30
+ )
31
+ .default([]),
32
+ deleted: z.record(z.array(z.string())).default({}),
33
+ })
34
+
35
+ export class Keys implements Now.Internal.KeysRegistry {
36
+ private readonly keys: Now.Internal.KeysRegistry
37
+ private readonly usedIds: Set<string> = new Set()
38
+
39
+ constructor(context: Context) {
40
+ this.keys = Keys.parseKeysFile(context) ?? { explicit: {}, composite: [], deleted: {} }
41
+ }
42
+
43
+ private static parseKeysFile(context: Context): Now.Internal.KeysRegistry | undefined {
44
+ const keysFile = Keys.getKeysFile(context)
45
+ if (!keysFile) {
46
+ return undefined
47
+ }
48
+
49
+ const keysInterface = Keys.getOrCreateKeysInterface(keysFile)
50
+ return KeysSchema.parse(
51
+ parseType(keysInterface.getType(), keysInterface, (unparsableType) => {
52
+ if (unparsableType.isArray()) {
53
+ return [] // If the keys file doesn't have composite keys, it will be an unparsable array so just return an empty one
54
+ } else {
55
+ throw `Unparsable type in keys.ts: ${unparsableType.getText()}`
56
+ }
57
+ })
58
+ )
59
+ }
60
+
61
+ private static getKeysFile(context: Context): SourceFile | undefined {
62
+ const keysFilePath = Keys.getKeysFilePath(context)
63
+ if (!FileSystem.existsSync(context.fs, keysFilePath)) {
64
+ // BUG: It shouldn't be necessary to check manually here, but there is a bug in
65
+ // ts-morph where attempting to add a source file that doesn't exist will cause
66
+ // subsequent operations on the parent directory to fail in certain scenarios.
67
+ //
68
+ // Created an issue here: https://github.com/dsherret/ts-morph/issues/1554
69
+ return undefined
70
+ }
71
+
72
+ return context.compiler.addSourceFileAtPathIfExists(keysFilePath)
73
+ }
74
+
75
+ public static getKeysFilePath(context: Context) {
76
+ return path.resolve(context.app.rootDir, context.app.config.generatedDir, KEYS_FILE_NAME)
77
+ }
78
+
79
+ private static createKeysFile(context: Context): SourceFile {
80
+ const keysFilePath = Keys.getKeysFilePath(context)
81
+ const parentDir = path.dirname(keysFilePath)
82
+ context.fs.mkdirSync(parentDir, { recursive: true })
83
+ const keysFile = context.compiler.createSourceFile(keysFilePath, '', {})
84
+ Keys.ensureGlobalImport(keysFile)
85
+
86
+ return keysFile
87
+ }
88
+
89
+ private static ensureGlobalImport(keysFile: SourceFile) {
90
+ if (!keysFile.getImportDeclaration((i) => i.getModuleSpecifierValue() === KEYS_MODULE)) {
91
+ keysFile.addImportDeclaration({ moduleSpecifier: KEYS_MODULE })
92
+ }
93
+ }
94
+
95
+ private static getOrCreateKeysInterface(keysFile: SourceFile) {
96
+ const declareGlobal =
97
+ keysFile.getModule('global') ??
98
+ keysFile.addModule({
99
+ name: 'global',
100
+ declarationKind: ModuleDeclarationKind.Global,
101
+ hasDeclareKeyword: true,
102
+ })
103
+
104
+ const nowNamespace =
105
+ declareGlobal.getModule('Now') ??
106
+ declareGlobal.addModule({
107
+ name: 'Now',
108
+ declarationKind: ModuleDeclarationKind.Namespace,
109
+ })
110
+
111
+ const internalNamespace =
112
+ nowNamespace.getModule('Internal') ??
113
+ nowNamespace.addModule({
114
+ name: 'Internal',
115
+ })
116
+
117
+ return (
118
+ internalNamespace.getInterface('Keys') ??
119
+ internalNamespace.addInterface({
120
+ name: 'Keys',
121
+ extends: (writer) => {
122
+ writer.write('KeysRegistry')
123
+ },
124
+ })
125
+ )
126
+ }
127
+
128
+ private use(id: string) {
129
+ this.usedIds.add(id)
130
+ return id
131
+ }
132
+
133
+ get explicit() {
134
+ return this.keys.explicit
135
+ }
136
+
137
+ get composite() {
138
+ return this.keys.composite
139
+ }
140
+
141
+ get deleted() {
142
+ return this.keys.deleted
143
+ }
144
+
145
+ getNextAvailableExplicitKey() {
146
+ for (let i = 0; ; i++) {
147
+ const key = `generated${i}`
148
+ if (!this.explicit[key]) {
149
+ return key
150
+ }
151
+ }
152
+ }
153
+
154
+ findExplicitKeyById(id: string) {
155
+ return Object.entries(this.explicit).find(([, v]) => v.id === id)?.[0]
156
+ }
157
+
158
+ registerExplicitId(table: string, key: string | number, sysIdOverride?: string): string {
159
+ if (isGUID(key)) {
160
+ // WARNING:
161
+ //
162
+ // IT IS CRITICAL THAT KEYS ARE NOT REGISTERED FOR THINGS OUTSIDE OF THE APP. IF KEYS ARE
163
+ // REGISTERED FOR THINGS THAT COME FROM THE CORE PLATFORM OR SOME OTHER APP, THERE IS RISK
164
+ // THAT THEY WILL BE DELETED ACCIDENTALLY BY THE CUSTOMER.
165
+ //
166
+ // THIS CHECK IS HERE AS AN EXTRA DEFENSIVE MEASURE TO MAKE SURE EXTERNAL SYS IDS ARE NOT
167
+ // ACCIDENTALLY REGISTERED AS LOCAL KEYS.
168
+ //
169
+ // TODO: We need to come up with a different system for key registration where external
170
+ // keys can be resolved to sys IDs without registering them as local keys.
171
+ return this.use(this.explicit[key]?.id ?? key)
172
+ }
173
+
174
+ const existing = this.explicit[key]
175
+ if (existing) {
176
+ if (existing.table !== table) {
177
+ throw `Explicit key '${key}' is already registered for table '${existing.table}', cannot register for table '${table}'`
178
+ }
179
+
180
+ return this.use(existing.id)
181
+ }
182
+
183
+ if (sysIdOverride) {
184
+ const existingKey = this.findExplicitKeyById(sysIdOverride)
185
+ if (existingKey) {
186
+ const existingWithSysId = this.explicit[existingKey]!
187
+ if (existingWithSysId.table !== table) {
188
+ throw `ID '${sysIdOverride}' is already registered for table '${existingWithSysId.table}', cannot register for table '${table}'`
189
+ }
190
+
191
+ if (existingKey !== (key as string | number)) {
192
+ throw `ID '${sysIdOverride}' is already registered for key '${existingKey}', cannot register for key '${key}'`
193
+ }
194
+
195
+ return this.use(existingWithSysId.id)
196
+ }
197
+ }
198
+
199
+ const newKey = {
200
+ table,
201
+ id: isGUID(key) ? (key as string) : sysIdOverride ?? GUID(),
202
+ }
203
+
204
+ this.explicit[key] = newKey
205
+ return this.use(newKey.id)
206
+ }
207
+
208
+ registerCompositeId(table: string, key: Record<string, string | number>, sysIdOverride?: string): string {
209
+ const existing = this.composite.find((k) => k.table === table && _.isEqual(k.key, key))
210
+ if (existing) {
211
+ if (existing.table !== table) {
212
+ throw `Composite key ${key} is already registered for table '${existing.table}', cannot register for table '${table}'`
213
+ }
214
+
215
+ return this.use(existing.id)
216
+ }
217
+
218
+ const newKey = {
219
+ table,
220
+ id: sysIdOverride ?? GUID(),
221
+ key,
222
+ }
223
+
224
+ this.composite.push(newKey)
225
+ return this.use(newKey.id)
226
+ }
227
+
228
+ getUsedExplicitIds() {
229
+ return Object.fromEntries(Object.entries(this.explicit).filter(([, v]) => this.usedIds.has(v.id)))
230
+ }
231
+
232
+ getUsedCompositeIds() {
233
+ return this.composite.filter((v) => this.usedIds.has(v.id))
234
+ }
235
+
236
+ // TODO: This is called in multiple places and is not very cheap. We should consider optimization options.
237
+ getDeletedAndUnusedIds() {
238
+ return [
239
+ ...Object.values(this.explicit),
240
+ ...this.composite,
241
+ ...Object.entries(this.deleted).flatMap(([k, v]) => v.map((id) => ({ table: k, id }))),
242
+ ]
243
+ .filter((v) => !this.usedIds.has(v.id))
244
+ .reduce(
245
+ (deletedIds, v) => {
246
+ deletedIds[v.table] = [...(deletedIds[v.table] ?? []), v.id]
247
+ return deletedIds
248
+ },
249
+ {} as Record<string, string[]>
250
+ )
251
+ }
252
+
253
+ async save(context: Context, formatter?: (file: SourceFile) => Promise<void>) {
254
+ const newProperties: OptionalKind<PropertySignatureStructure>[] = []
255
+ const usedExplicitIds = this.getUsedExplicitIds()
256
+ const usedCompositeIds = this.getUsedCompositeIds()
257
+ const deletedOrUnusedIds = this.getDeletedAndUnusedIds()
258
+
259
+ if (Object.keys(usedExplicitIds).length > 0) {
260
+ newProperties.push({
261
+ name: 'explicit',
262
+ type: JSON.stringify(usedExplicitIds, undefined, 4),
263
+ })
264
+ }
265
+
266
+ if (usedCompositeIds.length > 0) {
267
+ newProperties.push({
268
+ name: 'composite',
269
+ type: JSON.stringify(usedCompositeIds, undefined, 4),
270
+ })
271
+ }
272
+
273
+ if (Object.keys(deletedOrUnusedIds).length > 0) {
274
+ newProperties.push({
275
+ name: 'deleted',
276
+ type: JSON.stringify(deletedOrUnusedIds, undefined, 4),
277
+ })
278
+ }
279
+
280
+ const keysFile = Keys.getKeysFile(context) ?? Keys.createKeysFile(context)
281
+ const keysInterface = Keys.getOrCreateKeysInterface(keysFile)
282
+ keysInterface.getProperties().forEach((p) => p.remove())
283
+ keysInterface.addProperties(newProperties)
284
+ await formatter?.(keysFile)
285
+ keysFile.saveSync()
286
+ }
287
+ }