@matter/model 0.11.9-alpha.0-20241203-06077d82e → 0.11.9-alpha.0-20241206-22f233334

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 (182) hide show
  1. package/dist/cjs/elements/MatterElement.d.ts +5 -1
  2. package/dist/cjs/elements/MatterElement.d.ts.map +1 -1
  3. package/dist/cjs/elements/MatterElement.js +1 -1
  4. package/dist/cjs/elements/MatterElement.js.map +1 -1
  5. package/dist/cjs/logic/DefaultValue.d.ts +3 -1
  6. package/dist/cjs/logic/DefaultValue.d.ts.map +1 -1
  7. package/dist/cjs/logic/DefaultValue.js +11 -11
  8. package/dist/cjs/logic/DefaultValue.js.map +1 -1
  9. package/dist/cjs/logic/ModelTraversal.d.ts +6 -35
  10. package/dist/cjs/logic/ModelTraversal.d.ts.map +1 -1
  11. package/dist/cjs/logic/ModelTraversal.js +15 -109
  12. package/dist/cjs/logic/ModelTraversal.js.map +1 -1
  13. package/dist/cjs/logic/ModelVariantTraversal.d.ts.map +1 -1
  14. package/dist/cjs/logic/ModelVariantTraversal.js.map +1 -1
  15. package/dist/cjs/logic/Scope.d.ts +102 -0
  16. package/dist/cjs/logic/Scope.d.ts.map +1 -0
  17. package/dist/cjs/logic/Scope.js +220 -0
  18. package/dist/cjs/logic/Scope.js.map +6 -0
  19. package/dist/cjs/logic/definition-validation/ModelValidator.d.ts.map +1 -1
  20. package/dist/cjs/logic/index.d.ts +1 -0
  21. package/dist/cjs/logic/index.d.ts.map +1 -1
  22. package/dist/cjs/logic/index.js +1 -0
  23. package/dist/cjs/logic/index.js.map +1 -1
  24. package/dist/cjs/models/AttributeModel.d.ts +20 -0
  25. package/dist/cjs/models/AttributeModel.d.ts.map +1 -1
  26. package/dist/cjs/models/AttributeModel.js +3 -0
  27. package/dist/cjs/models/AttributeModel.js.map +1 -1
  28. package/dist/cjs/models/Children.d.ts +4 -0
  29. package/dist/cjs/models/Children.d.ts.map +1 -1
  30. package/dist/cjs/models/Children.js +13 -0
  31. package/dist/cjs/models/Children.js.map +1 -1
  32. package/dist/cjs/models/ClusterModel.d.ts +6 -7
  33. package/dist/cjs/models/ClusterModel.d.ts.map +1 -1
  34. package/dist/cjs/models/ClusterModel.js +5 -38
  35. package/dist/cjs/models/ClusterModel.js.map +1 -1
  36. package/dist/cjs/models/CommandModel.d.ts +22 -0
  37. package/dist/cjs/models/CommandModel.d.ts.map +1 -1
  38. package/dist/cjs/models/CommandModel.js +3 -0
  39. package/dist/cjs/models/CommandModel.js.map +1 -1
  40. package/dist/cjs/models/DatatypeModel.js +0 -2
  41. package/dist/cjs/models/DatatypeModel.js.map +1 -1
  42. package/dist/cjs/models/EventModel.d.ts +21 -0
  43. package/dist/cjs/models/EventModel.d.ts.map +1 -1
  44. package/dist/cjs/models/EventModel.js +3 -0
  45. package/dist/cjs/models/EventModel.js.map +1 -1
  46. package/dist/cjs/models/MatterModel.d.ts +3 -3
  47. package/dist/cjs/models/MatterModel.d.ts.map +1 -1
  48. package/dist/cjs/models/MatterModel.js +6 -5
  49. package/dist/cjs/models/MatterModel.js.map +1 -1
  50. package/dist/cjs/models/Model.d.ts +10 -6
  51. package/dist/cjs/models/Model.d.ts.map +1 -1
  52. package/dist/cjs/models/Model.js +28 -9
  53. package/dist/cjs/models/Model.js.map +1 -1
  54. package/dist/cjs/models/ScopeModel.d.ts +22 -0
  55. package/dist/cjs/models/ScopeModel.d.ts.map +1 -0
  56. package/dist/cjs/models/ScopeModel.js +63 -0
  57. package/dist/cjs/models/ScopeModel.js.map +6 -0
  58. package/dist/cjs/models/ValueModel.d.ts +7 -21
  59. package/dist/cjs/models/ValueModel.d.ts.map +1 -1
  60. package/dist/cjs/models/ValueModel.js +15 -34
  61. package/dist/cjs/models/ValueModel.js.map +1 -1
  62. package/dist/cjs/models/index.d.ts +1 -0
  63. package/dist/cjs/models/index.d.ts.map +1 -1
  64. package/dist/cjs/models/index.js +1 -0
  65. package/dist/cjs/models/index.js.map +1 -1
  66. package/dist/cjs/standard/elements/ColorControl.js +3 -4
  67. package/dist/cjs/standard/elements/ColorControl.js.map +1 -1
  68. package/dist/cjs/standard/elements/ModeBase.js +1 -1
  69. package/dist/cjs/standard/elements/ModeBase.js.map +1 -1
  70. package/dist/cjs/standard/elements/PumpConfigurationAndControl.d.ts.map +1 -1
  71. package/dist/cjs/standard/elements/PumpConfigurationAndControl.js +3 -20
  72. package/dist/cjs/standard/elements/PumpConfigurationAndControl.js.map +1 -1
  73. package/dist/cjs/standard/elements/UserLabel.d.ts.map +1 -1
  74. package/dist/cjs/standard/elements/UserLabel.js +13 -16
  75. package/dist/cjs/standard/elements/UserLabel.js.map +1 -1
  76. package/dist/cjs/standard/elements/WildcardPathFlagsBitmap.d.ts.map +1 -1
  77. package/dist/cjs/standard/elements/WildcardPathFlagsBitmap.js +1 -5
  78. package/dist/cjs/standard/elements/WildcardPathFlagsBitmap.js.map +1 -1
  79. package/dist/cjs/standard/elements/WindowCovering.js +2 -2
  80. package/dist/esm/elements/MatterElement.d.ts +5 -1
  81. package/dist/esm/elements/MatterElement.d.ts.map +1 -1
  82. package/dist/esm/elements/MatterElement.js +1 -1
  83. package/dist/esm/elements/MatterElement.js.map +1 -1
  84. package/dist/esm/logic/DefaultValue.d.ts +3 -1
  85. package/dist/esm/logic/DefaultValue.d.ts.map +1 -1
  86. package/dist/esm/logic/DefaultValue.js +11 -11
  87. package/dist/esm/logic/DefaultValue.js.map +1 -1
  88. package/dist/esm/logic/ModelTraversal.d.ts +6 -35
  89. package/dist/esm/logic/ModelTraversal.d.ts.map +1 -1
  90. package/dist/esm/logic/ModelTraversal.js +16 -110
  91. package/dist/esm/logic/ModelTraversal.js.map +1 -1
  92. package/dist/esm/logic/ModelVariantTraversal.d.ts.map +1 -1
  93. package/dist/esm/logic/ModelVariantTraversal.js.map +1 -1
  94. package/dist/esm/logic/Scope.d.ts +102 -0
  95. package/dist/esm/logic/Scope.d.ts.map +1 -0
  96. package/dist/esm/logic/Scope.js +200 -0
  97. package/dist/esm/logic/Scope.js.map +6 -0
  98. package/dist/esm/logic/definition-validation/ModelValidator.d.ts.map +1 -1
  99. package/dist/esm/logic/index.d.ts +1 -0
  100. package/dist/esm/logic/index.d.ts.map +1 -1
  101. package/dist/esm/logic/index.js +1 -0
  102. package/dist/esm/logic/index.js.map +1 -1
  103. package/dist/esm/models/AttributeModel.d.ts +20 -0
  104. package/dist/esm/models/AttributeModel.d.ts.map +1 -1
  105. package/dist/esm/models/AttributeModel.js +3 -0
  106. package/dist/esm/models/AttributeModel.js.map +1 -1
  107. package/dist/esm/models/Children.d.ts +4 -0
  108. package/dist/esm/models/Children.d.ts.map +1 -1
  109. package/dist/esm/models/Children.js +13 -0
  110. package/dist/esm/models/Children.js.map +1 -1
  111. package/dist/esm/models/ClusterModel.d.ts +6 -7
  112. package/dist/esm/models/ClusterModel.d.ts.map +1 -1
  113. package/dist/esm/models/ClusterModel.js +5 -38
  114. package/dist/esm/models/ClusterModel.js.map +1 -1
  115. package/dist/esm/models/CommandModel.d.ts +22 -0
  116. package/dist/esm/models/CommandModel.d.ts.map +1 -1
  117. package/dist/esm/models/CommandModel.js +3 -0
  118. package/dist/esm/models/CommandModel.js.map +1 -1
  119. package/dist/esm/models/DatatypeModel.js +0 -2
  120. package/dist/esm/models/DatatypeModel.js.map +1 -1
  121. package/dist/esm/models/EventModel.d.ts +21 -0
  122. package/dist/esm/models/EventModel.d.ts.map +1 -1
  123. package/dist/esm/models/EventModel.js +3 -0
  124. package/dist/esm/models/EventModel.js.map +1 -1
  125. package/dist/esm/models/MatterModel.d.ts +3 -3
  126. package/dist/esm/models/MatterModel.d.ts.map +1 -1
  127. package/dist/esm/models/MatterModel.js +6 -5
  128. package/dist/esm/models/MatterModel.js.map +1 -1
  129. package/dist/esm/models/Model.d.ts +10 -6
  130. package/dist/esm/models/Model.d.ts.map +1 -1
  131. package/dist/esm/models/Model.js +28 -9
  132. package/dist/esm/models/Model.js.map +1 -1
  133. package/dist/esm/models/ScopeModel.d.ts +22 -0
  134. package/dist/esm/models/ScopeModel.d.ts.map +1 -0
  135. package/dist/esm/models/ScopeModel.js +43 -0
  136. package/dist/esm/models/ScopeModel.js.map +6 -0
  137. package/dist/esm/models/ValueModel.d.ts +7 -21
  138. package/dist/esm/models/ValueModel.d.ts.map +1 -1
  139. package/dist/esm/models/ValueModel.js +15 -34
  140. package/dist/esm/models/ValueModel.js.map +1 -1
  141. package/dist/esm/models/index.d.ts +1 -0
  142. package/dist/esm/models/index.d.ts.map +1 -1
  143. package/dist/esm/models/index.js +1 -0
  144. package/dist/esm/models/index.js.map +1 -1
  145. package/dist/esm/standard/elements/ColorControl.js +3 -4
  146. package/dist/esm/standard/elements/ColorControl.js.map +1 -1
  147. package/dist/esm/standard/elements/ModeBase.js +1 -1
  148. package/dist/esm/standard/elements/ModeBase.js.map +1 -1
  149. package/dist/esm/standard/elements/PumpConfigurationAndControl.d.ts.map +1 -1
  150. package/dist/esm/standard/elements/PumpConfigurationAndControl.js +3 -20
  151. package/dist/esm/standard/elements/PumpConfigurationAndControl.js.map +1 -1
  152. package/dist/esm/standard/elements/UserLabel.d.ts.map +1 -1
  153. package/dist/esm/standard/elements/UserLabel.js +13 -16
  154. package/dist/esm/standard/elements/UserLabel.js.map +1 -1
  155. package/dist/esm/standard/elements/WildcardPathFlagsBitmap.d.ts.map +1 -1
  156. package/dist/esm/standard/elements/WildcardPathFlagsBitmap.js +1 -5
  157. package/dist/esm/standard/elements/WildcardPathFlagsBitmap.js.map +1 -1
  158. package/dist/esm/standard/elements/WindowCovering.js +2 -2
  159. package/package.json +4 -4
  160. package/src/elements/MatterElement.ts +7 -2
  161. package/src/logic/DefaultValue.ts +13 -11
  162. package/src/logic/ModelTraversal.ts +28 -147
  163. package/src/logic/ModelVariantTraversal.ts +0 -1
  164. package/src/logic/Scope.ts +400 -0
  165. package/src/logic/index.ts +1 -0
  166. package/src/models/AttributeModel.ts +4 -0
  167. package/src/models/Children.ts +24 -1
  168. package/src/models/ClusterModel.ts +12 -51
  169. package/src/models/CommandModel.ts +4 -0
  170. package/src/models/DatatypeModel.ts +0 -2
  171. package/src/models/EventModel.ts +4 -0
  172. package/src/models/MatterModel.ts +6 -5
  173. package/src/models/Model.ts +38 -12
  174. package/src/models/ScopeModel.ts +55 -0
  175. package/src/models/ValueModel.ts +17 -39
  176. package/src/models/index.ts +1 -0
  177. package/src/standard/elements/ColorControl.ts +4 -4
  178. package/src/standard/elements/ModeBase.ts +1 -1
  179. package/src/standard/elements/PumpConfigurationAndControl.ts +2 -18
  180. package/src/standard/elements/UserLabel.ts +8 -12
  181. package/src/standard/elements/WildcardPathFlagsBitmap.ts +1 -4
  182. package/src/standard/elements/WindowCovering.ts +2 -2
