@deconz-community/ddf-validator 2.16.0 → 2.18.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.
@@ -1,11 +1,12 @@
1
1
  import { z as e } from "zod";
2
- const E = "2.16.0", y = {
2
+ const E = "2.18.0", y = {
3
3
  "devcap1.schema.json": [
4
4
  O,
5
5
  _,
6
6
  $,
7
7
  w,
8
- C
8
+ C,
9
+ A
9
10
  ],
10
11
  "constants2.schema.json": [
11
12
  T
@@ -15,8 +16,8 @@ function O(t, a, u) {
15
16
  const n = typeof t.manufacturername == "string" && typeof t.modelid == "string";
16
17
  if (n)
17
18
  return;
18
- const c = Array.isArray(t.manufacturername) && Array.isArray(t.modelid);
19
- if (c && t.manufacturername.length !== t.modelid.length) {
19
+ const d = Array.isArray(t.manufacturername) && Array.isArray(t.modelid);
20
+ if (d && t.manufacturername.length !== t.modelid.length) {
20
21
  a.addIssue({
21
22
  code: e.ZodIssueCode.invalid_intersection_types,
22
23
  message: "When 'manufacturername' and 'modelid' are both arrays they should be the same length",
@@ -24,7 +25,7 @@ function O(t, a, u) {
24
25
  });
25
26
  return;
26
27
  }
27
- (n || c) === !1 && a.addIssue({
28
+ (n || d) === !1 && a.addIssue({
28
29
  code: e.ZodIssueCode.invalid_intersection_types,
29
30
  message: "Invalid properties 'manufacturername' and 'modelid' should have the same type",
30
31
  path: ["manufacturername", "modelid"]
@@ -33,22 +34,22 @@ function O(t, a, u) {
33
34
  function _(t, a, u) {
34
35
  if (!t.bindings)
35
36
  return;
36
- const n = (s) => `0x${(typeof s == "number" ? s : Number.parseInt(s, 16)).toString(16)}`, c = {};
37
- t.bindings.forEach((s) => {
38
- s.bind === "unicast" && s.report && s.report.forEach((d) => {
39
- d.max !== 65535 && (c[`${n(s["src.ep"])}.${n(s.cl)}.${n(d.at)}`] = d.max);
37
+ const n = (i) => `0x${(typeof i == "number" ? i : Number.parseInt(i, 16)).toString(16)}`, d = {};
38
+ t.bindings.forEach((i) => {
39
+ i.bind === "unicast" && i.report && i.report.forEach((l) => {
40
+ l.max !== 65535 && (d[`${n(i["src.ep"])}.${n(i.cl)}.${n(l.at)}`] = l.max);
40
41
  });
41
- }), t.subdevices.forEach((s, d) => {
42
- s.items.forEach((i, o) => {
43
- var l;
44
- if (i["refresh.interval"] && i.read && i.read.fn === "zcl") {
45
- const h = n(i.read.ep ?? ((l = s.fingerprint) == null ? void 0 : l.endpoint) ?? s.uuid[1]), b = Array.isArray(i.read.at) ? i.read.at : [i.read.at];
46
- for (let v = 0; v < b.length; v++) {
47
- const g = `${h}.${n(i.read.cl)}.${n(b[v])}`;
48
- c[g] !== void 0 && i["refresh.interval"] - 60 < c[g] && a.addIssue({
42
+ }), t.subdevices.forEach((i, l) => {
43
+ i.items.forEach((s, o) => {
44
+ var c;
45
+ if (s["refresh.interval"] && s.read && s.read.fn === "zcl") {
46
+ const b = n(s.read.ep ?? ((c = i.fingerprint) == null ? void 0 : c.endpoint) ?? i.uuid[1]), h = Array.isArray(s.read.at) ? s.read.at : [s.read.at];
47
+ for (let v = 0; v < h.length; v++) {
48
+ const g = `${b}.${n(s.read.cl)}.${n(h[v])}`;
49
+ d[g] !== void 0 && s["refresh.interval"] - 60 < d[g] && a.addIssue({
49
50
  code: e.ZodIssueCode.custom,
50
- message: `The refresh interval (${i["refresh.interval"]} - 60 = ${i["refresh.interval"] - 60}) should be greater than the binding max refresh value (${c[g]}) with a margin of 60 seconds`,
51
- path: ["subdevices", d, "items", o, "refresh.interval"]
51
+ message: `The refresh interval (${s["refresh.interval"]} - 60 = ${s["refresh.interval"] - 60}) should be greater than the binding max refresh value (${d[g]}) with a margin of 60 seconds`,
52
+ path: ["subdevices", l, "items", o, "refresh.interval"]
52
53
  });
53
54
  }
54
55
  }
@@ -146,41 +147,41 @@ function $(t, a, u) {
146
147
  }
147
148
  }
148
149
  }
149
- ], c = (s, d) => typeof s == "string" ? d(s) : Array.isArray(s) ? s.every((i) => c(i, d)) : "and" in s ? s.and.every((i) => c(i, d)) : "or" in s ? s.or.some((i) => c(i, d)) : !1;
150
- t.subdevices.forEach((s, d) => {
151
- const i = s.items.map((o) => o.name);
150
+ ], d = (i, l) => typeof i == "string" ? l(i) : Array.isArray(i) ? i.every((s) => d(s, l)) : "and" in i ? i.and.every((s) => d(s, l)) : "or" in i ? i.or.some((s) => d(s, l)) : !1;
151
+ t.subdevices.forEach((i, l) => {
152
+ const s = i.items.map((o) => o.name);
152
153
  n.forEach((o) => {
153
- (Object.keys(o.if).length === 0 || Object.entries(o.if).some(([l, h]) => {
154
- switch (l) {
154
+ (Object.keys(o.if).length === 0 || Object.entries(o.if).some(([c, b]) => {
155
+ switch (c) {
155
156
  case "type":
156
- return c(h, (b) => b === s.type);
157
+ return d(b, (h) => h === i.type);
157
158
  case "item":
158
- return c(h, (b) => i.includes(b));
159
+ return d(b, (h) => s.includes(h));
159
160
  default:
160
161
  return !1;
161
162
  }
162
- })) && (c(o.need.item, (l) => i.includes(l)) || a.addIssue({
163
+ })) && (d(o.need.item, (c) => s.includes(c)) || a.addIssue({
163
164
  code: e.ZodIssueCode.custom,
164
165
  message: `The device is missing some items because ${o.description}`,
165
- path: ["subdevices", d, "items"]
166
+ path: ["subdevices", l, "items"]
166
167
  }));
167
168
  });
168
169
  });
169
170
  }
170
171
  function w(t, a, u) {
171
172
  const n = ["parse", "write"];
172
- t.subdevices.forEach((c, s) => {
173
- c.items.forEach((d, i) => {
173
+ t.subdevices.forEach((d, i) => {
174
+ d.items.forEach((l, s) => {
174
175
  n.forEach((o) => {
175
- const l = d[o];
176
- l !== void 0 && (l.fn === void 0 || l.fn === "zcl" || l.fn === "zcl:attr" || l.fn === "zcl:cmd") && (l.eval === void 0 && l.script === void 0 && a.addIssue({
176
+ const c = l[o];
177
+ c !== void 0 && (c.fn === void 0 || c.fn === "zcl" || c.fn === "zcl:attr" || c.fn === "zcl:cmd") && (c.eval === void 0 && c.script === void 0 && a.addIssue({
177
178
  code: e.ZodIssueCode.custom,
178
179
  message: `The '${o}' function is missing 'eval' or 'script' option.`,
179
- path: ["subdevices", s, "items", i, o]
180
- }), l.eval !== void 0 && l.script !== void 0 && a.addIssue({
180
+ path: ["subdevices", i, "items", s, o]
181
+ }), c.eval !== void 0 && c.script !== void 0 && a.addIssue({
181
182
  code: e.ZodIssueCode.custom,
182
183
  message: `The '${o}' function is having both 'eval' and 'script' option.`,
183
- path: ["subdevices", s, "items", i, o]
184
+ path: ["subdevices", i, "items", s, o]
184
185
  }));
185
186
  });
186
187
  });
@@ -188,46 +189,58 @@ function w(t, a, u) {
188
189
  }
189
190
  function T(t, a, u) {
190
191
  const n = I();
191
- Object.keys(t).forEach((c) => {
192
- if (!Object.keys(n.shape).includes(c)) {
193
- if (!["$MF_", "$TYPE_"].some((s) => c.startsWith(s))) {
192
+ Object.keys(t).forEach((d) => {
193
+ if (!Object.keys(n.shape).includes(d)) {
194
+ if (!["$MF_", "$TYPE_"].some((i) => d.startsWith(i))) {
194
195
  a.addIssue({
195
196
  code: e.ZodIssueCode.custom,
196
197
  message: "The constant key should start with '$MF_' or '$TYPE_'",
197
- path: [c]
198
+ path: [d]
198
199
  });
199
200
  return;
200
201
  }
201
- typeof t[c] != "string" && a.addIssue({
202
+ typeof t[d] != "string" && a.addIssue({
202
203
  code: e.ZodIssueCode.custom,
203
204
  message: "The constant value should be a string",
204
- path: [c]
205
+ path: [d]
205
206
  });
206
207
  }
207
208
  });
208
209
  }
209
210
  function C(t, a, u) {
210
- t.subdevices.forEach((n, c) => {
211
- const s = u.subDevices[n.type];
212
- if (!s) {
211
+ t.subdevices.forEach((n, d) => {
212
+ const i = u.subDevices[n.type];
213
+ if (!i) {
213
214
  a.addIssue({
214
215
  code: e.ZodIssueCode.custom,
215
216
  message: `The device is missing the device definition for the type "${n.type}"`,
216
- path: ["subdevices", c, "items"]
217
+ path: ["subdevices", d, "items"]
217
218
  });
218
219
  return;
219
220
  }
220
- let d = s.items;
221
- s.items_optional && (d = d.filter((i) => !s.items_optional.includes(i))), d.forEach((i) => {
222
- n.items.find((o) => o.name === i) || a.addIssue({
221
+ let l = i.items;
222
+ i.items_optional && (l = l.filter((s) => !i.items_optional.includes(s))), l.forEach((s) => {
223
+ n.items.find((o) => o.name === s) || a.addIssue({
223
224
  code: e.ZodIssueCode.custom,
224
- message: `The device should have the item "${i}" because it is mandatory for devices of type "${n.type}"`,
225
- path: ["subdevices", c, "items"]
225
+ message: `The device should have the item "${s}" because it is mandatory for devices of type "${n.type}"`,
226
+ path: ["subdevices", d, "items"]
226
227
  });
227
228
  });
228
229
  });
229
230
  }
230
- function A(t) {
231
+ function A(t, a, u) {
232
+ t.subdevices.forEach((n, d) => {
233
+ const i = n.items.map((l) => l.name);
234
+ n.items.forEach((l, s) => {
235
+ l.parse && l.parse.fn === "numtostr" && (i.includes(l.parse.srcitem) || a.addIssue({
236
+ code: e.ZodIssueCode.custom,
237
+ message: `The device should have the item "${l.parse.srcitem}" because it is used in the 'numtostr' function`,
238
+ path: ["subdevices", d, "items", s, "parse", "srcitem"]
239
+ }));
240
+ });
241
+ });
242
+ }
243
+ function M(t) {
231
244
  return e.strictObject({
232
245
  $schema: e.optional(e.string()),
233
246
  schema: e.literal("constants1.schema.json"),
@@ -241,7 +254,7 @@ function I(t) {
241
254
  schema: e.literal("constants2.schema.json")
242
255
  }).passthrough();
243
256
  }
244
- function M() {
257
+ function S() {
245
258
  return e.string().regex(
246
259
  // Regex for AAAA-MM-JJ
247
260
  /^(\d{4})-(?:(?:0[1-9])|(?:1[0-2]))-(?:(?:0[1-9])|(?:[12][0-9])|(?:3[01]))$/,
@@ -258,7 +271,7 @@ function m() {
258
271
  e.number().min(0).max(255)
259
272
  ]);
260
273
  }
261
- function S() {
274
+ function J() {
262
275
  return e.custom((t) => {
263
276
  if (!Array.isArray(t) || t.length % 2 !== 0)
264
277
  return !1;
@@ -289,7 +302,7 @@ function f() {
289
302
  function p() {
290
303
  return e.string();
291
304
  }
292
- function J() {
305
+ function Z() {
293
306
  return e.discriminatedUnion("fn", [
294
307
  e.strictObject({
295
308
  fn: e.literal("none")
@@ -337,7 +350,7 @@ function J() {
337
350
  message: "eval and script should not both be present"
338
351
  });
339
352
  }
340
- function Z() {
353
+ function G(t) {
341
354
  return e.discriminatedUnion("fn", [
342
355
  e.strictObject({
343
356
  fn: e.undefined().describe("Generic function to parse ZCL attributes and commands."),
@@ -385,10 +398,11 @@ function Z() {
385
398
  }),
386
399
  e.strictObject({
387
400
  fn: e.literal("numtostr").describe("Generic function to to convert number to string."),
388
- // TODO use generic
389
- srcitem: e.enum(["state/airqualityppb", "state/pm2_5"]).describe("The source item holding the number."),
401
+ srcitem: e.enum(t.attributes, {
402
+ errorMap: (a, u) => a.code === "invalid_enum_value" ? { message: `Invalid enum value. Expected item from generic attributes definition, received '${a.received}'` } : { message: u.defaultError }
403
+ }).describe("The source item holding the number."),
390
404
  op: e.enum(["lt", "le", "eq", "gt", "ge"]).describe("Comparison operator (lt | le | eq | gt | ge)"),
391
- to: S().describe("Array of (num, string) mappings")
405
+ to: J().describe("Array of (num, string) mappings")
392
406
  }),
393
407
  e.strictObject({
394
408
  fn: e.literal("time").describe("Specialized function to parse time, local and last set time from read/report commands of the time cluster and auto-sync time if needed.")
@@ -408,11 +422,11 @@ function Z() {
408
422
  eval: e.optional(p()).describe("Javascript expression to transform the raw value."),
409
423
  script: e.optional(f()).describe("Relative path of a Javascript .js file.")
410
424
  })
411
- ]).refine((t) => !("eval" in t && "script" in t), {
425
+ ]).refine((a) => !("eval" in a && "script" in a), {
412
426
  message: "eval and script should not both be present"
413
427
  });
414
428
  }
415
- function G() {
429
+ function R() {
416
430
  return e.discriminatedUnion("fn", [
417
431
  e.strictObject({
418
432
  fn: e.literal("none")
@@ -480,7 +494,7 @@ function D(t) {
480
494
  id: e.string(),
481
495
  description: e.optional(e.string()).describe("Item description, better to do not use it."),
482
496
  comment: e.optional(e.string()).describe("TODO: What is this ? What the difference with description ?"),
483
- deprecated: e.optional(M()).describe("Date of deprecation, if the item is deprecated, it's better to use the new one."),
497
+ deprecated: e.optional(S()).describe("Date of deprecation, if the item is deprecated, it's better to use the new one."),
484
498
  datatype: e.optional(e.enum([
485
499
  "String",
486
500
  "Bool",
@@ -505,9 +519,9 @@ function D(t) {
505
519
  static: e.optional(e.union([e.string(), e.number(), e.boolean()])).describe("A static default value is fixed and can be not changed."),
506
520
  range: e.optional(e.tuple([e.number(), e.number()])).describe("Values range limit."),
507
521
  virtual: e.optional(e.boolean()).describe("TODO: What is this ?"),
508
- read: e.optional(J()).describe("Fonction used to read value."),
509
- parse: e.optional(Z()).describe("Fonction used to parse incoming values."),
510
- write: e.optional(G()).describe("Fonction used to write value."),
522
+ read: e.optional(Z()).describe("Fonction used to read value."),
523
+ parse: e.optional(G(t)).describe("Fonction used to parse incoming values."),
524
+ write: e.optional(R()).describe("Fonction used to write value."),
511
525
  "refresh.interval": e.optional(e.number()).describe("Refresh interval used for read fonction, NEED to be superior at value used in binding part."),
512
526
  // TODO Validate this
513
527
  values: e.optional(e.unknown()).describe("TODO: What is this ?"),
@@ -515,7 +529,7 @@ function D(t) {
515
529
  default: e.optional(e.unknown()).describe("Defaut value.")
516
530
  });
517
531
  }
518
- function R(t) {
532
+ function F(t) {
519
533
  return e.strictObject({
520
534
  $schema: e.optional(e.string()),
521
535
  schema: e.literal("devcap1.schema.json"),
@@ -544,11 +558,11 @@ function R(t) {
544
558
  sleeper: e.optional(e.boolean()).describe("Sleeping devices can only receive when awake."),
545
559
  supportsMgmtBind: e.optional(e.boolean()),
546
560
  status: e.enum(["Draft", "Bronze", "Silver", "Gold"]).describe("The code quality of the DDF file."),
547
- subdevices: e.array(F(t)).describe("Devices section."),
548
- bindings: e.optional(e.array(k())).describe("Bindings section.")
561
+ subdevices: e.array(z(t)).describe("Devices section."),
562
+ bindings: e.optional(e.array(L())).describe("Bindings section.")
549
563
  });
550
564
  }
551
- function F(t) {
565
+ function z(t) {
552
566
  return e.strictObject({
553
567
  type: e.union([
554
568
  e.enum(Object.keys(t.deviceTypes), {
@@ -574,12 +588,12 @@ function F(t) {
574
588
  buttons: e.optional(e.any()),
575
589
  // TODO validate this
576
590
  buttonevents: e.optional(e.any()),
577
- items: e.array(z(t)),
591
+ items: e.array(k(t)),
578
592
  example: e.optional(e.unknown())
579
593
  });
580
594
  }
581
- function z(t) {
582
- return D().omit({
595
+ function k(t) {
596
+ return D(t).omit({
583
597
  $schema: !0,
584
598
  schema: !0,
585
599
  id: !0
@@ -589,7 +603,7 @@ function z(t) {
589
603
  }).describe("Item name.")
590
604
  });
591
605
  }
592
- function k(t) {
606
+ function L(t) {
593
607
  return e.discriminatedUnion("bind", [
594
608
  e.strictObject({
595
609
  bind: e.literal("unicast"),
@@ -615,7 +629,7 @@ function k(t) {
615
629
  })
616
630
  ]);
617
631
  }
618
- function L(t) {
632
+ function W(t) {
619
633
  const a = e.array(
620
634
  e.enum(t.attributes, {
621
635
  errorMap: (u, n) => u.code === "invalid_enum_value" ? { message: `Invalid enum value. Expected item from generic attributes definition, received '${u.received}'` } : { message: n.defaultError }
@@ -640,11 +654,11 @@ function L(t) {
640
654
  }
641
655
  function x(t) {
642
656
  return e.discriminatedUnion("schema", [
643
- R(t),
644
- A(),
657
+ F(t),
658
+ M(),
645
659
  I(),
646
- D(),
647
- L(t)
660
+ D(t),
661
+ W(t)
648
662
  ]).superRefine((a, u) => {
649
663
  switch (a.schema) {
650
664
  case "devcap1.schema.json":
@@ -656,7 +670,7 @@ function x(t) {
656
670
  }
657
671
  });
658
672
  }
659
- function P(t = {
673
+ function B(t = {
660
674
  attributes: [],
661
675
  manufacturers: {},
662
676
  deviceTypes: {},
@@ -667,47 +681,47 @@ function P(t = {
667
681
  const u = () => {
668
682
  a = x(t);
669
683
  };
670
- return { generics: t, loadGeneric: (d) => {
671
- const i = a.parse(d);
672
- switch (i.schema) {
684
+ return { generics: t, loadGeneric: (s) => {
685
+ const o = a.parse(s);
686
+ switch (o.schema) {
673
687
  case "constants1.schema.json":
674
688
  t.manufacturers = {
675
689
  ...t.manufacturers,
676
- ...i.manufacturers
690
+ ...o.manufacturers
677
691
  }, t.deviceTypes = {
678
692
  ...t.deviceTypes,
679
- ...i["device-types"]
693
+ ...o["device-types"]
680
694
  };
681
695
  break;
682
696
  case "constants2.schema.json": {
683
- Object.keys(i).filter((o) => o.startsWith("$MF_")).forEach((o) => {
684
- t.manufacturers[o] = i[o];
685
- }), Object.keys(i).filter((o) => o.startsWith("$TYPE_")).forEach((o) => {
686
- t.deviceTypes[o] = i[o];
697
+ Object.keys(o).filter((c) => c.startsWith("$MF_")).forEach((c) => {
698
+ t.manufacturers[c] = o[c];
699
+ }), Object.keys(o).filter((c) => c.startsWith("$TYPE_")).forEach((c) => {
700
+ t.deviceTypes[c] = o[c];
687
701
  });
688
702
  break;
689
703
  }
690
704
  case "resourceitem1.schema.json": {
691
- if (t.attributes.includes(i.id))
692
- throw new Error(`Got duplicate resource item with attribute id '${i.id}'.`);
693
- const o = i, l = i.id;
694
- delete o.$schema, delete o.schema, delete o.id, t.resources[l] = o, t.attributes.push(l);
705
+ if (t.attributes.includes(o.id))
706
+ throw new Error(`Got duplicate resource item with attribute id '${o.id}'.`);
707
+ const c = o, b = o.id;
708
+ delete c.$schema, delete c.schema, delete c.id, t.resources[b] = c, t.attributes.push(b);
695
709
  break;
696
710
  }
697
711
  case "subdevice1.schema.json":
698
- t.subDevices[i.type] = i, t.subDevices[i.name] = i;
712
+ t.subDevices[o.type] = o, t.subDevices[o.name] = o;
699
713
  break;
700
714
  default:
701
- throw new Error(`Got invalid generic file, got data with schema '${i.schema}'.`);
715
+ throw new Error(`Got invalid generic file, got data with schema '${o.schema}'.`);
702
716
  }
703
717
  return u(), !0;
704
- }, validate: (d) => a.parse(d), getSchema: () => a, version: E, isGeneric: (d) => [
718
+ }, validate: (s) => a.parse(s), getSchema: () => a, version: E, isGeneric: (s) => [
705
719
  "constants1.schema.json",
706
720
  "constants2.schema.json",
707
721
  "resourceitem1.schema.json",
708
722
  "subdevice1.schema.json"
709
- ].includes(d) };
723
+ ].includes(s), isDDF: (s) => s === "devcap1.schema.json" };
710
724
  }
711
725
  export {
712
- P as createValidator
726
+ B as createValidator
713
727
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deconz-community/ddf-validator",
3
- "version": "2.16.0",
3
+ "version": "2.18.0",
4
4
  "description": "Validating DDF files for deconz",
5
5
  "keywords": [
6
6
  "deconz",
@@ -53,13 +53,13 @@
53
53
  "pnpm": ">=8.6.8",
54
54
  "node": ">=16.0.0"
55
55
  },
56
- "packageManager": "pnpm@8.7.4",
56
+ "packageManager": "pnpm@8.7.5",
57
57
  "devDependencies": {
58
- "@types/jsdom": "^21.1.2",
59
- "@types/node": "^20.6.0",
58
+ "@types/jsdom": "^21.1.3",
59
+ "@types/node": "^20.6.2",
60
60
  "@types/pako": "^2.0.0",
61
- "@typescript-eslint/eslint-plugin": "^6.6.0",
62
- "@typescript-eslint/parser": "^6.6.0",
61
+ "@typescript-eslint/eslint-plugin": "^6.7.0",
62
+ "@typescript-eslint/parser": "^6.7.0",
63
63
  "degit": "^2.8.4",
64
64
  "eslint": "^8.49.0",
65
65
  "glob": "^10.3.4",