@matter/model 0.16.0-alpha.0-20251004-92135c7df → 0.16.0-alpha.0-20251006-3fe1e7c57
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/elements/DatatypeElement.d.ts +6 -9
- package/dist/cjs/elements/DatatypeElement.d.ts.map +1 -1
- package/dist/cjs/elements/DatatypeElement.js.map +1 -1
- package/dist/cjs/logic/ModelIndex.d.ts +39 -0
- package/dist/cjs/logic/ModelIndex.d.ts.map +1 -0
- package/dist/cjs/logic/ModelIndex.js +100 -0
- package/dist/cjs/logic/ModelIndex.js.map +6 -0
- package/dist/cjs/logic/Scope.d.ts +2 -1
- package/dist/cjs/logic/Scope.d.ts.map +1 -1
- package/dist/cjs/logic/Scope.js +7 -3
- package/dist/cjs/logic/Scope.js.map +1 -1
- package/dist/cjs/logic/index.d.ts +1 -0
- package/dist/cjs/logic/index.d.ts.map +1 -1
- package/dist/cjs/logic/index.js +1 -0
- package/dist/cjs/logic/index.js.map +1 -1
- package/dist/cjs/models/ClusterModel.d.ts +43 -5
- package/dist/cjs/models/ClusterModel.d.ts.map +1 -1
- package/dist/cjs/models/ClusterModel.js +69 -1
- package/dist/cjs/models/ClusterModel.js.map +2 -2
- package/dist/cjs/models/ValueModel.d.ts +18 -2
- package/dist/cjs/models/ValueModel.d.ts.map +1 -1
- package/dist/cjs/models/ValueModel.js +27 -0
- package/dist/cjs/models/ValueModel.js.map +2 -2
- package/dist/esm/elements/DatatypeElement.d.ts +6 -9
- package/dist/esm/elements/DatatypeElement.d.ts.map +1 -1
- package/dist/esm/elements/DatatypeElement.js.map +1 -1
- package/dist/esm/logic/ModelIndex.d.ts +39 -0
- package/dist/esm/logic/ModelIndex.d.ts.map +1 -0
- package/dist/esm/logic/ModelIndex.js +80 -0
- package/dist/esm/logic/ModelIndex.js.map +6 -0
- package/dist/esm/logic/Scope.d.ts +2 -1
- package/dist/esm/logic/Scope.d.ts.map +1 -1
- package/dist/esm/logic/Scope.js +7 -3
- package/dist/esm/logic/Scope.js.map +1 -1
- package/dist/esm/logic/index.d.ts +1 -0
- package/dist/esm/logic/index.d.ts.map +1 -1
- package/dist/esm/logic/index.js +1 -0
- package/dist/esm/logic/index.js.map +1 -1
- package/dist/esm/models/ClusterModel.d.ts +43 -5
- package/dist/esm/models/ClusterModel.d.ts.map +1 -1
- package/dist/esm/models/ClusterModel.js +69 -1
- package/dist/esm/models/ClusterModel.js.map +2 -2
- package/dist/esm/models/ValueModel.d.ts +18 -2
- package/dist/esm/models/ValueModel.d.ts.map +1 -1
- package/dist/esm/models/ValueModel.js +27 -0
- package/dist/esm/models/ValueModel.js.map +2 -2
- package/package.json +4 -4
- package/src/elements/DatatypeElement.ts +6 -9
- package/src/logic/ModelIndex.ts +125 -0
- package/src/logic/Scope.ts +16 -12
- package/src/logic/index.ts +1 -0
- package/src/models/ClusterModel.ts +82 -9
- package/src/models/ValueModel.ts +35 -3
|
@@ -56,6 +56,9 @@ class ValueModel extends Model {
|
|
|
56
56
|
get fields() {
|
|
57
57
|
return Scope(this).membersOf(this, { tags: [ElementTag.Field] });
|
|
58
58
|
}
|
|
59
|
+
get conformant() {
|
|
60
|
+
return new ValueModel.Conformant(this);
|
|
61
|
+
}
|
|
59
62
|
/**
|
|
60
63
|
* Metatype is only present on global types with specific semantic meaning. This model is significant because it
|
|
61
64
|
* gives us information about how to manipulate the data. This accessor retrieves this model.
|
|
@@ -243,6 +246,30 @@ class ValueModel extends Model {
|
|
|
243
246
|
});
|
|
244
247
|
}
|
|
245
248
|
}
|
|
249
|
+
((ValueModel2) => {
|
|
250
|
+
class Conformant {
|
|
251
|
+
#model;
|
|
252
|
+
constructor(model) {
|
|
253
|
+
this.#model = model;
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* The model's conformant fields.
|
|
257
|
+
*/
|
|
258
|
+
get fields() {
|
|
259
|
+
return Scope(this.#model).membersOf(this.#model, {
|
|
260
|
+
tags: [ElementTag.Field],
|
|
261
|
+
conformance: "conformant"
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* An alias for {@link fields} that offers compatibility with the same field for clusters.
|
|
266
|
+
*/
|
|
267
|
+
get properties() {
|
|
268
|
+
return this.fields;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
ValueModel2.Conformant = Conformant;
|
|
272
|
+
})(ValueModel || (ValueModel = {}));
|
|
246
273
|
export {
|
|
247
274
|
ValueModel
|
|
248
275
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/models/ValueModel.ts"],
|
|
4
|
-
"mappings": "AAAA;AAAA;AAAA;AAAA;AAAA;AAMA,SAAS,aAAa;AACtB,SAAS,QAAgB,aAAa,YAAY,eAAe;AACjE,SAAS,YAAwB,gBAAgB;AAEjD,SAAS,sBAAsB;AAC/B,SAAS,aAAa;
|
|
5
|
-
"names": []
|
|
4
|
+
"mappings": "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",
|
|
5
|
+
"names": ["ValueModel"]
|
|
6
6
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@matter/model",
|
|
3
|
-
"version": "0.16.0-alpha.0-
|
|
3
|
+
"version": "0.16.0-alpha.0-20251006-3fe1e7c57",
|
|
4
4
|
"description": "Matter data model",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"iot",
|
|
@@ -31,11 +31,11 @@
|
|
|
31
31
|
"embed-examples": "embedme **/README.md"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@matter/general": "0.16.0-alpha.0-
|
|
34
|
+
"@matter/general": "0.16.0-alpha.0-20251006-3fe1e7c57"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
|
-
"@matter/testing": "0.16.0-alpha.0-
|
|
38
|
-
"@matter/tools": "0.16.0-alpha.0-
|
|
37
|
+
"@matter/testing": "0.16.0-alpha.0-20251006-3fe1e7c57",
|
|
38
|
+
"@matter/tools": "0.16.0-alpha.0-20251006-3fe1e7c57"
|
|
39
39
|
},
|
|
40
40
|
"files": [
|
|
41
41
|
"dist/**/*",
|
|
@@ -43,9 +43,8 @@ export namespace DatatypeElement {
|
|
|
43
43
|
/**
|
|
44
44
|
* Convert a TypeScript enum to Matter enum values.
|
|
45
45
|
*
|
|
46
|
-
* Matter enums include conformance and other metadata. They may also have
|
|
47
|
-
*
|
|
48
|
-
* we can't use a TypeScript enum directly.
|
|
46
|
+
* Matter enums include conformance and other metadata. They may also have multiple definitions of the same value
|
|
47
|
+
* selectable by conformance. So we can't use a TypeScript enum directly.
|
|
49
48
|
*/
|
|
50
49
|
export function ListValues(values: ValueMap): ListValues {
|
|
51
50
|
const result = Array<FieldElement>();
|
|
@@ -67,16 +66,14 @@ export namespace DatatypeElement {
|
|
|
67
66
|
}
|
|
68
67
|
|
|
69
68
|
/**
|
|
70
|
-
* We express enum values as IntElements as this gives us conformance
|
|
71
|
-
* and other metadata.
|
|
69
|
+
* We express enum values as IntElements as this gives us conformance and other metadata.
|
|
72
70
|
*/
|
|
73
71
|
export type ListValues = FieldElement[];
|
|
74
72
|
|
|
75
73
|
/**
|
|
76
|
-
* Per the Matter specification, enums are named integers. The following
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
* generating the Matter enum we ignore the string keys.
|
|
74
|
+
* Per the Matter specification, enums are named integers. The following allows TypeScript enums to be supplied for
|
|
75
|
+
* translation into Matter enums. To do so, we must accept both numeric and string values. For generating the
|
|
76
|
+
* Matter enum we ignore the string keys.
|
|
80
77
|
*/
|
|
81
78
|
export type ValueMap = { [name: string]: number | string };
|
|
82
79
|
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2022-2025 Matter.js Authors
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { camelize } from "#general";
|
|
8
|
+
import { Model } from "../models/Model.js";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* An read-only array of models with support for efficient lookup by name and ID.
|
|
12
|
+
*
|
|
13
|
+
* Name search uses canonical camel case, so "FooBar", "fooBar" and "foo-bar" are considered equivalent.
|
|
14
|
+
*/
|
|
15
|
+
export interface ModelIndex<T extends Model = Model> extends ReadonlyArray<T> {
|
|
16
|
+
/**
|
|
17
|
+
* Retrieve a model for the given ID or name.
|
|
18
|
+
*
|
|
19
|
+
* Use the two-parameter version for indices that contain multiple model types.
|
|
20
|
+
*/
|
|
21
|
+
for(key: number | string): T | undefined;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Retrieve a model of the specific type for the given ID or name.
|
|
25
|
+
*
|
|
26
|
+
* Name search uses canonical camel case.
|
|
27
|
+
*/
|
|
28
|
+
for<M extends T>(key: number | string, type: Model.Type<M>): M | undefined;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Filter to a specific model subtype.
|
|
32
|
+
*/
|
|
33
|
+
ofType<M extends T>(type: Model.Type<M>): M[];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Implementation of {@link ModelIndex} used for initial creation.
|
|
38
|
+
*/
|
|
39
|
+
export class MutableModelIndex<T extends Model = Model> extends Array<T> implements ModelIndex {
|
|
40
|
+
#nameIndex?: Map<string, T | T[]>;
|
|
41
|
+
#idIndex?: Map<number, T | T[]>;
|
|
42
|
+
|
|
43
|
+
for(key: number | string): T;
|
|
44
|
+
for<M extends T>(key: number | string, type: Model.Type<M>): M;
|
|
45
|
+
|
|
46
|
+
for(key: number | string, type?: Model.Type): Model | undefined {
|
|
47
|
+
let untyped: undefined | Model | Model[];
|
|
48
|
+
|
|
49
|
+
if (typeof key === "number") {
|
|
50
|
+
untyped = this.#ids.get(key);
|
|
51
|
+
} else {
|
|
52
|
+
untyped = this.#names.get(camelize(key));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (untyped === undefined) {
|
|
56
|
+
return undefined;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (Array.isArray(untyped)) {
|
|
60
|
+
if (type) {
|
|
61
|
+
return untyped.find(m => m instanceof type);
|
|
62
|
+
}
|
|
63
|
+
return untyped[0];
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (type && !(untyped instanceof type)) {
|
|
67
|
+
return undefined;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return untyped;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
ofType<T extends Model.Type>(type: T): InstanceType<T>[] {
|
|
74
|
+
return this.filter(m => m instanceof type) as InstanceType<T>[];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
get #ids() {
|
|
78
|
+
if (this.#idIndex) {
|
|
79
|
+
return this.#idIndex;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const index = (this.#idIndex = new Map<number, T | T[]>());
|
|
83
|
+
for (const model of this) {
|
|
84
|
+
if (model.id === undefined) {
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const already = index.get(model.id);
|
|
89
|
+
if (already) {
|
|
90
|
+
if (Array.isArray(already)) {
|
|
91
|
+
already.push(model);
|
|
92
|
+
} else {
|
|
93
|
+
index.set(model.id, [already, model]);
|
|
94
|
+
}
|
|
95
|
+
} else {
|
|
96
|
+
index.set(model.id, model);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return this.#idIndex;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
get #names() {
|
|
104
|
+
if (this.#nameIndex) {
|
|
105
|
+
return this.#nameIndex;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const index = (this.#nameIndex = new Map<string, T | T[]>());
|
|
109
|
+
for (const model of this) {
|
|
110
|
+
const name = camelize(model.name);
|
|
111
|
+
const already = index.get(name);
|
|
112
|
+
if (already) {
|
|
113
|
+
if (Array.isArray(already)) {
|
|
114
|
+
already.push(model);
|
|
115
|
+
} else {
|
|
116
|
+
index.set(name, [already, model]);
|
|
117
|
+
}
|
|
118
|
+
} else {
|
|
119
|
+
index.set(name, model);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return this.#nameIndex;
|
|
124
|
+
}
|
|
125
|
+
}
|
package/src/logic/Scope.ts
CHANGED
|
@@ -12,6 +12,7 @@ import { ModelTraversal } from "./ModelTraversal.js";
|
|
|
12
12
|
|
|
13
13
|
// These must be types to avoid circular references
|
|
14
14
|
import type { ClusterModel, Model, ScopeModel, ValueModel } from "#models/index.js";
|
|
15
|
+
import { ModelIndex, MutableModelIndex } from "./ModelIndex.js";
|
|
15
16
|
|
|
16
17
|
const DEFAULT_TAGS = new Set([ElementTag.Field, ElementTag.Attribute]);
|
|
17
18
|
const GLOBAL_IDS = new Set([0xfffd, 0xfffc, 0xfffb, 0xfffa, 0xfff9, 0xfff8]);
|
|
@@ -61,7 +62,7 @@ export interface Scope {
|
|
|
61
62
|
/**
|
|
62
63
|
* Identify members (child properties) of the designated model in this scope.
|
|
63
64
|
*/
|
|
64
|
-
membersOf<T extends Model>(parent: T, options?: Scope.MemberOptions): Model.ChildOf<T
|
|
65
|
+
membersOf<T extends Model>(parent: T, options?: Scope.MemberOptions): ModelIndex<Model.ChildOf<T>>;
|
|
65
66
|
}
|
|
66
67
|
|
|
67
68
|
/**
|
|
@@ -156,11 +157,14 @@ export function Scope(subject: Model, options: Scope.ScopeOptions = {}) {
|
|
|
156
157
|
const allMembers = findAllMembers(parent, tags, result);
|
|
157
158
|
|
|
158
159
|
if (parent.tag === ElementTag.Cluster && tags.has(ElementTag.Attribute)) {
|
|
159
|
-
injectGlobalAttributes(
|
|
160
|
+
injectGlobalAttributes(
|
|
161
|
+
owner as ClusterModel,
|
|
162
|
+
allMembers as unknown as MutableModelIndex<ClusterModel.Child>,
|
|
163
|
+
);
|
|
160
164
|
}
|
|
161
165
|
|
|
162
166
|
if (!conformanceMode || conformanceMode === "ignore") {
|
|
163
|
-
return allMembers
|
|
167
|
+
return allMembers;
|
|
164
168
|
}
|
|
165
169
|
|
|
166
170
|
const conformantOnly = conformanceMode === "conformant";
|
|
@@ -177,7 +181,7 @@ export function Scope(subject: Model, options: Scope.ScopeOptions = {}) {
|
|
|
177
181
|
supportedFeatures,
|
|
178
182
|
conformantOnly,
|
|
179
183
|
conformantOnly ? deconflictedMemberCache : conformantMemberCache,
|
|
180
|
-
)
|
|
184
|
+
);
|
|
181
185
|
}
|
|
182
186
|
|
|
183
187
|
if (useCache) {
|
|
@@ -248,8 +252,8 @@ export namespace Scope {
|
|
|
248
252
|
/**
|
|
249
253
|
* Selects all candidate members for a model.
|
|
250
254
|
*/
|
|
251
|
-
function findAllMembers(parent:
|
|
252
|
-
const members =
|
|
255
|
+
function findAllMembers<T extends Model>(parent: T, tags: Set<ElementTag>, scope: Scope) {
|
|
256
|
+
const members = new MutableModelIndex<Model.ChildOf<T>>();
|
|
253
257
|
|
|
254
258
|
// This is a map of identity (based on tag + id/name + discriminator) to a priority based on inheritance depth
|
|
255
259
|
const defined = {} as Record<string, number | undefined>;
|
|
@@ -288,7 +292,7 @@ function findAllMembers(parent: Model, tags: Set<ElementTag>, scope: Scope) {
|
|
|
288
292
|
defined[nameIdentity] = level;
|
|
289
293
|
|
|
290
294
|
// Found a member
|
|
291
|
-
members.push(child);
|
|
295
|
+
members.push(child as Model.ChildOf<T>);
|
|
292
296
|
}
|
|
293
297
|
};
|
|
294
298
|
traversal.visitInheritance(parent, childSearchVisitor);
|
|
@@ -300,7 +304,7 @@ function findAllMembers(parent: Model, tags: Set<ElementTag>, scope: Scope) {
|
|
|
300
304
|
* We consider the standard set of "global" attributes members of all clusters. This injects those members that are
|
|
301
305
|
* not otherwise defined in the cluster.
|
|
302
306
|
*/
|
|
303
|
-
function injectGlobalAttributes(scope:
|
|
307
|
+
function injectGlobalAttributes(scope: ClusterModel, members: ClusterModel.Child[]) {
|
|
304
308
|
const missingGlobalIds = new Set(GLOBAL_IDS);
|
|
305
309
|
for (const m of members) {
|
|
306
310
|
if (m.tag === ElementTag.Attribute && m.id) {
|
|
@@ -342,8 +346,8 @@ function injectGlobalAttributes(scope: Model, members: Model[]) {
|
|
|
342
346
|
* Note 2 - members may not be differentiated with conformance rules that rely on field values in this way. That will
|
|
343
347
|
* probably never be necessary and would require an entirely different (more complicated) structure.
|
|
344
348
|
*/
|
|
345
|
-
function filterWithConformance(
|
|
346
|
-
parent:
|
|
349
|
+
function filterWithConformance<T extends Model>(
|
|
350
|
+
parent: T,
|
|
347
351
|
tags: Set<ElementTag>,
|
|
348
352
|
members: Model[],
|
|
349
353
|
features: FeatureSet,
|
|
@@ -352,7 +356,7 @@ function filterWithConformance(
|
|
|
352
356
|
cache?: Map<Model, Map<ElementTag, Set<Model>>>,
|
|
353
357
|
) {
|
|
354
358
|
const tagsToCollect = new Set<ElementTag>(tags);
|
|
355
|
-
const result =
|
|
359
|
+
const result = new MutableModelIndex<Model.ChildOf<T>>();
|
|
356
360
|
const cached = cache ? (cache.get(parent) ?? new Map()) : undefined;
|
|
357
361
|
|
|
358
362
|
if (cache && cached) {
|
|
@@ -415,7 +419,7 @@ function filterWithConformance(
|
|
|
415
419
|
}
|
|
416
420
|
|
|
417
421
|
for (const tag in selectedMembers) {
|
|
418
|
-
const tagResult = Object.values(selectedMembers[tag]);
|
|
422
|
+
const tagResult = Object.values(selectedMembers[tag]) as Model.ChildOf<T>[];
|
|
419
423
|
if (tagResult.length) {
|
|
420
424
|
result.push(...tagResult);
|
|
421
425
|
if (cached) {
|
package/src/logic/index.ts
CHANGED
|
@@ -13,6 +13,7 @@ export * from "./ClusterVariance.js";
|
|
|
13
13
|
export * from "./DefaultValue.js";
|
|
14
14
|
export * from "./MergedModel.js";
|
|
15
15
|
export * from "./ModelDiff.js";
|
|
16
|
+
export * from "./ModelIndex.js";
|
|
16
17
|
export * from "./ModelVariantTraversal.js";
|
|
17
18
|
export * from "./Scope.js";
|
|
18
19
|
export * from "./ValidateModel.js";
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import { camelize, describeList } from "#general";
|
|
8
|
+
import { ModelIndex } from "#logic/ModelIndex.js";
|
|
8
9
|
import { ModelTraversal } from "#logic/ModelTraversal.js";
|
|
9
10
|
import { Access } from "../aspects/Access.js";
|
|
10
11
|
import { Quality } from "../aspects/Quality.js";
|
|
@@ -40,19 +41,23 @@ export class ClusterModel extends ScopeModel<ClusterElement, ClusterModel.Child>
|
|
|
40
41
|
}
|
|
41
42
|
|
|
42
43
|
get attributes() {
|
|
43
|
-
return this.scope.membersOf(this, { tags: [ElementTag.Attribute] }) as AttributeModel
|
|
44
|
+
return this.scope.membersOf(this, { tags: [ElementTag.Attribute] }) as ModelIndex<AttributeModel>;
|
|
44
45
|
}
|
|
45
46
|
|
|
46
47
|
get commands() {
|
|
47
|
-
return this.scope.membersOf(this, { tags: [ElementTag.Command] }) as CommandModel
|
|
48
|
+
return this.scope.membersOf(this, { tags: [ElementTag.Command] }) as ModelIndex<CommandModel>;
|
|
48
49
|
}
|
|
49
50
|
|
|
50
51
|
get events() {
|
|
51
|
-
return this.scope.membersOf(this, { tags: [ElementTag.Event] }) as EventModel
|
|
52
|
+
return this.scope.membersOf(this, { tags: [ElementTag.Event] }) as ModelIndex<EventModel>;
|
|
52
53
|
}
|
|
53
54
|
|
|
54
55
|
get datatypes() {
|
|
55
|
-
return this.scope.membersOf(this, { tags: [ElementTag.Datatype] }) as DatatypeModel
|
|
56
|
+
return this.scope.membersOf(this, { tags: [ElementTag.Datatype] }) as ModelIndex<DatatypeModel>;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
get conformant() {
|
|
60
|
+
return new ClusterModel.Conformant(this);
|
|
56
61
|
}
|
|
57
62
|
|
|
58
63
|
get classification(): ClusterElement.Classification | undefined {
|
|
@@ -79,11 +84,9 @@ export class ClusterModel extends ScopeModel<ClusterElement, ClusterModel.Child>
|
|
|
79
84
|
* Get attributes, commands and events whether inherited or defined directly in this model.
|
|
80
85
|
*/
|
|
81
86
|
get allAces() {
|
|
82
|
-
return this.scope.membersOf(this, {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
| EventModel
|
|
86
|
-
)[];
|
|
87
|
+
return this.scope.membersOf(this, {
|
|
88
|
+
tags: [ElementTag.Attribute, ElementTag.Command, ElementTag.Event],
|
|
89
|
+
}) as ModelIndex<AttributeModel | CommandModel | EventModel>;
|
|
87
90
|
}
|
|
88
91
|
|
|
89
92
|
get revision() {
|
|
@@ -193,4 +196,74 @@ export namespace ClusterModel {
|
|
|
193
196
|
|
|
194
197
|
// Fields are not cluster children in canonical schema but we allow them as private values in operational schema
|
|
195
198
|
| FieldModel;
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* A conformant view of {@link ClusterModel} child indices properties.
|
|
202
|
+
*/
|
|
203
|
+
export class Conformant {
|
|
204
|
+
#model: ClusterModel;
|
|
205
|
+
|
|
206
|
+
constructor(model: ClusterModel) {
|
|
207
|
+
this.#model = model;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* The cluster's conformant attributes.
|
|
212
|
+
*/
|
|
213
|
+
get attributes() {
|
|
214
|
+
return this.#model.scope.membersOf(this.#model, {
|
|
215
|
+
tags: [ElementTag.Attribute],
|
|
216
|
+
conformance: "conformant",
|
|
217
|
+
}) as ModelIndex<AttributeModel>;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* The cluster's conformant properties (includes fields and attributes).
|
|
222
|
+
*
|
|
223
|
+
* This offers compatibility with the equivalent field for ValueModel. It is useful when treating a cluster as
|
|
224
|
+
* a struct.
|
|
225
|
+
*/
|
|
226
|
+
get properties() {
|
|
227
|
+
return this.#model.scope.membersOf(this.#model, {
|
|
228
|
+
tags: [ElementTag.Attribute, ElementTag.Field],
|
|
229
|
+
conformance: "conformant",
|
|
230
|
+
}) as ModelIndex<AttributeModel | FieldModel>;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* The cluster's conformant fields.
|
|
235
|
+
*
|
|
236
|
+
* Fields are not formally allowed on clusters but we allow for extensions that should not be served via the
|
|
237
|
+
* Matter protocol.
|
|
238
|
+
*
|
|
239
|
+
* This is primarily here to allow simplified access to fields in contexts where a variable is typed as a
|
|
240
|
+
* ClusterModel or ValueModel.
|
|
241
|
+
*/
|
|
242
|
+
get fields() {
|
|
243
|
+
return this.#model.scope.membersOf(this.#model, {
|
|
244
|
+
tags: [ElementTag.Field],
|
|
245
|
+
conformance: "conformant",
|
|
246
|
+
}) as ModelIndex<FieldModel>;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* The cluster's conformant commands.
|
|
251
|
+
*/
|
|
252
|
+
get commands() {
|
|
253
|
+
return this.#model.scope.membersOf(this.#model, {
|
|
254
|
+
tags: [ElementTag.Command],
|
|
255
|
+
conformance: "conformant",
|
|
256
|
+
}) as ModelIndex<CommandModel>;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* The cluster's conformant events.
|
|
261
|
+
*/
|
|
262
|
+
get events() {
|
|
263
|
+
return this.#model.scope.membersOf(this.#model, {
|
|
264
|
+
tags: [ElementTag.Event],
|
|
265
|
+
conformance: "conformant",
|
|
266
|
+
}) as ModelIndex<EventModel>;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
196
269
|
}
|
package/src/models/ValueModel.ts
CHANGED
|
@@ -14,6 +14,7 @@ import type { PropertyModel } from "./PropertyModel.js";
|
|
|
14
14
|
|
|
15
15
|
// These are circular dependencies so just to be safe we only import the types. We also need the class, though, at
|
|
16
16
|
// runtime. So we use the references in the Model.constructors factory pool.
|
|
17
|
+
import { ModelIndex } from "#logic/ModelIndex.js";
|
|
17
18
|
import type { FieldModel } from "./FieldModel.js";
|
|
18
19
|
|
|
19
20
|
/**
|
|
@@ -74,7 +75,11 @@ export abstract class ValueModel<T extends ValueElement = ValueElement>
|
|
|
74
75
|
}
|
|
75
76
|
|
|
76
77
|
get fields() {
|
|
77
|
-
return Scope(this).membersOf(this, { tags: [ElementTag.Field] }) as FieldModel
|
|
78
|
+
return Scope(this).membersOf(this, { tags: [ElementTag.Field] }) as ModelIndex<FieldModel>;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
get conformant() {
|
|
82
|
+
return new ValueModel.Conformant(this);
|
|
78
83
|
}
|
|
79
84
|
|
|
80
85
|
/**
|
|
@@ -165,8 +170,8 @@ export abstract class ValueModel<T extends ValueElement = ValueElement>
|
|
|
165
170
|
/**
|
|
166
171
|
* All {@link FieldModel} children in the context of the model's containing scope.
|
|
167
172
|
*/
|
|
168
|
-
get members()
|
|
169
|
-
return Scope(this).membersOf(this) as PropertyModel
|
|
173
|
+
get members() {
|
|
174
|
+
return Scope(this).membersOf(this) as ModelIndex<PropertyModel>;
|
|
170
175
|
}
|
|
171
176
|
|
|
172
177
|
/**
|
|
@@ -294,3 +299,30 @@ export abstract class ValueModel<T extends ValueElement = ValueElement>
|
|
|
294
299
|
});
|
|
295
300
|
}
|
|
296
301
|
}
|
|
302
|
+
|
|
303
|
+
export namespace ValueModel {
|
|
304
|
+
export class Conformant {
|
|
305
|
+
#model: Model;
|
|
306
|
+
|
|
307
|
+
constructor(model: Model) {
|
|
308
|
+
this.#model = model;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* The model's conformant fields.
|
|
313
|
+
*/
|
|
314
|
+
get fields() {
|
|
315
|
+
return Scope(this.#model).membersOf(this.#model, {
|
|
316
|
+
tags: [ElementTag.Field],
|
|
317
|
+
conformance: "conformant",
|
|
318
|
+
}) as ModelIndex<FieldModel>;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* An alias for {@link fields} that offers compatibility with the same field for clusters.
|
|
323
|
+
*/
|
|
324
|
+
get properties() {
|
|
325
|
+
return this.fields;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|