@willieee802/zigbee-herdsman 0.49.3 → 0.50.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/.github/dependabot.yml +0 -3
- package/.github/workflows/ci.yml +1 -2
- package/.github/workflows/release-please.yml +1 -1
- package/.github/workflows/typedoc.yaml +3 -3
- package/.release-please-manifest.json +1 -1
- package/CHANGELOG.md +143 -0
- package/biome.json +1 -1
- package/dist/adapter/adapter.d.ts +14 -1
- package/dist/adapter/adapter.d.ts.map +1 -1
- package/dist/adapter/adapter.js +17 -0
- package/dist/adapter/adapter.js.map +1 -1
- package/dist/adapter/adapterDiscovery.d.ts.map +1 -1
- package/dist/adapter/adapterDiscovery.js.map +1 -1
- package/dist/adapter/deconz/adapter/deconzAdapter.d.ts +1 -3
- package/dist/adapter/deconz/adapter/deconzAdapter.d.ts.map +1 -1
- package/dist/adapter/deconz/adapter/deconzAdapter.js +14 -29
- package/dist/adapter/deconz/adapter/deconzAdapter.js.map +1 -1
- package/dist/adapter/deconz/driver/constants.d.ts +1 -1
- package/dist/adapter/deconz/driver/constants.d.ts.map +1 -1
- package/dist/adapter/ember/adapter/emberAdapter.d.ts +1 -1
- package/dist/adapter/ember/adapter/emberAdapter.d.ts.map +1 -1
- package/dist/adapter/ember/adapter/emberAdapter.js +19 -10
- package/dist/adapter/ember/adapter/emberAdapter.js.map +1 -1
- package/dist/adapter/ember/adapter/oneWaitress.d.ts +2 -0
- package/dist/adapter/ember/adapter/oneWaitress.d.ts.map +1 -1
- package/dist/adapter/ember/adapter/oneWaitress.js +13 -5
- package/dist/adapter/ember/adapter/oneWaitress.js.map +1 -1
- package/dist/adapter/ezsp/adapter/ezspAdapter.d.ts +1 -3
- package/dist/adapter/ezsp/adapter/ezspAdapter.d.ts.map +1 -1
- package/dist/adapter/ezsp/adapter/ezspAdapter.js +17 -30
- package/dist/adapter/ezsp/adapter/ezspAdapter.js.map +1 -1
- package/dist/adapter/ezsp/driver/index.d.ts +1 -1
- package/dist/adapter/ezsp/driver/index.d.ts.map +1 -1
- package/dist/adapter/ezsp/driver/index.js +1 -1
- package/dist/adapter/ezsp/driver/index.js.map +1 -1
- package/dist/adapter/ezsp/driver/types/index.d.ts +1 -1
- package/dist/adapter/ezsp/driver/types/index.d.ts.map +1 -1
- package/dist/adapter/ezsp/driver/types/index.js +3 -3
- package/dist/adapter/ezsp/driver/types/index.js.map +1 -1
- package/dist/adapter/serialPort.d.ts.map +1 -1
- package/dist/adapter/serialPort.js +7 -0
- package/dist/adapter/serialPort.js.map +1 -1
- package/dist/adapter/z-stack/adapter/adapter-backup.js +1 -1
- package/dist/adapter/z-stack/adapter/adapter-backup.js.map +1 -1
- package/dist/adapter/z-stack/adapter/adapter-nv-memory.js +1 -1
- package/dist/adapter/z-stack/adapter/adapter-nv-memory.js.map +1 -1
- package/dist/adapter/z-stack/adapter/manager.d.ts.map +1 -1
- package/dist/adapter/z-stack/adapter/manager.js +12 -2
- package/dist/adapter/z-stack/adapter/manager.js.map +1 -1
- package/dist/adapter/z-stack/adapter/tstype.d.ts.map +1 -1
- package/dist/adapter/z-stack/adapter/zStackAdapter.d.ts +1 -3
- package/dist/adapter/z-stack/adapter/zStackAdapter.d.ts.map +1 -1
- package/dist/adapter/z-stack/adapter/zStackAdapter.js +20 -34
- package/dist/adapter/z-stack/adapter/zStackAdapter.js.map +1 -1
- package/dist/adapter/z-stack/constants/index.d.ts +1 -1
- package/dist/adapter/z-stack/constants/index.d.ts.map +1 -1
- package/dist/adapter/z-stack/constants/index.js +1 -1
- package/dist/adapter/z-stack/constants/index.js.map +1 -1
- package/dist/adapter/z-stack/unpi/constants.d.ts +1 -1
- package/dist/adapter/z-stack/unpi/constants.d.ts.map +1 -1
- package/dist/adapter/z-stack/unpi/constants.js +1 -1
- package/dist/adapter/z-stack/unpi/constants.js.map +1 -1
- package/dist/adapter/zboss/adapter/zbossAdapter.d.ts +7 -8
- package/dist/adapter/zboss/adapter/zbossAdapter.d.ts.map +1 -1
- package/dist/adapter/zboss/adapter/zbossAdapter.js +12 -30
- package/dist/adapter/zboss/adapter/zbossAdapter.js.map +1 -1
- package/dist/adapter/zboss/driver.d.ts.map +1 -1
- package/dist/adapter/zboss/driver.js +8 -1
- package/dist/adapter/zboss/driver.js.map +1 -1
- package/dist/adapter/zboss/uart.d.ts.map +1 -1
- package/dist/adapter/zboss/uart.js +14 -2
- package/dist/adapter/zboss/uart.js.map +1 -1
- package/dist/adapter/zigate/adapter/zigateAdapter.d.ts +1 -3
- package/dist/adapter/zigate/adapter/zigateAdapter.d.ts.map +1 -1
- package/dist/adapter/zigate/adapter/zigateAdapter.js +8 -29
- package/dist/adapter/zigate/adapter/zigateAdapter.js.map +1 -1
- package/dist/adapter/zoh/adapter/zohAdapter.d.ts +1 -3
- package/dist/adapter/zoh/adapter/zohAdapter.d.ts.map +1 -1
- package/dist/adapter/zoh/adapter/zohAdapter.js +18 -33
- package/dist/adapter/zoh/adapter/zohAdapter.js.map +1 -1
- package/dist/controller/controller.d.ts.map +1 -1
- package/dist/controller/controller.js +10 -2
- package/dist/controller/controller.js.map +1 -1
- package/dist/controller/greenPower.d.ts.map +1 -1
- package/dist/controller/greenPower.js +15 -9
- package/dist/controller/greenPower.js.map +1 -1
- package/dist/controller/helpers/ota.d.ts +4 -4
- package/dist/controller/helpers/ota.d.ts.map +1 -1
- package/dist/controller/helpers/ota.js +28 -9
- package/dist/controller/helpers/ota.js.map +1 -1
- package/dist/controller/helpers/zclFrameConverter.d.ts.map +1 -1
- package/dist/controller/helpers/zclFrameConverter.js +17 -16
- package/dist/controller/helpers/zclFrameConverter.js.map +1 -1
- package/dist/controller/model/device.d.ts +14 -4
- package/dist/controller/model/device.d.ts.map +1 -1
- package/dist/controller/model/device.js +167 -85
- package/dist/controller/model/device.js.map +1 -1
- package/dist/controller/model/endpoint.d.ts +7 -3
- package/dist/controller/model/endpoint.d.ts.map +1 -1
- package/dist/controller/model/endpoint.js +34 -21
- package/dist/controller/model/endpoint.js.map +1 -1
- package/dist/controller/model/group.d.ts +0 -1
- package/dist/controller/model/group.d.ts.map +1 -1
- package/dist/controller/model/group.js +14 -19
- package/dist/controller/model/group.js.map +1 -1
- package/dist/controller/touchlink.js +3 -3
- package/dist/controller/touchlink.js.map +1 -1
- package/dist/utils/timeService.js +2 -2
- package/dist/utils/timeService.js.map +1 -1
- package/dist/zspec/zcl/buffaloZcl.d.ts +3 -3
- package/dist/zspec/zcl/buffaloZcl.d.ts.map +1 -1
- package/dist/zspec/zcl/buffaloZcl.js +198 -96
- package/dist/zspec/zcl/buffaloZcl.js.map +1 -1
- package/dist/zspec/zcl/definition/cluster.d.ts +2 -2
- package/dist/zspec/zcl/definition/cluster.d.ts.map +1 -1
- package/dist/zspec/zcl/definition/cluster.js +2699 -2808
- package/dist/zspec/zcl/definition/cluster.js.map +1 -1
- package/dist/zspec/zcl/definition/clusters-types.d.ts +63 -1109
- package/dist/zspec/zcl/definition/clusters-types.d.ts.map +1 -1
- package/dist/zspec/zcl/definition/enums.d.ts +0 -1
- package/dist/zspec/zcl/definition/enums.d.ts.map +1 -1
- package/dist/zspec/zcl/definition/enums.js +0 -1
- package/dist/zspec/zcl/definition/enums.js.map +1 -1
- package/dist/zspec/zcl/definition/foundation.d.ts +306 -7
- package/dist/zspec/zcl/definition/foundation.d.ts.map +1 -1
- package/dist/zspec/zcl/definition/foundation.js +552 -207
- package/dist/zspec/zcl/definition/foundation.js.map +1 -1
- package/dist/zspec/zcl/definition/status.d.ts +21 -10
- package/dist/zspec/zcl/definition/status.d.ts.map +1 -1
- package/dist/zspec/zcl/definition/status.js +11 -0
- package/dist/zspec/zcl/definition/status.js.map +1 -1
- package/dist/zspec/zcl/definition/tstype.d.ts +57 -48
- package/dist/zspec/zcl/definition/tstype.d.ts.map +1 -1
- package/dist/zspec/zcl/utils.d.ts +7 -4
- package/dist/zspec/zcl/utils.d.ts.map +1 -1
- package/dist/zspec/zcl/utils.js +133 -240
- package/dist/zspec/zcl/utils.js.map +1 -1
- package/dist/zspec/zcl/zclFrame.d.ts +4 -4
- package/dist/zspec/zcl/zclFrame.d.ts.map +1 -1
- package/dist/zspec/zcl/zclFrame.js +19 -103
- package/dist/zspec/zcl/zclFrame.js.map +1 -1
- package/dist/zspec/zcl/zclStatusError.d.ts +1 -1
- package/dist/zspec/zcl/zclStatusError.d.ts.map +1 -1
- package/dist/zspec/zcl/zclStatusError.js +2 -2
- package/dist/zspec/zcl/zclStatusError.js.map +1 -1
- package/package.json +1 -1
- package/scripts/clusters-typegen.ts +44 -139
- package/src/adapter/adapter.ts +38 -3
- package/src/adapter/adapterDiscovery.ts +2 -1
- package/src/adapter/deconz/adapter/deconzAdapter.ts +24 -51
- package/src/adapter/deconz/driver/constants.ts +1 -1
- package/src/adapter/ember/adapter/emberAdapter.ts +23 -10
- package/src/adapter/ember/adapter/oneWaitress.ts +16 -6
- package/src/adapter/ezsp/adapter/ezspAdapter.ts +27 -48
- package/src/adapter/ezsp/driver/index.ts +1 -1
- package/src/adapter/ezsp/driver/types/index.ts +99 -99
- package/src/adapter/serialPort.ts +9 -0
- package/src/adapter/z-stack/adapter/adapter-backup.ts +1 -1
- package/src/adapter/z-stack/adapter/adapter-nv-memory.ts +1 -1
- package/src/adapter/z-stack/adapter/manager.ts +16 -2
- package/src/adapter/z-stack/adapter/tstype.ts +1 -0
- package/src/adapter/z-stack/adapter/zStackAdapter.ts +34 -81
- package/src/adapter/z-stack/constants/index.ts +1 -1
- package/src/adapter/z-stack/unpi/constants.ts +1 -1
- package/src/adapter/zboss/adapter/zbossAdapter.ts +23 -54
- package/src/adapter/zboss/driver.ts +8 -1
- package/src/adapter/zboss/uart.ts +14 -1
- package/src/adapter/zigate/adapter/zigateAdapter.ts +17 -48
- package/src/adapter/zoh/adapter/zohAdapter.ts +27 -50
- package/src/controller/controller.ts +12 -2
- package/src/controller/greenPower.ts +16 -9
- package/src/controller/helpers/ota.ts +37 -11
- package/src/controller/helpers/zclFrameConverter.ts +20 -17
- package/src/controller/model/device.ts +204 -97
- package/src/controller/model/endpoint.ts +36 -24
- package/src/controller/model/group.ts +14 -20
- package/src/controller/touchlink.ts +3 -3
- package/src/utils/timeService.ts +2 -2
- package/src/zspec/zcl/buffaloZcl.ts +226 -100
- package/src/zspec/zcl/definition/cluster.ts +2713 -2822
- package/src/zspec/zcl/definition/clusters-types.ts +80 -1135
- package/src/zspec/zcl/definition/enums.ts +0 -1
- package/src/zspec/zcl/definition/foundation.ts +703 -216
- package/src/zspec/zcl/definition/status.ts +22 -11
- package/src/zspec/zcl/definition/tstype.ts +59 -58
- package/src/zspec/zcl/utils.ts +137 -264
- package/src/zspec/zcl/zclFrame.ts +25 -130
- package/src/zspec/zcl/zclStatusError.ts +2 -2
- package/test/adapter/ember/emberAdapter.test.ts +191 -4
- package/test/adapter/ezsp/uart.test.ts +10 -10
- package/test/adapter/z-stack/adapter.test.ts +88 -32
- package/test/adapter/zoh/zohAdapter.test.ts +4 -4
- package/test/controller.test.ts +822 -248
- package/test/device-ota.test.ts +141 -16
- package/test/device.test.ts +731 -0
- package/test/requests.bench.ts +2 -0
- package/test/zcl.test.ts +70 -95
- package/test/zspec/zcl/buffalo.test.ts +251 -11
- package/test/zspec/zcl/foundation.test.ts +990 -0
- package/test/zspec/zcl/frame.test.ts +84 -69
- package/test/zspec/zcl/utils.test.ts +105 -81
- package/tsconfig.json +0 -1
- package/scripts/check-clusters-changes.ts +0 -328
- package/scripts/clusters-changes.log +0 -584
- package/scripts/utils.ts +0 -88
- package/scripts/zap-update-clusters-report.json +0 -303
- package/scripts/zap-update-clusters.ts +0 -1520
- package/scripts/zap-update-types.ts +0 -707
- package/scripts/zap-xml-clusters-overrides-data.ts +0 -52
- package/scripts/zap-xml-clusters-overrides.ts +0 -400
- package/scripts/zap-xml-types.ts +0 -146
|
@@ -1,707 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Script: Generate enums and interfaces from ZCL XML data type definitions.
|
|
3
|
-
*
|
|
4
|
-
* Goals:
|
|
5
|
-
* - Parse XML cluster definition files (library.xml and its includes).
|
|
6
|
-
* - Respect XSD-described structure (type.xsd).
|
|
7
|
-
* - For <type:type> with <restriction><type:enumeration>, create a TS enum.
|
|
8
|
-
* - For <type:type> with <bitmap><element>, create a TS enum (for flags).
|
|
9
|
-
* - For <type:type> with <restriction><sequence>, create a TS interface.
|
|
10
|
-
* - Parse inline type definitions within attributes and command fields.
|
|
11
|
-
* - Write the generated code to a new file.
|
|
12
|
-
*
|
|
13
|
-
* Requirements:
|
|
14
|
-
* pnpm i xml2js @types/xml2js
|
|
15
|
-
*
|
|
16
|
-
* Usage:
|
|
17
|
-
* tsx scripts/zap-update-types.ts ../zap/zcl-builtin/dotdot
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
import {promises as fs} from "node:fs";
|
|
21
|
-
import path from "node:path";
|
|
22
|
-
import process from "node:process";
|
|
23
|
-
import ts from "typescript";
|
|
24
|
-
import {parseStringPromise} from "xml2js";
|
|
25
|
-
import type {XMLAttr, XMLBitmapDefinition, XMLClusterSide, XMLEnumeration, XMLRestriction, XMLRoot, XMLSequence, XMLTypeType} from "./zap-xml-types";
|
|
26
|
-
|
|
27
|
-
// #region Type Definitions
|
|
28
|
-
|
|
29
|
-
interface ParsedXMLTypeType extends XMLTypeType {
|
|
30
|
-
clusterName?: string;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
interface ParsedType {
|
|
34
|
-
name: string;
|
|
35
|
-
node: ts.EnumDeclaration | ts.InterfaceDeclaration | ts.TypeAliasDeclaration | ts.VariableStatement;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// #endregion
|
|
39
|
-
|
|
40
|
-
// #region Helpers
|
|
41
|
-
|
|
42
|
-
const NUMBER_TO_WORD: Record<string, string> = {
|
|
43
|
-
"0": "Zero",
|
|
44
|
-
"1": "One",
|
|
45
|
-
"2": "Two",
|
|
46
|
-
"3": "Three",
|
|
47
|
-
"4": "Four",
|
|
48
|
-
"5": "Five",
|
|
49
|
-
"6": "Six",
|
|
50
|
-
"7": "Seven",
|
|
51
|
-
"8": "Eight",
|
|
52
|
-
"9": "Nine",
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
const NAME_OVERRIDES: Record<string, string> = {
|
|
56
|
-
CCColorOptions: "ColorControlColorOptions",
|
|
57
|
-
CCDirection: "ColorControlDirection",
|
|
58
|
-
CCMoveMode: "ColorControlMoveMode",
|
|
59
|
-
CCStepMode: "ColorControlStepMode",
|
|
60
|
-
CCColorLoopDirection: "ColorControlColorLoopDirection",
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Converts a string to PascalCase.
|
|
65
|
-
* Handles various delimiters like spaces, hyphens, and underscores.
|
|
66
|
-
* Sanitizes names that start with a number.
|
|
67
|
-
* @param str The input string.
|
|
68
|
-
* @returns The PascalCased string.
|
|
69
|
-
*/
|
|
70
|
-
function pascalCase(str: string): string {
|
|
71
|
-
if (!str) {
|
|
72
|
-
return "";
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
let sanitized = str.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/[^0-9a-zA-Z]/g, " ");
|
|
76
|
-
const firstChar = sanitized.charAt(0);
|
|
77
|
-
|
|
78
|
-
if (NUMBER_TO_WORD[firstChar]) {
|
|
79
|
-
sanitized = `${NUMBER_TO_WORD[firstChar]}${sanitized.slice(1)}`;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
return sanitized
|
|
83
|
-
.trim()
|
|
84
|
-
.split(" ")
|
|
85
|
-
.map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
|
|
86
|
-
.join("");
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/** Only uppercase first char after sanitized */
|
|
90
|
-
function simplePascalCase(str: string): string {
|
|
91
|
-
if (!str) {
|
|
92
|
-
return "";
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
const override = NAME_OVERRIDES[str];
|
|
96
|
-
|
|
97
|
-
if (override) {
|
|
98
|
-
return override;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
const sanitized = str.replace(/[^0-9a-zA-Z]/g, "");
|
|
102
|
-
|
|
103
|
-
return `${sanitized.charAt(0).toUpperCase()}${sanitized.slice(1)}`;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Converts a string to camelCase.
|
|
108
|
-
* @param str The input string.
|
|
109
|
-
* @returns The camelCased string.
|
|
110
|
-
*/
|
|
111
|
-
function camelCase(str: string): string {
|
|
112
|
-
if (!str) {
|
|
113
|
-
return "";
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
const pascal = simplePascalCase(str);
|
|
117
|
-
|
|
118
|
-
return pascal.charAt(0).toLowerCase() + pascal.slice(1);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Converts a hex or decimal string to a 0x-prefixed hex string.
|
|
123
|
-
* @param value The input string (e.g., "01", "ff", "255").
|
|
124
|
-
* @param pad4 If true pad to 4-digit instead of 2.
|
|
125
|
-
* @returns The formatted hex string (e.g., "0x01", "0xFF").
|
|
126
|
-
*/
|
|
127
|
-
function toHex(value: string, pad4 = false): string {
|
|
128
|
-
if (!value) {
|
|
129
|
-
return "0x00";
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
const num = Number.parseInt(value, 16);
|
|
133
|
-
|
|
134
|
-
if (Number.isNaN(num)) {
|
|
135
|
-
return "0x00";
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
return `0x${num.toString(16).padStart(pad4 ? 4 : 2, "0")}`;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
// #endregion
|
|
142
|
-
|
|
143
|
-
// #region XML Parsing and Type Collection
|
|
144
|
-
|
|
145
|
-
const createSyntheticType = (
|
|
146
|
-
clusterName: string,
|
|
147
|
-
name: string,
|
|
148
|
-
parent: XMLAttr<{type: string}> & {restriction?: XMLRestriction[]; bitmap?: XMLBitmapDefinition[]},
|
|
149
|
-
): ParsedXMLTypeType | undefined => {
|
|
150
|
-
if (parent.restriction || parent.bitmap) {
|
|
151
|
-
return {
|
|
152
|
-
// biome-ignore lint/style/useNamingConvention: API
|
|
153
|
-
$: {id: "", name: name, short: name, inheritsFrom: parent.$.type},
|
|
154
|
-
clusterName: clusterName,
|
|
155
|
-
restriction: parent.restriction,
|
|
156
|
-
bitmap: parent.bitmap,
|
|
157
|
-
};
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
return undefined;
|
|
161
|
-
};
|
|
162
|
-
|
|
163
|
-
async function collectAllTypes(startFile: string): Promise<ParsedXMLTypeType[]> {
|
|
164
|
-
const allTypes: ParsedXMLTypeType[] = [];
|
|
165
|
-
const visitedFiles = new Set<string>();
|
|
166
|
-
const filesToProcess: string[] = [startFile];
|
|
167
|
-
|
|
168
|
-
const processSide = (clusterName: string, side: XMLClusterSide | undefined) => {
|
|
169
|
-
if (!side) {
|
|
170
|
-
return;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
if (side.attributes) {
|
|
174
|
-
for (const attr of side.attributes[0].attribute) {
|
|
175
|
-
const synthetic = createSyntheticType(clusterName, attr.$.name, attr);
|
|
176
|
-
|
|
177
|
-
if (synthetic) {
|
|
178
|
-
allTypes.push(synthetic);
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
if (side.commands) {
|
|
184
|
-
for (const cmd of side.commands[0].command) {
|
|
185
|
-
if (cmd.fields) {
|
|
186
|
-
for (const field of cmd.fields[0].field) {
|
|
187
|
-
const synthetic = createSyntheticType(clusterName, field.$.name, field);
|
|
188
|
-
|
|
189
|
-
if (synthetic) {
|
|
190
|
-
allTypes.push(synthetic);
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
};
|
|
197
|
-
|
|
198
|
-
while (filesToProcess.length > 0) {
|
|
199
|
-
const currentFile = filesToProcess.shift();
|
|
200
|
-
|
|
201
|
-
if (!currentFile || visitedFiles.has(currentFile)) {
|
|
202
|
-
continue;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
visitedFiles.add(currentFile);
|
|
206
|
-
|
|
207
|
-
try {
|
|
208
|
-
const xmlContent = await fs.readFile(currentFile, "utf-8");
|
|
209
|
-
const parsed = (await parseStringPromise(xmlContent, {
|
|
210
|
-
explicitArray: true,
|
|
211
|
-
mergeAttrs: false,
|
|
212
|
-
explicitRoot: true,
|
|
213
|
-
})) as XMLRoot;
|
|
214
|
-
const libraries = parsed["zcl:library"];
|
|
215
|
-
const global = parsed["zcl:global"];
|
|
216
|
-
const clusters = parsed["zcl:cluster"];
|
|
217
|
-
|
|
218
|
-
if (libraries) {
|
|
219
|
-
for (const lib of Array.isArray(libraries) ? libraries : [libraries]) {
|
|
220
|
-
if (lib["type:type"]) {
|
|
221
|
-
allTypes.push(...lib["type:type"]);
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
if (lib["xi:include"]) {
|
|
225
|
-
const baseDir = path.dirname(currentFile);
|
|
226
|
-
|
|
227
|
-
for (const include of lib["xi:include"]) {
|
|
228
|
-
if (include.$.href && include.$.parse === "xml") {
|
|
229
|
-
filesToProcess.push(path.resolve(baseDir, include.$.href));
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
if (global) {
|
|
237
|
-
for (const lib of Array.isArray(global) ? global : [global]) {
|
|
238
|
-
if (lib["type:type"]) {
|
|
239
|
-
allTypes.push(...lib["type:type"]);
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
if (clusters) {
|
|
245
|
-
for (const cluster of Array.isArray(clusters) ? clusters : [clusters]) {
|
|
246
|
-
if (cluster["type:type"]) {
|
|
247
|
-
for (const type of cluster["type:type"]) {
|
|
248
|
-
allTypes.push({...type, clusterName: cluster.$.name});
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
if (cluster.server) {
|
|
253
|
-
processSide(cluster.$.name, cluster.server[0]);
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
if (cluster.client) {
|
|
257
|
-
processSide(cluster.$.name, cluster.client[0]);
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
} catch (error) {
|
|
262
|
-
console.error(`Error processing file ${currentFile}:`, error);
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
return allTypes;
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
class TypeResolver {
|
|
270
|
-
#typesByShort = new Map<string, ParsedXMLTypeType>();
|
|
271
|
-
|
|
272
|
-
add(types: ParsedXMLTypeType[]): void {
|
|
273
|
-
for (const type of types) {
|
|
274
|
-
const short = type.$.short.toLowerCase();
|
|
275
|
-
|
|
276
|
-
if (!this.#typesByShort.has(short)) {
|
|
277
|
-
this.#typesByShort.set(short, type);
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
resolve(short: string, factory: ts.NodeFactory): ts.TypeNode {
|
|
283
|
-
const type = this.#typesByShort.get(short.toLowerCase());
|
|
284
|
-
|
|
285
|
-
if (type?.$.inheritsFrom && !type.restriction?.some((r) => r["type:sequence"])) {
|
|
286
|
-
return this.resolve(type.$.inheritsFrom, factory);
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
switch (short.toLowerCase()) {
|
|
290
|
-
case "data8":
|
|
291
|
-
case "data16":
|
|
292
|
-
case "data24":
|
|
293
|
-
case "data32":
|
|
294
|
-
case "data40":
|
|
295
|
-
case "data48":
|
|
296
|
-
case "data56":
|
|
297
|
-
case "data64":
|
|
298
|
-
case "bool":
|
|
299
|
-
case "map8":
|
|
300
|
-
case "map16":
|
|
301
|
-
case "map24":
|
|
302
|
-
case "map32":
|
|
303
|
-
case "map40":
|
|
304
|
-
case "map48":
|
|
305
|
-
case "map56":
|
|
306
|
-
case "map64":
|
|
307
|
-
case "uint8":
|
|
308
|
-
case "uint16":
|
|
309
|
-
case "uint24":
|
|
310
|
-
case "uint32":
|
|
311
|
-
case "uint40":
|
|
312
|
-
case "uint48":
|
|
313
|
-
case "uint56":
|
|
314
|
-
case "uint64":
|
|
315
|
-
case "int8":
|
|
316
|
-
case "int16":
|
|
317
|
-
case "int24":
|
|
318
|
-
case "int32":
|
|
319
|
-
case "int40":
|
|
320
|
-
case "int48":
|
|
321
|
-
case "int56":
|
|
322
|
-
case "int64":
|
|
323
|
-
case "enum8":
|
|
324
|
-
case "enum16":
|
|
325
|
-
case "semi":
|
|
326
|
-
case "single":
|
|
327
|
-
case "double":
|
|
328
|
-
case "utc":
|
|
329
|
-
case "clusterid":
|
|
330
|
-
case "attribid":
|
|
331
|
-
case "bacoid":
|
|
332
|
-
return factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword);
|
|
333
|
-
|
|
334
|
-
case "octstr":
|
|
335
|
-
case "string":
|
|
336
|
-
case "octstr16":
|
|
337
|
-
case "string16":
|
|
338
|
-
return factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword);
|
|
339
|
-
|
|
340
|
-
case "array":
|
|
341
|
-
case "set":
|
|
342
|
-
case "bag":
|
|
343
|
-
return factory.createArrayTypeNode(factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword));
|
|
344
|
-
|
|
345
|
-
case "eui64":
|
|
346
|
-
return factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword);
|
|
347
|
-
case "key128":
|
|
348
|
-
return factory.createTypeReferenceNode("Buffer");
|
|
349
|
-
|
|
350
|
-
default:
|
|
351
|
-
if (type && type.$.short !== "unk") {
|
|
352
|
-
return factory.createTypeReferenceNode(simplePascalCase(type.$.short));
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
return factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword);
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
// #endregion
|
|
361
|
-
|
|
362
|
-
// #region AST Generation
|
|
363
|
-
|
|
364
|
-
function addComments(_factory: ts.NodeFactory, node: ts.Node, type: ParsedXMLTypeType, noType = false): void {
|
|
365
|
-
const comments: string[] = [];
|
|
366
|
-
|
|
367
|
-
if (type.clusterName) {
|
|
368
|
-
comments.push(`@cluster ${type.clusterName}`);
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
if (type.$.inheritsFrom && !noType) {
|
|
372
|
-
comments.push(`@type ${type.$.inheritsFrom}`);
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
if (comments.length > 0) {
|
|
376
|
-
const commentText = `*\n * ${comments.join("\n * ")}\n `;
|
|
377
|
-
|
|
378
|
-
ts.addSyntheticLeadingComment(node, ts.SyntaxKind.MultiLineCommentTrivia, commentText, true);
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
function createEnumFromEnumeration(factory: ts.NodeFactory, type: ParsedXMLTypeType, enumerations: XMLEnumeration[]): ts.EnumDeclaration {
|
|
383
|
-
const memberNames = new Map<string, number>();
|
|
384
|
-
const members: ts.EnumMember[] = [];
|
|
385
|
-
|
|
386
|
-
for (const e of enumerations) {
|
|
387
|
-
let memberName = pascalCase(e.$.name);
|
|
388
|
-
const count = memberNames.get(memberName);
|
|
389
|
-
|
|
390
|
-
if (count !== undefined) {
|
|
391
|
-
memberNames.set(memberName, count + 1);
|
|
392
|
-
|
|
393
|
-
memberName = `${memberName}${count + 1}`;
|
|
394
|
-
} else {
|
|
395
|
-
memberNames.set(memberName, 1);
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
const memberValue = factory.createNumericLiteral(toHex(e.$.value, type.$.inheritsFrom?.endsWith("16")));
|
|
399
|
-
|
|
400
|
-
members.push(factory.createEnumMember(memberName, memberValue));
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
const enumDeclaration = factory.createEnumDeclaration(
|
|
404
|
-
[factory.createToken(ts.SyntaxKind.ExportKeyword)],
|
|
405
|
-
simplePascalCase(type.$.short),
|
|
406
|
-
members,
|
|
407
|
-
);
|
|
408
|
-
|
|
409
|
-
addComments(factory, enumDeclaration, type);
|
|
410
|
-
|
|
411
|
-
return enumDeclaration;
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
function createEnumFromBitmap(factory: ts.NodeFactory, type: ParsedXMLTypeType, bitmap: XMLBitmapDefinition, shiftRight = false): ts.EnumDeclaration {
|
|
415
|
-
const memberNames = new Map<string, number>();
|
|
416
|
-
const members: ts.EnumMember[] = [];
|
|
417
|
-
|
|
418
|
-
for (const e of bitmap.element) {
|
|
419
|
-
if (shiftRight && !e.$.shiftRight) {
|
|
420
|
-
continue;
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
let memberName = pascalCase(e.$.name);
|
|
424
|
-
const count = memberNames.get(memberName);
|
|
425
|
-
|
|
426
|
-
if (count !== undefined) {
|
|
427
|
-
memberNames.set(memberName, count + 1);
|
|
428
|
-
|
|
429
|
-
memberName = `${memberName}${count + 1}`;
|
|
430
|
-
} else {
|
|
431
|
-
memberNames.set(memberName, 1);
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
const memberValue = factory.createNumericLiteral(
|
|
435
|
-
// biome-ignore lint/style/noNonNullAssertion: valid from top of loop
|
|
436
|
-
toHex(shiftRight ? e.$.shiftRight! : e.$.mask, !shiftRight && type.$.inheritsFrom?.endsWith("16")),
|
|
437
|
-
);
|
|
438
|
-
|
|
439
|
-
members.push(factory.createEnumMember(memberName, memberValue));
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
const enumDeclaration = factory.createEnumDeclaration(
|
|
443
|
-
[factory.createToken(ts.SyntaxKind.ExportKeyword)],
|
|
444
|
-
simplePascalCase(
|
|
445
|
-
shiftRight
|
|
446
|
-
? type.$.short.endsWith("ShiftRight")
|
|
447
|
-
? type.$.short
|
|
448
|
-
: `${type.$.short.endsWith("Mask") ? type.$.short.slice(0, -4) : type.$.short}ShiftRight`
|
|
449
|
-
: type.$.short.endsWith("Mask")
|
|
450
|
-
? type.$.short
|
|
451
|
-
: `${type.$.short}Mask`,
|
|
452
|
-
),
|
|
453
|
-
members,
|
|
454
|
-
);
|
|
455
|
-
|
|
456
|
-
addComments(factory, enumDeclaration, type, shiftRight);
|
|
457
|
-
|
|
458
|
-
return enumDeclaration;
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
function createInterfaceFromSequence(
|
|
462
|
-
factory: ts.NodeFactory,
|
|
463
|
-
type: ParsedXMLTypeType,
|
|
464
|
-
sequence: XMLSequence,
|
|
465
|
-
resolver: TypeResolver,
|
|
466
|
-
): ts.InterfaceDeclaration {
|
|
467
|
-
const memberNames = new Map<string, number>();
|
|
468
|
-
const members: ts.PropertySignature[] = [];
|
|
469
|
-
|
|
470
|
-
for (const f of sequence.field) {
|
|
471
|
-
let propertyName = camelCase(f.$.name);
|
|
472
|
-
const count = memberNames.get(propertyName);
|
|
473
|
-
|
|
474
|
-
if (count !== undefined) {
|
|
475
|
-
memberNames.set(propertyName, count + 1);
|
|
476
|
-
|
|
477
|
-
propertyName = `${propertyName}${count + 1}`;
|
|
478
|
-
} else {
|
|
479
|
-
memberNames.set(propertyName, 1);
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
const propertyType = resolver.resolve(f.$.type, factory);
|
|
483
|
-
|
|
484
|
-
members.push(
|
|
485
|
-
factory.createPropertySignature(
|
|
486
|
-
undefined,
|
|
487
|
-
propertyName,
|
|
488
|
-
f.$.presentIf ? factory.createToken(ts.SyntaxKind.QuestionToken) : undefined,
|
|
489
|
-
propertyType,
|
|
490
|
-
),
|
|
491
|
-
);
|
|
492
|
-
}
|
|
493
|
-
|
|
494
|
-
const interfaceDeclaration = factory.createInterfaceDeclaration(
|
|
495
|
-
[factory.createToken(ts.SyntaxKind.ExportKeyword)],
|
|
496
|
-
simplePascalCase(type.$.short),
|
|
497
|
-
undefined,
|
|
498
|
-
undefined,
|
|
499
|
-
members,
|
|
500
|
-
);
|
|
501
|
-
|
|
502
|
-
addComments(factory, interfaceDeclaration, type);
|
|
503
|
-
|
|
504
|
-
return interfaceDeclaration;
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
function createSafeNumericLiteral(value: string | number, bigInt: boolean, factory: ts.NodeFactory): ts.Expression {
|
|
508
|
-
if (bigInt) {
|
|
509
|
-
const num = BigInt(value);
|
|
510
|
-
const str = String(value);
|
|
511
|
-
|
|
512
|
-
return factory.createBigIntLiteral({base10Value: num < 0 ? str.slice(1) : str, negative: num < 0});
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
const num = Number(value);
|
|
516
|
-
|
|
517
|
-
if (num < 0) {
|
|
518
|
-
return factory.createPrefixUnaryExpression(ts.SyntaxKind.MinusToken, factory.createNumericLiteral(Math.abs(num)));
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
return factory.createNumericLiteral(num);
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
function createZclTypeInvalidConstants(
|
|
525
|
-
factory: ts.NodeFactory,
|
|
526
|
-
types: ParsedXMLTypeType[],
|
|
527
|
-
): [byName: ts.VariableStatement, byType: ts.VariableStatement] | undefined {
|
|
528
|
-
const zclType = types.find((t) => t.$.short === "zclType");
|
|
529
|
-
|
|
530
|
-
if (!zclType?.restriction?.[0]?.["type:enumeration"]) {
|
|
531
|
-
return undefined;
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
const zclTypeEnumMap = new Map(zclType.restriction[0]["type:enumeration"].map((e) => [e.$.name, e.$.value]));
|
|
535
|
-
const byNameProperties: ts.PropertyAssignment[] = [];
|
|
536
|
-
const byTypeProperties: ts.PropertyAssignment[] = [];
|
|
537
|
-
|
|
538
|
-
for (const type of types) {
|
|
539
|
-
const invalidValue = type.restriction?.[0]?.["type:invalid"]?.[0]?.$?.value;
|
|
540
|
-
const typeId = zclTypeEnumMap.get(type.$.short);
|
|
541
|
-
|
|
542
|
-
if (invalidValue && typeId) {
|
|
543
|
-
const name = pascalCase(type.$.short);
|
|
544
|
-
const invalidValueLiteral = createSafeNumericLiteral(invalidValue, name.endsWith("56") || name.endsWith("64"), factory);
|
|
545
|
-
|
|
546
|
-
byNameProperties.push(factory.createPropertyAssignment(factory.createIdentifier(name), invalidValueLiteral));
|
|
547
|
-
|
|
548
|
-
const byTypeProp = factory.createPropertyAssignment(factory.createNumericLiteral(Number.parseInt(typeId, 16)), invalidValueLiteral);
|
|
549
|
-
const commentText = `* ${name} `;
|
|
550
|
-
|
|
551
|
-
ts.addSyntheticLeadingComment(byTypeProp, ts.SyntaxKind.MultiLineCommentTrivia, commentText, true);
|
|
552
|
-
byTypeProperties.push(byTypeProp);
|
|
553
|
-
}
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
const invalidVal = factory.createUnionTypeNode([
|
|
557
|
-
factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword),
|
|
558
|
-
factory.createKeywordTypeNode(ts.SyntaxKind.BigIntKeyword),
|
|
559
|
-
]);
|
|
560
|
-
const byNameCommentText = "* ZCL non-values by type name (key of `ZclType`). ";
|
|
561
|
-
const byNameConst = factory.createVariableStatement(
|
|
562
|
-
[factory.createToken(ts.SyntaxKind.ExportKeyword)],
|
|
563
|
-
factory.createVariableDeclarationList(
|
|
564
|
-
[
|
|
565
|
-
factory.createVariableDeclaration(
|
|
566
|
-
"ZCL_TYPE_INVALID_BY_TYPE_NAME",
|
|
567
|
-
undefined,
|
|
568
|
-
factory.createTypeReferenceNode("Readonly", [
|
|
569
|
-
factory.createTypeReferenceNode("Record", [factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword), invalidVal]),
|
|
570
|
-
]),
|
|
571
|
-
factory.createObjectLiteralExpression(byNameProperties, true),
|
|
572
|
-
),
|
|
573
|
-
],
|
|
574
|
-
ts.NodeFlags.Const,
|
|
575
|
-
),
|
|
576
|
-
);
|
|
577
|
-
const byTypeCommentText = "* ZCL non-values by type ID (value of `ZclType`). ";
|
|
578
|
-
const byTypeConst = factory.createVariableStatement(
|
|
579
|
-
[factory.createToken(ts.SyntaxKind.ExportKeyword)],
|
|
580
|
-
factory.createVariableDeclarationList(
|
|
581
|
-
[
|
|
582
|
-
factory.createVariableDeclaration(
|
|
583
|
-
"ZCL_TYPE_INVALID_BY_TYPE",
|
|
584
|
-
undefined,
|
|
585
|
-
factory.createTypeReferenceNode("Readonly", [
|
|
586
|
-
factory.createTypeReferenceNode("Record", [factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword), invalidVal]),
|
|
587
|
-
]),
|
|
588
|
-
factory.createObjectLiteralExpression(byTypeProperties, true),
|
|
589
|
-
),
|
|
590
|
-
],
|
|
591
|
-
ts.NodeFlags.Const,
|
|
592
|
-
),
|
|
593
|
-
);
|
|
594
|
-
|
|
595
|
-
ts.addSyntheticLeadingComment(byNameConst, ts.SyntaxKind.MultiLineCommentTrivia, byNameCommentText, true);
|
|
596
|
-
ts.addSyntheticLeadingComment(byTypeConst, ts.SyntaxKind.MultiLineCommentTrivia, byTypeCommentText, true);
|
|
597
|
-
|
|
598
|
-
return [byNameConst, byTypeConst];
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
function processTypes(factory: ts.NodeFactory, types: ParsedXMLTypeType[], resolver: TypeResolver): ParsedType[] {
|
|
602
|
-
const processed: ParsedType[] = [];
|
|
603
|
-
const processedNames = new Set<string>();
|
|
604
|
-
|
|
605
|
-
for (const type of types) {
|
|
606
|
-
const name = simplePascalCase(type.$.short);
|
|
607
|
-
|
|
608
|
-
if (processedNames.has(name)) {
|
|
609
|
-
continue;
|
|
610
|
-
}
|
|
611
|
-
|
|
612
|
-
const restriction = type.restriction?.[0];
|
|
613
|
-
const bitmap = type.bitmap?.[0];
|
|
614
|
-
|
|
615
|
-
if (restriction?.["type:enumeration"]) {
|
|
616
|
-
const createdNode = createEnumFromEnumeration(factory, type, restriction["type:enumeration"]);
|
|
617
|
-
|
|
618
|
-
if (createdNode.members.length > 0) {
|
|
619
|
-
processed.push({name, node: createdNode});
|
|
620
|
-
processedNames.add(name);
|
|
621
|
-
}
|
|
622
|
-
} else if (bitmap?.element) {
|
|
623
|
-
const createdNode = createEnumFromBitmap(factory, type, bitmap);
|
|
624
|
-
|
|
625
|
-
if (createdNode.members.length > 0) {
|
|
626
|
-
processed.push({name: `${name}Mask`, node: createdNode});
|
|
627
|
-
processedNames.add(name);
|
|
628
|
-
}
|
|
629
|
-
|
|
630
|
-
const createdNodeShiftRight = createEnumFromBitmap(factory, type, bitmap, true);
|
|
631
|
-
|
|
632
|
-
if (createdNodeShiftRight.members.length > 0) {
|
|
633
|
-
processed.push({name: `${name}ShiftRight`, node: createdNodeShiftRight});
|
|
634
|
-
processedNames.add(name);
|
|
635
|
-
}
|
|
636
|
-
} else if (restriction?.["type:sequence"]) {
|
|
637
|
-
const createdNode = createInterfaceFromSequence(factory, type, restriction["type:sequence"][0], resolver);
|
|
638
|
-
|
|
639
|
-
if (createdNode.members.length > 0) {
|
|
640
|
-
processed.push({name, node: createdNode});
|
|
641
|
-
processedNames.add(name);
|
|
642
|
-
}
|
|
643
|
-
}
|
|
644
|
-
}
|
|
645
|
-
|
|
646
|
-
const zclTypeInvalidConsts = createZclTypeInvalidConstants(factory, types);
|
|
647
|
-
|
|
648
|
-
if (zclTypeInvalidConsts) {
|
|
649
|
-
processed.push({name: "ZCL_TYPE_INVALID_BY_TYPE_NAME", node: zclTypeInvalidConsts[0]});
|
|
650
|
-
processed.push({name: "ZCL_TYPE_INVALID_BY_TYPE", node: zclTypeInvalidConsts[1]});
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
return processed;
|
|
654
|
-
}
|
|
655
|
-
|
|
656
|
-
// #endregion
|
|
657
|
-
|
|
658
|
-
// #region Main
|
|
659
|
-
|
|
660
|
-
async function main(): Promise<void> {
|
|
661
|
-
const args = process.argv.slice(2);
|
|
662
|
-
|
|
663
|
-
if (args.length !== 1) {
|
|
664
|
-
throw new Error("Usage: tsx scripts/zap-update-types.ts <path-to-xml-files>");
|
|
665
|
-
}
|
|
666
|
-
|
|
667
|
-
const xmlPath = args[0];
|
|
668
|
-
const libraryFile = path.join(xmlPath, "library.xml");
|
|
669
|
-
const outputFile = "src/zspec/zcl/definition/datatypes.ts";
|
|
670
|
-
|
|
671
|
-
console.log(`Starting type generation from ${libraryFile}...`);
|
|
672
|
-
|
|
673
|
-
const allTypes = await collectAllTypes(libraryFile);
|
|
674
|
-
|
|
675
|
-
if (allTypes.length === 0) {
|
|
676
|
-
console.log("No types found to process.");
|
|
677
|
-
|
|
678
|
-
return;
|
|
679
|
-
}
|
|
680
|
-
|
|
681
|
-
const resolver = new TypeResolver();
|
|
682
|
-
|
|
683
|
-
resolver.add(allTypes);
|
|
684
|
-
|
|
685
|
-
const factory = ts.factory;
|
|
686
|
-
const processedTypes = processTypes(factory, allTypes, resolver);
|
|
687
|
-
const nodesToPrint = processedTypes.map((p) => p.node);
|
|
688
|
-
const sourceFile = ts.createSourceFile(outputFile, "", ts.ScriptTarget.Latest, false, ts.ScriptKind.TS);
|
|
689
|
-
const printer = ts.createPrinter({newLine: ts.NewLineKind.LineFeed, removeComments: false});
|
|
690
|
-
const content = nodesToPrint.map((node) => printer.printNode(ts.EmitHint.Unspecified, node, sourceFile)).join("\n\n");
|
|
691
|
-
const fileHeader = `/**
|
|
692
|
-
* This file was automatically generated by scripts/zap-update-types.ts. Do NOT edit manually.
|
|
693
|
-
*
|
|
694
|
-
* ZCL data type definitions.
|
|
695
|
-
*/\n\n`;
|
|
696
|
-
|
|
697
|
-
await fs.writeFile(outputFile, `${fileHeader + content}\n`, "utf8");
|
|
698
|
-
|
|
699
|
-
console.log(`Successfully generated ${processedTypes.length} types to ${outputFile}.`);
|
|
700
|
-
}
|
|
701
|
-
|
|
702
|
-
main().catch((err) => {
|
|
703
|
-
console.error(err);
|
|
704
|
-
process.exit(1);
|
|
705
|
-
});
|
|
706
|
-
|
|
707
|
-
// #endregion
|