@@ -9,6 +9,7 @@ import { ElementTag, FieldValue, Metatype } from "../common/index.js";
9
9
  import { Model } from "../models/Model.js";
10
10
  import type { ValueModel } from "../models/ValueModel.js";
11
11
  import { FeatureMap } from "../standard/elements/FeatureMap.js";
12
+ import { Scope } from "./Scope.js";
12
13
 
13
14
  /**
14
15
  * Obtain a native JS default value for a ValueModel.
@@ -17,13 +18,14 @@ import { FeatureMap } from "../standard/elements/FeatureMap.js";
17
18
  * structural issues but generally returns undefined if the model's default value cannot be converted to the correct
18
19
  * type.
19
20
  *
21
+ * @param scope the scope in which the model is referenced
20
22
  * @param model the model from which the default value is extracted
21
23
  * @param ifValid some structs only have partial defaults defined so would be invalid; do not return these
22
24
  */
23
- export function DefaultValue(model: ValueModel, ifValid = false): any {
25
+ export function DefaultValue(scope: Scope, model: ValueModel, ifValid = false): any {
24
26
  const value = castValue(model, model.default);
25
27
  if (value === undefined) {
26
- return buildValue(model, ifValid);
28
+ return buildValue(scope, model, ifValid);
27
29
  }
28
30
  return value;
29
31
  }
@@ -117,7 +119,7 @@ function castValue(model: ValueModel, modelDefault?: FieldValue): unknown {
117
119
  /**
118
120
  * When an explicit default value is not present, for some types we generate a default from the structure.
119
121
  */
120
- function buildValue(model: ValueModel, ifValid: boolean) {
122
+ function buildValue(scope: Scope, model: ValueModel, ifValid: boolean) {
121
123
  switch (model.effectiveMetatype) {
122
124
  case Metatype.array:
123
125
  // We don't really build default array values except in the case of non-nullable arrays where zero items is
@@ -133,23 +135,23 @@ function buildValue(model: ValueModel, ifValid: boolean) {
133
135
  return;
134
136
 
135
137
  case Metatype.object:
136
- return buildObject(model, ifValid);
138
+ return buildObject(scope, model, ifValid);
137
139
 
138
140
  case Metatype.bitmap:
139
- return buildBitmap(model);
141
+ return buildBitmap(scope, model);
140
142
  }
141
143
  }
142
144
 
143
- function buildObject(model: ValueModel, ifValid: boolean) {
145
+ function buildObject(scope: Scope, model: ValueModel, ifValid: boolean) {
144
146
  let result: { [key: string]: any } | undefined;
145
147
 
146
- for (const child of model.conformantMembers) {
148
+ for (const child of scope.membersOf(model, { conformance: "conformant" })) {
147
149
  const name = camelize(child.name);
148
150
  if (result && result[name] !== undefined) {
149
151
  continue;
150
152
  }
151
153
 
152
- const value = child.effectiveDefault;
154
+ const value = DefaultValue(scope, child);
153
155
  if (value !== undefined) {
154
156
  if (!result) {
155
157
  result = {};
@@ -168,11 +170,11 @@ function buildObject(model: ValueModel, ifValid: boolean) {
168
170
  return result;
169
171
  }
170
172
 
171
- function buildBitmap(model: ValueModel) {
173
+ function buildBitmap(scope: Scope, model: ValueModel) {
172
174
  let result;
173
175
  let fieldsDefined = 0;
174
176
 
175
- for (const m of model.conformantMembers) {
177
+ for (const m of scope.membersOf(model, { conformance: "conformant" })) {
176
178
  const defaultValue = FieldValue.numericValue(m.default);
177
179
  if (defaultValue === undefined) {
178
180
  continue;
@@ -228,7 +230,7 @@ function decodeBitmap(model: ValueModel, value: number | bigint) {
228
230
  }
229
231
 
230
232
  const definition = model.bitDefinition(bit);
231
- if (!definition || definition.isDeprecated) {
233
+ if (!definition) {
232
234
  continue;
233
235
  }
234
236
 
@@ -6,11 +6,9 @@
6
6
 
7
7
  import { InternalError } from "@matter/general";
8
8
  import { Access, Aspect, Constraint } from "../aspects/index.js";
9
- import { SchemaImplementationError } from "../common/errors.js";
10
- import { ElementTag, FeatureSet, FieldValue, Metatype } from "../common/index.js";
9
+ import { ElementTag, FieldValue, Metatype } from "../common/index.js";
11
10
  import { AnyElement } from "../elements/index.js";
12
11
  import { Children } from "../models/Children.js";
13
- import { PropertyModel, type ClusterModel, type CommandModel, type Model, type ValueModel } from "../models/index.js";
14
12
  import {
15
13
  enum16,
16
14
  enum8,
@@ -24,14 +22,13 @@ import {
24
22
  uint8,
25
23
  } from "../standard/elements/definitions.js";
26
24
 
25
+ // These must be types to avoid circular references
26
+ import type { CommandModel, Model, ScopeModel, ValueModel } from "../models/index.js";
27
+
27
28
  const OPERATION_DEPTH_LIMIT = 20;
28
29
 
29
30
  let memos: Memos | undefined;
30
31
 
31
- // Member caches. Only populated for frozen models
32
- const activeMemberCache = new WeakMap<Model, ValueModel[]>();
33
- const conformantMemberCache = new WeakMap<Model, ValueModel[]>();
34
-
35
32
  /**
36
33
  * This class performs lookups of models in the scope of a specific model. We use a class so the lookup can maintain
37
34
  * state and guard against circular references.
@@ -173,11 +170,8 @@ export class ModelTraversal {
173
170
  }
174
171
 
175
172
  const findBaseOp = () => {
176
- // If I override another element (same identity and tag in parent's inheritance hierarchy) then I implicitly
177
- // inherit from the shadow.
178
- //
179
- // Semantics would be wonky if the model designates a different type than the shadow, but we support this by
180
- // ignoring the shadow in this case.
173
+ // If I override another element (same identity and tag in parent's inheritance hierarchy) and don't specify
174
+ // a type then I implicitly inherit from the shadow.
181
175
  const shadow = this.findShadow(model);
182
176
  if (
183
177
  shadow !== undefined &&
@@ -466,126 +460,6 @@ export class ModelTraversal {
466
460
  });
467
461
  }
468
462
 
469
- /**
470
- * Retrieve all children of a specific type, including those inherited from the base or a shadow. Does not include
471
- * members overridden by a deeper member.
472
- */
473
- findChildren(scope: Model, tags: ElementTag[]) {
474
- const members = Array<Model>();
475
-
476
- // This is a map of identity (based on tag + id/name + discriminator) to a priority based on inheritance depth
477
- const defined = {} as Record<string, number | undefined>;
478
-
479
- let level = 0;
480
- const childSearchVisitor = (model: Model) => {
481
- level++;
482
- for (const child of model.children) {
483
- if (!tags.includes(child.tag)) {
484
- continue;
485
- }
486
-
487
- // Identify and skip shadows based on ID
488
- let numericIdentity;
489
- if (child.id !== undefined) {
490
- numericIdentity = `i␜${child.tag}␜${child.id}␜${child.discriminator ?? ""}`;
491
- const numericLevel = defined[numericIdentity];
492
- if (numericLevel !== undefined && numericLevel < level) {
493
- continue;
494
- }
495
- }
496
-
497
- // Identify and skip shadows based on name
498
- const nameIdentity = `s␜${child.tag}␜${child.name}␜${child.discriminator ?? ""}`;
499
- const nameLevel = defined[nameIdentity];
500
- if (nameLevel !== undefined && nameLevel < level) {
501
- continue;
502
- }
503
-
504
- // Mark the level in which we saw these members
505
- if (numericIdentity) {
506
- defined[numericIdentity] = level;
507
- }
508
- defined[nameIdentity] = level;
509
-
510
- // Found a member
511
- members.push(child);
512
- }
513
- };
514
- this.visitInheritance(scope, childSearchVisitor);
515
-
516
- return members;
517
- }
518
-
519
- /**
520
- * Filter a model's members as follows:
521
- *
522
- * - If the member is deprecated, ignore it
523
- *
524
- * - If there is only a single member of a given name, select that member
525
- *
526
- * - If there are multiple members with the same name but there is no cluster throw an error
527
- *
528
- * - If there are multiple members with the same name, use conformance to select the member that is applicable
529
- * based on active features in the provided cluster
530
- *
531
- * - If there are multiple applicable members based on conformance the definitions conflict and throw an error
532
- *
533
- * If the model is frozen we cache the return value.
534
- *
535
- * Note that "active" in this case does not imply the member is conformant, only that conflicts are resolved.
536
- *
537
- * Note 2 - members may not be differentiated with conformance rules that rely on field values in this way. That
538
- * will probably never be necessary and would require an entirely different (more complicated) structure.
539
- */
540
- findActiveMembers(scope: Model & { members: PropertyModel[] }, conformantOnly: boolean, cluster?: ClusterModel) {
541
- const cache = Object.isFrozen(scope) ? (conformantOnly ? conformantMemberCache : activeMemberCache) : undefined;
542
-
543
- const cached = cache?.get(scope);
544
- if (cached) {
545
- return cached;
546
- }
547
-
548
- const features = cluster?.featureNames ?? new FeatureSet();
549
- const supportedFeatures = cluster?.supportedFeatures ?? new FeatureSet();
550
-
551
- const selectedMembers = {} as Record<string, ValueModel>;
552
- for (const member of scope.members) {
553
- if (member.isDeprecated) {
554
- continue;
555
- }
556
-
557
- if (conformantOnly && !member.conformance.isApplicable(features, supportedFeatures)) {
558
- continue;
559
- }
560
-
561
- const other = selectedMembers[member.name];
562
- if (other !== undefined) {
563
- if (!conformantOnly && !member.conformance.isApplicable(features, supportedFeatures)) {
564
- continue;
565
- }
566
-
567
- if (other.conformance.isApplicable(features, supportedFeatures)) {
568
- throw new SchemaImplementationError(
569
- scope,
570
- `There are multiple definitions of "${member.name}" that cannot be differentiated by conformance`,
571
- );
572
- }
573
-
574
- // This member takes precedence and will overwrite below
575
- }
576
-
577
- selectedMembers[member.name] = member;
578
- }
579
-
580
- const result = Object.values(selectedMembers);
581
-
582
- if (cache) {
583
- cache.set(scope, result);
584
- }
585
-
586
- return result;
587
- }
588
-
589
463
  /**
590
464
  * Search inherited scope for a bit definition.
591
465
  */
@@ -615,21 +489,21 @@ export class ModelTraversal {
615
489
  /**
616
490
  * Search inherited and structural type scope for a named type.
617
491
  */
618
- findType(scope: Model | undefined, name: string, tag: ElementTag): Model | undefined {
619
- if (!scope) {
492
+ findType(owner: Model | undefined, name: string, tag: ElementTag): Model | undefined {
493
+ if (!owner) {
620
494
  return;
621
495
  }
622
496
 
623
497
  const memoKey = `${name} ${tag}`;
624
- const memosForScope = memos?.types.get(scope);
498
+ const memosForScope = memos?.types.get(owner);
625
499
  if (memosForScope && memoKey in memosForScope) {
626
500
  return memosForScope[memoKey];
627
501
  }
628
502
 
629
503
  const findTypeOp = () => {
630
- const queue = Array<Model>(scope as Model);
631
- for (scope = queue.shift(); scope; scope = queue.shift()) {
632
- if (scope.isTypeScope) {
504
+ const queue = Array<Model>(owner);
505
+ for (let scope = queue.shift(); scope; scope = queue.shift()) {
506
+ if ((scope as ScopeModel).isScope) {
633
507
  const result = scope.children.select(name, tag, this.#dismissed);
634
508
  if (result) {
635
509
  return result;
@@ -648,15 +522,22 @@ export class ModelTraversal {
648
522
  queue.push(parent);
649
523
  }
650
524
  }
525
+
526
+ // If the model is not part of a MatterModel hierarchy, findBase and findParent will use the fallback model for
527
+ // resolution. However, if the model is part of an incomplete MatterModel hierarchy, that logic is not
528
+ // triggered. So handle the case where a global type is missing here
529
+ if (ModelTraversal.fallbackScope && owner !== ModelTraversal.fallbackScope) {
530
+ return this.findType(ModelTraversal.fallbackScope, name, tag);
531
+ }
651
532
  };
652
533
  const type = this.operation(findTypeOp);
653
534
 
654
535
  if (memos) {
655
- const memosForScope = memos.types.get(scope);
536
+ const memosForScope = memos.types.get(owner);
656
537
  if (memosForScope) {
657
538
  memosForScope[memoKey] = type;
658
539
  } else {
659
- memos.types.set(scope, { [memoKey]: type });
540
+ memos.types.set(owner, { [memoKey]: type });
660
541
  }
661
542
  }
662
543
 
@@ -666,8 +547,8 @@ export class ModelTraversal {
666
547
  /**
667
548
  * Similar to findType but operates with a qualified type name.
668
549
  *
669
- * Unlike findType, a qualified type may reference an element parented by any other, not just those with
670
- * parent.isTypeScope === true.
550
+ * Unlike findType, a qualified type may reference an element parented by any other, not just those within
551
+ * ScopeModels.
671
552
  *
672
553
  * This is quite complicated and would be painfully slow except in practice we don't use many qualified types and
673
554
  * those we do use resolve with few failing branches in the search once the root qualifier of the name matches.
@@ -835,7 +716,7 @@ export class ModelTraversal {
835
716
  return false;
836
717
  }
837
718
  const base = this.findBase(model);
838
- this.visitInheritance(base, visitor);
719
+ return this.visitInheritance(base, visitor);
839
720
  });
840
721
  }
841
722
 
@@ -863,15 +744,15 @@ export class ModelTraversal {
863
744
  /**
864
745
  * Find an owner that defines type scope for a model.
865
746
  */
866
- findScope(model?: Model): Model | undefined {
747
+ findScope(model?: Model): ScopeModel | undefined {
867
748
  if (model === undefined) {
868
749
  return;
869
750
  }
870
751
 
871
752
  // First, examine parents
872
753
  if (model.parent) {
873
- if (model.parent.isTypeScope) {
874
- return model.parent;
754
+ if ((model.parent as ScopeModel).isScope) {
755
+ return model.parent as ScopeModel;
875
756
  }
876
757
 
877
758
  return this.operationWithDismissal(model, () => this.findScope(model.parent));
@@ -890,7 +771,7 @@ export class ModelTraversal {
890
771
  * If a model is not owned by a MatterModel, global resolution won't work. This model acts as a fallback to work
891
772
  * around this.
892
773
  */
893
- static fallbackScope: Model | undefined;
774
+ static fallbackScope: ScopeModel | undefined;
894
775
 
895
776
  /**
896
777
  * This is a cheap hack to optimize analysis of large static models. It temporarily memoizes key operations.
@@ -321,7 +321,6 @@ export abstract class ModelVariantTraversal<S = void> {
321
321
  // For each applicable child of this variant, associated it with a slot
322
322
  for (let i = 0; i < variant.children.length; i++) {
323
323
  const child = variant.children[i];
324
-
325
324
  if (!child.appliesTo(this.revision)) {
326
325
  continue;
327
326
  }