@matter/model 0.12.0-alpha.0-20241229-9d9c99934 → 0.12.0-alpha.0-20241231-9ac20db97

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 (41) hide show
  1. package/dist/cjs/aspects/Constraint.d.ts +24 -15
  2. package/dist/cjs/aspects/Constraint.d.ts.map +1 -1
  3. package/dist/cjs/aspects/Constraint.js +268 -198
  4. package/dist/cjs/aspects/Constraint.js.map +2 -2
  5. package/dist/cjs/common/FieldValue.d.ts +9 -3
  6. package/dist/cjs/common/FieldValue.d.ts.map +1 -1
  7. package/dist/cjs/common/FieldValue.js +1 -1
  8. package/dist/cjs/common/FieldValue.js.map +1 -1
  9. package/dist/cjs/logic/definition-validation/ValueValidator.js +1 -1
  10. package/dist/cjs/logic/definition-validation/ValueValidator.js.map +1 -1
  11. package/dist/cjs/parser/Lexer.d.ts +3 -3
  12. package/dist/cjs/parser/Lexer.d.ts.map +1 -1
  13. package/dist/cjs/parser/Lexer.js +35 -31
  14. package/dist/cjs/parser/Lexer.js.map +1 -1
  15. package/dist/cjs/parser/Token.d.ts +5 -2
  16. package/dist/cjs/parser/Token.d.ts.map +1 -1
  17. package/dist/cjs/parser/TokenStream.js +2 -2
  18. package/dist/esm/aspects/Constraint.d.ts +24 -15
  19. package/dist/esm/aspects/Constraint.d.ts.map +1 -1
  20. package/dist/esm/aspects/Constraint.js +269 -199
  21. package/dist/esm/aspects/Constraint.js.map +2 -2
  22. package/dist/esm/common/FieldValue.d.ts +9 -3
  23. package/dist/esm/common/FieldValue.d.ts.map +1 -1
  24. package/dist/esm/common/FieldValue.js +1 -1
  25. package/dist/esm/common/FieldValue.js.map +1 -1
  26. package/dist/esm/logic/definition-validation/ValueValidator.js +1 -1
  27. package/dist/esm/logic/definition-validation/ValueValidator.js.map +1 -1
  28. package/dist/esm/parser/Lexer.d.ts +3 -3
  29. package/dist/esm/parser/Lexer.d.ts.map +1 -1
  30. package/dist/esm/parser/Lexer.js +35 -31
  31. package/dist/esm/parser/Lexer.js.map +1 -1
  32. package/dist/esm/parser/Token.d.ts +5 -2
  33. package/dist/esm/parser/Token.d.ts.map +1 -1
  34. package/dist/esm/parser/TokenStream.js +2 -2
  35. package/package.json +4 -4
  36. package/src/aspects/Constraint.ts +340 -215
  37. package/src/common/FieldValue.ts +9 -4
  38. package/src/logic/definition-validation/ValueValidator.ts +1 -1
  39. package/src/parser/Lexer.ts +38 -40
  40. package/src/parser/Token.ts +11 -1
  41. package/src/parser/TokenStream.ts +2 -2
@@ -47,6 +47,11 @@ export namespace FieldValue {
47
47
  export const none = "none";
48
48
  export type none = typeof none;
49
49
 
50
+ /**
51
+ * A field value that allows type extension.
52
+ */
53
+ export type Open = FieldValue | { type: string };
54
+
50
55
  /**
51
56
  * If a field value isn't a primitive type, it's an object with a type field indicating one of these types.
52
57
  */
@@ -55,7 +60,7 @@ export namespace FieldValue {
55
60
  /**
56
61
  * Test for one of the special placeholder types.
57
62
  */
58
- export function is(value: FieldValue | undefined, type: Type) {
63
+ export function is(value: Open | undefined, type: Type) {
59
64
  return value && (value as any).type === type;
60
65
  }
61
66
 
@@ -150,7 +155,7 @@ export namespace FieldValue {
150
155
  return `${(value as Celsius).value}°C`;
151
156
  }
152
157
  if (is(value, percent)) {
153
- return `${(value as Percent).value}%';`;
158
+ return `${(value as Percent).value}%`;
154
159
  }
155
160
  if (is(value, properties)) {
156
161
  return stringSerialize((value as Properties).properties) ?? "?";
@@ -161,7 +166,7 @@ export namespace FieldValue {
161
166
  /**
162
167
  * Given a type name as a hint, do our best to convert a field value to a number.
163
168
  */
164
- export function numericValue(value: FieldValue | undefined, typeName?: string) {
169
+ export function numericValue(value: Open | undefined, typeName?: string) {
165
170
  if (typeof value === "boolean") {
166
171
  return value ? 1 : 0;
167
172
  }
@@ -240,7 +245,7 @@ export namespace FieldValue {
240
245
  /**
241
246
  * Get the referenced name if the FieldValue is a reference.
242
247
  */
243
- export function referenced(value: FieldValue | undefined) {
248
+ export function referenced(value: Open | undefined) {
244
249
  if (is(value, reference)) {
245
250
  return (value as Reference).name;
246
251
  }
@@ -49,7 +49,7 @@ export class ValueValidator<T extends ValueModel> extends ModelValidator<T> {
49
49
  private validateAspect(name: string) {
50
50
  const aspect = (this.model as any)[name] as Aspect;
51
51
  if (aspect?.errors) {
52
- aspect.errors.forEach((e: DefinitionError) => this.model.error(e.code, e.message));
52
+ aspect.errors.forEach((e: DefinitionError) => this.model.error(e.code, `${e.source}: ${e.message}`));
53
53
  }
54
54
  }
55
55
 
@@ -16,10 +16,10 @@ function isNameChar(c: string) {
16
16
  *
17
17
  * Tokenizes simple text dialects. Currently sufficient for Matter conformance and constraint tokenization.
18
18
  */
19
- export class Lexer<T extends BasicToken> {
19
+ export class Lexer<T extends BasicToken<KW>, const KW extends string[] = []> {
20
20
  #keywords: Set<string>;
21
21
 
22
- constructor(keywords: Iterable<string> = []) {
22
+ constructor(keywords?: KW) {
23
23
  if (keywords instanceof Set) {
24
24
  this.#keywords = keywords;
25
25
  } else {
@@ -117,33 +117,7 @@ function* lex(
117
117
  return;
118
118
  }
119
119
 
120
- function tokenizeNumber(sign: number) {
121
- markStart();
122
- if (sign === -1) {
123
- // Skip "-" prefix
124
- next();
125
- }
126
-
127
- if (current.value === "0") {
128
- if (peeked.value === "x") {
129
- next();
130
- next();
131
- return tokenizeDigits(16, sign, hexadecimalValueOf);
132
- } else if (peeked.value === "b") {
133
- next();
134
- next();
135
- return tokenizeDigits(2, sign, binaryValueOf);
136
- }
137
- }
138
-
139
- return tokenizeDigits(10, sign, decimalValueOf);
140
- }
141
-
142
- function tokenizeDigits(
143
- base: number,
144
- sign: number,
145
- valueOf: (digit: string[1] | undefined) => number | undefined,
146
- ): BasicToken {
120
+ function tokenizeDigits(base: number, valueOf: (digit: string[1] | undefined) => number | undefined): BasicToken {
147
121
  // The first digit may not actually be a digit if number is hexadecimal or binary
148
122
  let num = valueOf(current.value);
149
123
  if (num === undefined) {
@@ -161,7 +135,19 @@ function* lex(
161
135
  num = num * base + digitValue;
162
136
  }
163
137
 
164
- num *= sign;
138
+ if (base === 10 && peeked.value === ".") {
139
+ next();
140
+ let fraction = "";
141
+ while (true) {
142
+ const digitValue = valueOf(peeked.value);
143
+ if (digitValue === undefined) {
144
+ break;
145
+ }
146
+ fraction += peeked.value;
147
+ next();
148
+ }
149
+ num = Number.parseFloat(`${num}.${fraction}`);
150
+ }
165
151
 
166
152
  // Handle specialized suffices for percents and temperatures
167
153
  if (peeked.value === "%") {
@@ -169,7 +155,7 @@ function* lex(
169
155
  return { type: "value", value: FieldValue.Percent(num), startLine, startChar };
170
156
  } else if (peeked.value === "°") {
171
157
  next();
172
- if (peeked.value?.toLowerCase() === "C") {
158
+ if (peeked.value?.toLowerCase() === "c") {
173
159
  next();
174
160
  }
175
161
  return { type: "value", value: FieldValue.Celsius(num), startLine, startChar };
@@ -190,22 +176,34 @@ function* lex(
190
176
  case "]":
191
177
  case "(":
192
178
  case ")":
179
+ case "{":
180
+ case "}":
181
+ case "-":
193
182
  case "+":
194
183
  case "/":
195
184
  case "*":
196
185
  yield { type: current.value, startLine: line, startChar: char };
197
186
  break;
198
187
 
199
- case "-":
200
- if (peeked.value !== undefined && (peeked.value >= "0" || peeked.value <= "0")) {
201
- yield tokenizeNumber(-1);
202
- } else {
203
- yield { type: current.value, startLine: line, startChar: char };
188
+ case "0":
189
+ markStart();
190
+
191
+ if (current.value === "0") {
192
+ if (peeked.value === "x") {
193
+ next();
194
+ next();
195
+ yield tokenizeDigits(16, hexadecimalValueOf);
196
+ break;
197
+ }
198
+
199
+ if (peeked.value === "b") {
200
+ next();
201
+ next();
202
+ yield tokenizeDigits(2, binaryValueOf);
203
+ }
204
204
  }
205
- break;
206
205
 
207
- case "0":
208
- yield tokenizeNumber(1);
206
+ yield tokenizeDigits(10, decimalValueOf);
209
207
  break;
210
208
 
211
209
  case "1":
@@ -217,7 +215,7 @@ function* lex(
217
215
  case "7":
218
216
  case "8":
219
217
  case "9":
220
- yield tokenizeDigits(10, 1, decimalValueOf);
218
+ yield tokenizeDigits(10, decimalValueOf);
221
219
  break;
222
220
 
223
221
  case "!":
@@ -18,7 +18,11 @@ export interface Token {
18
18
  /**
19
19
  * The base token produced by the tokenizer.
20
20
  */
21
- export type BasicToken = BasicToken.Special | BasicToken.Word | BasicToken.Number;
21
+ export type BasicToken<KW extends string[] = []> =
22
+ | BasicToken.Special
23
+ | BasicToken.Word
24
+ | BasicToken.Number
25
+ | BasicToken.Keyword<KW>;
22
26
 
23
27
  /**
24
28
  * A {@link BasicToken} with additional keywords.
@@ -39,6 +43,8 @@ export namespace BasicToken {
39
43
  | "]"
40
44
  | "("
41
45
  | ")"
46
+ | "{"
47
+ | "}"
42
48
  | "-"
43
49
  | "+"
44
50
  | "*"
@@ -61,4 +67,8 @@ export namespace BasicToken {
61
67
  type: "value";
62
68
  value: FieldValue;
63
69
  }
70
+
71
+ export interface Keyword<T extends string[]> extends Token {
72
+ type: T[number];
73
+ }
64
74
  }
@@ -50,10 +50,10 @@ export function TokenStream<T extends Token>(iterator: Iterator<T>): TokenStream
50
50
  return "end of statement";
51
51
 
52
52
  case "word":
53
- return `word "${(this.token as unknown as BasicToken.Word).value}`;
53
+ return `word "${(this.token as unknown as BasicToken.Word).value}"`;
54
54
 
55
55
  case "number":
56
- return `number "${(this.token as unknown as BasicToken.Number).value}`;
56
+ return `number "${(this.token as unknown as BasicToken.Number).value}"`;
57
57
 
58
58
  default:
59
59
  if (this.token?.type.match(/[a-z]/i)) {