From 3c09d9aecd365be4db4b4df6715e8d496ff4e01b Mon Sep 17 00:00:00 2001 From: "Travis.Cobbs" <77415528+tcobbs-bentley@users.noreply.github.com> Date: Fri, 8 Aug 2025 14:38:38 -0600 Subject: [PATCH 01/15] Get rid of lint warnings in core/ec* --- .../ecschema-editing/src/Editing/Constants.ts | 2 +- .../src/Editing/CustomAttributes.ts | 2 +- core/ecschema-editing/src/Editing/Entities.ts | 2 +- .../src/Editing/Enumerations.ts | 2 +- .../ecschema-editing/src/Editing/Exception.ts | 2 +- core/ecschema-editing/src/Editing/Formats.ts | 2 +- .../src/Editing/InvertedUnits.ts | 2 +- .../src/Editing/KindOfQuantities.ts | 2 +- core/ecschema-editing/src/Editing/Mixins.ts | 2 +- .../ecschema-editing/src/Editing/Phenomena.ts | 2 +- .../src/Editing/PropertyCategories.ts | 2 +- .../src/Editing/RelationshipClasses.ts | 7 +-- core/ecschema-editing/src/Editing/Structs.ts | 2 +- .../src/Editing/UnitSystems.ts | 2 +- core/ecschema-editing/src/Editing/Units.ts | 2 +- .../src/Merging/EnumerationMerger.ts | 2 +- .../src/Merging/RelationshipClassMerger.ts | 2 +- .../src/Merging/SchemaReferenceMerger.ts | 2 +- .../src/Validation/DiagnosticReporter.ts | 1 + .../src/Validation/ECRules.ts | 3 +- .../src/Validation/SchemaChanges.ts | 46 ++++++++--------- .../src/StubSchemaXmlFileLocater.ts | 3 +- .../src/Deserialization/Helper.ts | 49 +++++++++++++------ .../src/Deserialization/JsonParser.ts | 40 +++++++-------- .../IncrementalLoading/ECSqlSchemaLocater.ts | 29 ++++++----- .../IncrementalSchemaLocater.ts | 9 ++-- .../IncrementalSchemaReader.ts | 6 ++- .../src/IncrementalLoading/SchemaParser.ts | 3 +- core/ecschema-metadata/src/Metadata/Class.ts | 4 +- .../src/Metadata/EntityClass.ts | 4 +- .../src/Metadata/InvertedUnit.ts | 5 +- .../src/Metadata/KindOfQuantity.ts | 3 +- .../src/Metadata/OverrideFormat.ts | 2 +- .../src/Metadata/Property.ts | 11 +++-- .../src/Metadata/RelationshipClass.ts | 3 +- core/ecschema-metadata/src/Metadata/Schema.ts | 2 +- .../src/Metadata/SchemaItem.ts | 4 +- core/ecschema-metadata/src/Metadata/Unit.ts | 5 +- .../src/SchemaFormatsProvider.ts | 2 + .../src/UnitConversion/Parser.ts | 4 +- .../src/UnitConversion/UnitTree.ts | 4 +- .../test/UnitProvider/UnitProvider.test.ts | 6 +-- core/ecsql/common/src/ECSqlAst.ts | 2 +- 43 files changed, 164 insertions(+), 127 deletions(-) diff --git a/core/ecschema-editing/src/Editing/Constants.ts b/core/ecschema-editing/src/Editing/Constants.ts index cd96ecba28c7..b128d8df4c28 100644 --- a/core/ecschema-editing/src/Editing/Constants.ts +++ b/core/ecschema-editing/src/Editing/Constants.ts @@ -59,7 +59,7 @@ export class Constants extends SchemaItems { const newConstant = await this.createSchemaItemFromProps(schemaKey, this.schemaItemType, (schema) => schema.createConstant.bind(schema), constantProps); return newConstant.key; } catch (e: any) { - throw new SchemaEditingError(ECEditingStatus.CreateSchemaItemFromProps, new SchemaItemId(this.schemaItemType, constantProps.name!, schemaKey), e); + throw new SchemaEditingError(ECEditingStatus.CreateSchemaItemFromProps, new SchemaItemId(this.schemaItemType, constantProps.name ?? "", schemaKey), e); } } } diff --git a/core/ecschema-editing/src/Editing/CustomAttributes.ts b/core/ecschema-editing/src/Editing/CustomAttributes.ts index 9ec23ed0c5fb..337a3fb987e8 100644 --- a/core/ecschema-editing/src/Editing/CustomAttributes.ts +++ b/core/ecschema-editing/src/Editing/CustomAttributes.ts @@ -53,7 +53,7 @@ export class CustomAttributes extends ECClasses { const newClass = await this.createSchemaItemFromProps(schemaKey, this.schemaItemType, (schema) => schema.createCustomAttributeClass.bind(schema), caProps); return newClass.key; } catch (e: any) { - throw new SchemaEditingError(ECEditingStatus.CreateSchemaItemFromProps, new ClassId(this.schemaItemType, caProps.name!, schemaKey), e); + throw new SchemaEditingError(ECEditingStatus.CreateSchemaItemFromProps, new ClassId(this.schemaItemType, caProps.name ?? "", schemaKey), e); } } } diff --git a/core/ecschema-editing/src/Editing/Entities.ts b/core/ecschema-editing/src/Editing/Entities.ts index acde75ad15c8..1d74da1bfc41 100644 --- a/core/ecschema-editing/src/Editing/Entities.ts +++ b/core/ecschema-editing/src/Editing/Entities.ts @@ -99,7 +99,7 @@ export class Entities extends ECClasses { const newClass = await this.createSchemaItemFromProps(schemaKey, this.schemaItemType, (schema) => schema.createEntityClass.bind(schema), entityProps); return newClass.key; } catch (e: any) { - throw new SchemaEditingError(ECEditingStatus.CreateSchemaItemFromProps, new ClassId(this.schemaItemType, entityProps.name!, schemaKey), e); + throw new SchemaEditingError(ECEditingStatus.CreateSchemaItemFromProps, new ClassId(this.schemaItemType, entityProps.name ?? "", schemaKey), e); } } diff --git a/core/ecschema-editing/src/Editing/Enumerations.ts b/core/ecschema-editing/src/Editing/Enumerations.ts index b64737706355..a6ac57202109 100644 --- a/core/ecschema-editing/src/Editing/Enumerations.ts +++ b/core/ecschema-editing/src/Editing/Enumerations.ts @@ -59,7 +59,7 @@ export class Enumerations extends SchemaItems { const newEnum = await this.createSchemaItemFromProps(schemaKey, this.schemaItemType, (schema) => schema.createEnumeration.bind(schema), enumProps); return newEnum.key; } catch (e: any) { - throw new SchemaEditingError(ECEditingStatus.CreateSchemaItemFromProps, new SchemaItemId(this.schemaItemType, enumProps.name!, schemaKey), e); + throw new SchemaEditingError(ECEditingStatus.CreateSchemaItemFromProps, new SchemaItemId(this.schemaItemType, enumProps.name ?? "", schemaKey), e); } } diff --git a/core/ecschema-editing/src/Editing/Exception.ts b/core/ecschema-editing/src/Editing/Exception.ts index b8d3988d6f92..0ec4929a14ec 100644 --- a/core/ecschema-editing/src/Editing/Exception.ts +++ b/core/ecschema-editing/src/Editing/Exception.ts @@ -253,7 +253,7 @@ export class SchemaItemId implements ISchemaItemIdentifier { if (!schemaKey) throw new Error("schemaKey if required if the specified schemaItem the name of the schema item."); - this.schemaKey = schemaKey!; + this.schemaKey = schemaKey; this.schemaItemKey = new SchemaItemKey(schemaItemKeyOrName, schemaKey); } else { this.schemaKey = schemaItemKeyOrName.schemaKey; diff --git a/core/ecschema-editing/src/Editing/Formats.ts b/core/ecschema-editing/src/Editing/Formats.ts index 5ac5ce908bdf..1ebb2a71fa46 100644 --- a/core/ecschema-editing/src/Editing/Formats.ts +++ b/core/ecschema-editing/src/Editing/Formats.ts @@ -68,7 +68,7 @@ export class Formats extends SchemaItems { const newFormat = await this.createSchemaItemFromProps(schemaKey, this.schemaItemType, (schema) => schema.createFormat.bind(schema), formatProps); return newFormat.key; } catch (e: any) { - throw new SchemaEditingError(ECEditingStatus.CreateSchemaItemFromProps, new SchemaItemId(this.schemaItemType, formatProps.name!, schemaKey), e); + throw new SchemaEditingError(ECEditingStatus.CreateSchemaItemFromProps, new SchemaItemId(this.schemaItemType, formatProps.name ?? "", schemaKey), e); } } } diff --git a/core/ecschema-editing/src/Editing/InvertedUnits.ts b/core/ecschema-editing/src/Editing/InvertedUnits.ts index db54436a6655..70239057f4e9 100644 --- a/core/ecschema-editing/src/Editing/InvertedUnits.ts +++ b/core/ecschema-editing/src/Editing/InvertedUnits.ts @@ -51,7 +51,7 @@ export class InvertedUnits extends SchemaItems { const newUnit = await this.createSchemaItemFromProps(schemaKey, this.schemaItemType, (schema) => schema.createInvertedUnit.bind(schema), invertedUnitProps); return newUnit.key; } catch (e: any) { - throw new SchemaEditingError(ECEditingStatus.CreateSchemaItemFromProps, new SchemaItemId(this.schemaItemType, invertedUnitProps.name!, schemaKey), e); + throw new SchemaEditingError(ECEditingStatus.CreateSchemaItemFromProps, new SchemaItemId(this.schemaItemType, invertedUnitProps.name ?? "", schemaKey), e); } } diff --git a/core/ecschema-editing/src/Editing/KindOfQuantities.ts b/core/ecschema-editing/src/Editing/KindOfQuantities.ts index 722f5f1dff46..b0600de1f41e 100644 --- a/core/ecschema-editing/src/Editing/KindOfQuantities.ts +++ b/core/ecschema-editing/src/Editing/KindOfQuantities.ts @@ -58,7 +58,7 @@ export class KindOfQuantities extends SchemaItems { const koqItem = await this.createSchemaItemFromProps(schemaKey, this.schemaItemType, (schema) => schema.createKindOfQuantity.bind(schema), koqProps); return koqItem.key; } catch (e: any) { - throw new SchemaEditingError(ECEditingStatus.CreateSchemaItemFromProps, new SchemaItemId(this.schemaItemType, koqProps.name!, schemaKey), e); + throw new SchemaEditingError(ECEditingStatus.CreateSchemaItemFromProps, new SchemaItemId(this.schemaItemType, koqProps.name ?? "", schemaKey), e); } } diff --git a/core/ecschema-editing/src/Editing/Mixins.ts b/core/ecschema-editing/src/Editing/Mixins.ts index 3beb7f09e5e4..2a8466df2577 100644 --- a/core/ecschema-editing/src/Editing/Mixins.ts +++ b/core/ecschema-editing/src/Editing/Mixins.ts @@ -60,7 +60,7 @@ export class Mixins extends ECClasses { const newClass = await this.createSchemaItemFromProps(schemaKey, this.schemaItemType, (schema) => schema.createMixinClass.bind(schema), mixinProps); return newClass.key; } catch (e: any) { - throw new SchemaEditingError(ECEditingStatus.CreateSchemaItemFromProps, new ClassId(this.schemaItemType, mixinProps.name!, schemaKey), e); + throw new SchemaEditingError(ECEditingStatus.CreateSchemaItemFromProps, new ClassId(this.schemaItemType, mixinProps.name ?? "", schemaKey), e); } } diff --git a/core/ecschema-editing/src/Editing/Phenomena.ts b/core/ecschema-editing/src/Editing/Phenomena.ts index 0452a728f66d..4e0d6d95ef51 100644 --- a/core/ecschema-editing/src/Editing/Phenomena.ts +++ b/core/ecschema-editing/src/Editing/Phenomena.ts @@ -45,7 +45,7 @@ export class Phenomena extends SchemaItems { const newPhenomenon = await this.createSchemaItemFromProps(schemaKey, this.schemaItemType, (schema) => schema.createPhenomenon.bind(schema), phenomenonProps); return newPhenomenon.key; } catch (e: any) { - throw new SchemaEditingError(ECEditingStatus.CreateSchemaItemFromProps, new SchemaItemId(this.schemaItemType, phenomenonProps.name!, schemaKey), e); + throw new SchemaEditingError(ECEditingStatus.CreateSchemaItemFromProps, new SchemaItemId(this.schemaItemType, phenomenonProps.name ?? "", schemaKey), e); } } } diff --git a/core/ecschema-editing/src/Editing/PropertyCategories.ts b/core/ecschema-editing/src/Editing/PropertyCategories.ts index 48762302c85c..fd38b411f549 100644 --- a/core/ecschema-editing/src/Editing/PropertyCategories.ts +++ b/core/ecschema-editing/src/Editing/PropertyCategories.ts @@ -43,7 +43,7 @@ export class PropertyCategories extends SchemaItems { const newPropCategory = await this.createSchemaItemFromProps(schemaKey, this.schemaItemType, (schema) => schema.createPropertyCategory.bind(schema), propertyCategoryProps); return newPropCategory.key; } catch (e: any) { - throw new SchemaEditingError(ECEditingStatus.CreateSchemaItemFromProps, new SchemaItemId(this.schemaItemType, propertyCategoryProps.name!, schemaKey), e); + throw new SchemaEditingError(ECEditingStatus.CreateSchemaItemFromProps, new SchemaItemId(this.schemaItemType, propertyCategoryProps.name ?? "", schemaKey), e); } } diff --git a/core/ecschema-editing/src/Editing/RelationshipClasses.ts b/core/ecschema-editing/src/Editing/RelationshipClasses.ts index 69e3eb298b20..93413fba5298 100644 --- a/core/ecschema-editing/src/Editing/RelationshipClasses.ts +++ b/core/ecschema-editing/src/Editing/RelationshipClasses.ts @@ -6,6 +6,7 @@ * @module Editing */ +import { expectDefined } from "@itwin/core-bentley"; import { CustomAttribute, DelayedPromiseWithProps, ECClass, ECClassModifier, EntityClass, LazyLoadedRelationshipConstraintClass, Mixin, NavigationPropertyProps, RelationshipClass, RelationshipClassProps, RelationshipConstraint, RelationshipEnd, RelationshipMultiplicity, SchemaItemKey, SchemaItemType, @@ -102,7 +103,7 @@ export class RelationshipClasses extends ECClasses { return newClass.key; } catch (e: any) { - throw new SchemaEditingError(ECEditingStatus.CreateSchemaItemFromProps, new ClassId(this.schemaItemType, relationshipProps.name!, schemaKey), e); + throw new SchemaEditingError(ECEditingStatus.CreateSchemaItemFromProps, new ClassId(this.schemaItemType, relationshipProps.name ?? "", schemaKey), e); } } @@ -121,9 +122,9 @@ export class RelationshipClasses extends ECClasses { await super.setBaseClass(itemKey, baseClassKey); try { - await this.validate(relClass!); + await this.validate(expectDefined(relClass)); } catch(e: any) { - await (relClass! as ECClass as MutableClass).setBaseClass(baseClass); + await (expectDefined(relClass) as ECClass as MutableClass).setBaseClass(baseClass); throw new SchemaEditingError(ECEditingStatus.SetBaseClass, new ClassId(SchemaItemType.RelationshipClass, itemKey), e); } } diff --git a/core/ecschema-editing/src/Editing/Structs.ts b/core/ecschema-editing/src/Editing/Structs.ts index f2b5770345a6..08b01763983e 100644 --- a/core/ecschema-editing/src/Editing/Structs.ts +++ b/core/ecschema-editing/src/Editing/Structs.ts @@ -47,7 +47,7 @@ export class Structs extends ECClasses { const newClass = await this.createSchemaItemFromProps(schemaKey, this.schemaItemType, (schema) => schema.createStructClass.bind(schema), structProps); return newClass.key; } catch (e: any) { - throw new SchemaEditingError(ECEditingStatus.CreateSchemaItemFromProps, new ClassId(this.schemaItemType, structProps.name!, schemaKey), e); + throw new SchemaEditingError(ECEditingStatus.CreateSchemaItemFromProps, new ClassId(this.schemaItemType, structProps.name ?? "", schemaKey), e); } } } diff --git a/core/ecschema-editing/src/Editing/UnitSystems.ts b/core/ecschema-editing/src/Editing/UnitSystems.ts index 7ce378463a87..086b0fefa97a 100644 --- a/core/ecschema-editing/src/Editing/UnitSystems.ts +++ b/core/ecschema-editing/src/Editing/UnitSystems.ts @@ -44,7 +44,7 @@ export class UnitSystems extends SchemaItems { const newUnitSystem = await this.createSchemaItemFromProps(schemaKey, this.schemaItemType, (schema) => schema.createUnitSystem.bind(schema), unitSystemProps); return newUnitSystem.key; } catch (e: any) { - throw new SchemaEditingError(ECEditingStatus.CreateSchemaItemFromProps, new SchemaItemId(this.schemaItemType, unitSystemProps.name!, schemaKey), e); + throw new SchemaEditingError(ECEditingStatus.CreateSchemaItemFromProps, new SchemaItemId(this.schemaItemType, unitSystemProps.name ?? "", schemaKey), e); } } } diff --git a/core/ecschema-editing/src/Editing/Units.ts b/core/ecschema-editing/src/Editing/Units.ts index 55ced49ba66e..3533ac043027 100644 --- a/core/ecschema-editing/src/Editing/Units.ts +++ b/core/ecschema-editing/src/Editing/Units.ts @@ -52,7 +52,7 @@ export class Units extends SchemaItems { const newUnit = await this.createSchemaItemFromProps(schemaKey, this.schemaItemType, (schema) => schema.createUnit.bind(schema), unitProps); return newUnit.key; } catch (e: any) { - throw new SchemaEditingError(ECEditingStatus.CreateSchemaItemFromProps, new SchemaItemId(this.schemaItemType, unitProps.name!, schemaKey), e); + throw new SchemaEditingError(ECEditingStatus.CreateSchemaItemFromProps, new SchemaItemId(this.schemaItemType, unitProps.name ?? "", schemaKey), e); } } } diff --git a/core/ecschema-editing/src/Merging/EnumerationMerger.ts b/core/ecschema-editing/src/Merging/EnumerationMerger.ts index 387688134775..37bd23260972 100644 --- a/core/ecschema-editing/src/Merging/EnumerationMerger.ts +++ b/core/ecschema-editing/src/Merging/EnumerationMerger.ts @@ -39,7 +39,7 @@ export async function addEnumeration(context: SchemaMergeContext, change: Enumer export async function modifyEnumeration(context: SchemaMergeContext, change: EnumerationDifference, itemKey: SchemaItemKey) { const enumeration = await context.targetSchema.lookupItem(itemKey) as MutableEnumeration; if(change.difference.type !== undefined) { - throw new Error(`The Enumeration ${itemKey.name} has an incompatible type. It must be "${primitiveTypeToString(enumeration.type!)}", not "${change.difference.type}".`); + throw new Error(`The Enumeration ${itemKey.name} has an incompatible type. It must be "${enumeration.type ? primitiveTypeToString(enumeration.type) : ""}", not "${change.difference.type}".`); } if(change.difference.label !== undefined) { await context.editor.enumerations.setDisplayLabel(itemKey, change.difference.label); diff --git a/core/ecschema-editing/src/Merging/RelationshipClassMerger.ts b/core/ecschema-editing/src/Merging/RelationshipClassMerger.ts index 3eb99d33fa70..aae0f29df96a 100644 --- a/core/ecschema-editing/src/Merging/RelationshipClassMerger.ts +++ b/core/ecschema-editing/src/Merging/RelationshipClassMerger.ts @@ -114,7 +114,7 @@ export async function mergeRelationshipConstraint(context: SchemaMergeContext, c */ export async function mergeRelationshipClassConstraint(context: SchemaMergeContext, change: RelationshipConstraintClassDifference): Promise { if(change.changeType !== "add") { - throw new Error(`Change type ${change.changeType} is not supported for Relationship constraint classes.`); + throw new Error(`Change type ${String(change.changeType)} is not supported for Relationship constraint classes.`); } const item = await locateSchemaItem(context, change.itemName, SchemaItemType.RelationshipClass) as MutableRelationshipClass; diff --git a/core/ecschema-editing/src/Merging/SchemaReferenceMerger.ts b/core/ecschema-editing/src/Merging/SchemaReferenceMerger.ts index a95d29bd1f30..c4d18dd64e27 100644 --- a/core/ecschema-editing/src/Merging/SchemaReferenceMerger.ts +++ b/core/ecschema-editing/src/Merging/SchemaReferenceMerger.ts @@ -28,7 +28,7 @@ export async function modifySchemaReferences(context: SchemaMergeContext, change } if(!latest.matches(older, SchemaMatchType.LatestWriteCompatible)) { - throw new Error(`Schemas references of ${change.difference.name} have incompatible versions: ${older.version} and ${latest.version}`); + throw new Error(`Schemas references of ${change.difference.name} have incompatible versions: ${older.version.toString()} and ${latest.version.toString()}`); } const index = context.targetSchema.references.findIndex((reference) => reference === existingSchema); diff --git a/core/ecschema-editing/src/Validation/DiagnosticReporter.ts b/core/ecschema-editing/src/Validation/DiagnosticReporter.ts index 6abaaab4ebb2..c9b84c85b813 100644 --- a/core/ecschema-editing/src/Validation/DiagnosticReporter.ts +++ b/core/ecschema-editing/src/Validation/DiagnosticReporter.ts @@ -70,6 +70,7 @@ export abstract class SuppressionDiagnosticReporter implements IDiagnosticReport public report(diagnostic: AnyDiagnostic) { if (this._suppressions && this._suppressions.has(diagnostic.schema.fullName)) { const suppressedCodes = this._suppressions.get(diagnostic.schema.fullName); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion if (suppressedCodes!.includes(diagnostic.code)) return; } diff --git a/core/ecschema-editing/src/Validation/ECRules.ts b/core/ecschema-editing/src/Validation/ECRules.ts index 73e348f45733..a5dbf186b4a9 100644 --- a/core/ecschema-editing/src/Validation/ECRules.ts +++ b/core/ecschema-editing/src/Validation/ECRules.ts @@ -6,6 +6,7 @@ * @module Validation */ +import { expectDefined } from "@itwin/core-bentley"; import { AnyClass, AnyProperty, CustomAttribute, CustomAttributeContainerProps, ECClass, ECClassModifier, ECStringConstants, EntityClass, Enumeration, Mixin, PrimitiveProperty, PrimitiveType, primitiveTypeToString, @@ -328,7 +329,7 @@ export async function* incompatibleValueTypePropertyOverride(property: AnyProper if (!baseType || primitiveType === baseType) return; - return new Diagnostics.IncompatibleValueTypePropertyOverride(property, [property.class.fullName, property.name, baseClass.fullName, primitiveTypeToString(baseType), primitiveTypeToString(primitiveType!)]); + return new Diagnostics.IncompatibleValueTypePropertyOverride(property, [property.class.fullName, property.name, baseClass.fullName, primitiveTypeToString(baseType), primitiveTypeToString(expectDefined(primitiveType))]); } for await (const baseClass of property.class.getAllBaseClasses()) { diff --git a/core/ecschema-editing/src/Validation/SchemaChanges.ts b/core/ecschema-editing/src/Validation/SchemaChanges.ts index 8b178e409119..0537e64cab59 100644 --- a/core/ecschema-editing/src/Validation/SchemaChanges.ts +++ b/core/ecschema-editing/src/Validation/SchemaChanges.ts @@ -203,9 +203,9 @@ export abstract class BaseSchemaChanges implements ISchemaChanges { * @param changeKey The key used to identify the ISchemaChanges in the Map (typically the name of the EC type, ie. SchemaItem.name). */ protected addChangeToMap(changes: Map, changesType: SchemaChangesConstructor, change: ISchemaChange, changeKey: string) { - if (changes.has(changeKey)) { - const existingChanges = changes.get(changeKey); - existingChanges!.addChange(change); + const existingChanges = changes.get(changeKey); + if (undefined !== existingChanges) { + existingChanges.addChange(change); } else { const newChanges = new changesType(this._schema, changeKey); newChanges.addChange(change); @@ -457,9 +457,9 @@ export class SchemaChanges extends BaseSchemaChanges { } private addChangeToSchemaItemMap(change: ISchemaChange, schemaItem: SchemaItem) { - if (this.schemaItemChanges.has(schemaItem.name)) { - const existingChanges = this.schemaItemChanges.get(schemaItem.name); - existingChanges!.addChange(change); + const existingChanges = this.schemaItemChanges.get(schemaItem.name) + if (undefined !== existingChanges) { + existingChanges.addChange(change); } else { const newChanges = new SchemaItemChanges(this.schema, schemaItem.name, schemaItem.schemaItemType); newChanges.addChange(change); @@ -468,9 +468,9 @@ export class SchemaChanges extends BaseSchemaChanges { } private addChangeToClassMap(change: ISchemaChange, ecClass: AnyClass) { - if (this.classChanges.has(ecClass.name)) { - const existingChanges = this.classChanges.get(ecClass.name); - existingChanges!.addChange(change); + const existingChanges = this.classChanges.get(ecClass.name); + if (undefined !== existingChanges) { + existingChanges.addChange(change); } else { const newChanges = new ClassChanges(this.schema, ecClass.name, ecClass.schemaItemType); newChanges.addChange(change); @@ -479,9 +479,9 @@ export class SchemaChanges extends BaseSchemaChanges { } private addChangeToEntityClassMap(change: ISchemaChange, ecClass: EntityClass) { - if (this.entityClassChanges.has(ecClass.name)) { const existingChanges = this.entityClassChanges.get(ecClass.name); - existingChanges!.addChange(change); + if (undefined !== existingChanges) { + existingChanges.addChange(change); } else { const newChanges = new EntityClassChanges(this.schema, ecClass.name, ecClass.schemaItemType); newChanges.addChange(change); @@ -490,9 +490,9 @@ export class SchemaChanges extends BaseSchemaChanges { } private addChangeToRelationshipClassMap(change: ISchemaChange, ecClass: RelationshipClass) { - if (this.relationshipClassChanges.has(ecClass.name)) { - const existingChanges = this.relationshipClassChanges.get(ecClass.name); - existingChanges!.addChange(change); + const existingChanges = this.relationshipClassChanges.get(ecClass.name); + if (undefined !== existingChanges) { + existingChanges.addChange(change); } else { const newChanges = new RelationshipClassChanges(this.schema, ecClass.name, ecClass.schemaItemType); newChanges.addChange(change); @@ -501,9 +501,9 @@ export class SchemaChanges extends BaseSchemaChanges { } private addChangeToEnumerationMap(change: ISchemaChange, enumeration: Enumeration) { - if (this.enumerationChanges.has(enumeration.name)) { - const existingChanges = this.enumerationChanges.get(enumeration.name); - existingChanges!.addChange(change); + const existingChanges = this.enumerationChanges.get(enumeration.name); + if (undefined !== existingChanges) { + existingChanges.addChange(change); } else { const newChanges = new EnumerationChanges(this.schema, enumeration.name, enumeration.schemaItemType); newChanges.addChange(change); @@ -512,9 +512,9 @@ export class SchemaChanges extends BaseSchemaChanges { } private addChangeToKOQMap(change: ISchemaChange, koq: KindOfQuantity) { - if (this.kindOfQuantityChanges.has(koq.name)) { - const existingChanges = this.kindOfQuantityChanges.get(koq.name); - existingChanges!.addChange(change); + const existingChanges = this.kindOfQuantityChanges.get(koq.name); + if (undefined !== existingChanges) { + existingChanges.addChange(change); } else { const newChanges = new KindOfQuantityChanges(this.schema, koq.name, koq.schemaItemType); newChanges.addChange(change); @@ -523,9 +523,9 @@ export class SchemaChanges extends BaseSchemaChanges { } private addChangeToFormatMap(change: ISchemaChange, format: Format) { - if (this.formatChanges.has(format.name)) { - const existingChanges = this.formatChanges.get(format.name); - existingChanges!.addChange(change); + const existingChanges = this.formatChanges.get(format.name); + if (undefined !== existingChanges) { + existingChanges.addChange(change); } else { const newChanges = new FormatChanges(this.schema, format.name, format.schemaItemType); newChanges.addChange(change); diff --git a/core/ecschema-locaters/src/StubSchemaXmlFileLocater.ts b/core/ecschema-locaters/src/StubSchemaXmlFileLocater.ts index 5e47923b17f1..3d4ff15dc703 100644 --- a/core/ecschema-locaters/src/StubSchemaXmlFileLocater.ts +++ b/core/ecschema-locaters/src/StubSchemaXmlFileLocater.ts @@ -84,7 +84,8 @@ export class StubSchemaXmlFileLocater extends SchemaFileLocater implements ISche return undefined; const maxCandidate = candidates.sort(this.compareSchemaKeyByVersion)[candidates.length - 1]; - const alias = this.getSchemaAlias(maxCandidate.schemaText!); + // Note: if maxCandidate.schemaText is undefined, getSchemaAlias will throw an ECSchemaError. + const alias = this.getSchemaAlias(maxCandidate.schemaText ?? ""); const schema = new Schema(context, maxCandidate, alias); context.addSchemaSync(schema); diff --git a/core/ecschema-metadata/src/Deserialization/Helper.ts b/core/ecschema-metadata/src/Deserialization/Helper.ts index 53747217dbd1..539d783fa206 100644 --- a/core/ecschema-metadata/src/Deserialization/Helper.ts +++ b/core/ecschema-metadata/src/Deserialization/Helper.ts @@ -111,20 +111,21 @@ export class SchemaReadHelper { * The default is true. If false, the schema will be loaded directly by this method and not from the context's schema cache. */ public async readSchema(schema: Schema, rawSchema: T, addSchemaToCache: boolean = true): Promise { - if (!this._schemaInfo) { - await this.readSchemaInfo(schema, rawSchema, addSchemaToCache); + let schemaInfo = this._schemaInfo; + if (!schemaInfo) { + schemaInfo = await this.readSchemaInfo(schema, rawSchema, addSchemaToCache); } // If not adding schema to cache (occurs in readSchemaInfo), we must load the schema here if (!addSchemaToCache) { - const loadedSchema = await this.loadSchema(this._schemaInfo!, schema); + const loadedSchema = await this.loadSchema(schemaInfo, schema); if (undefined === loadedSchema) throw new ECSchemaError(ECSchemaStatus.UnableToLoadSchema, `Could not load schema ${schema.schemaKey.toString()}`); return loadedSchema; } - const cachedSchema = await this._context.getCachedSchema(this._schemaInfo!.schemaKey, SchemaMatchType.Latest); + const cachedSchema = await this._context.getCachedSchema(schemaInfo.schemaKey, SchemaMatchType.Latest); if (undefined === cachedSchema) throw new ECSchemaError(ECSchemaStatus.UnableToLoadSchema, `Could not load schema ${schema.schemaKey.toString()}`); @@ -142,6 +143,15 @@ export class SchemaReadHelper { return schemaItem !== undefined; } + /** + * Same as isSchemaItemLoaded, but also asserts that the schema item is defined using a type predicate. + * @note isSchemaItemLoaded already checks if the item is defined, but updating it to be a type predicate + * would break existing code that uses it. + */ + protected isSchemaItemLoadedAndDefined(schemaItem: SchemaItem | undefined): schemaItem is SchemaItem { + return this.isSchemaItemLoaded(schemaItem) && schemaItem !== undefined; + } + /* Finish loading the rest of the schema */ private async loadSchema(schemaInfo: SchemaInfo, schema: Schema): Promise { // Verify that there are no schema reference cycles, this will start schema loading by loading their headers @@ -163,8 +173,8 @@ export class SchemaReadHelper { continue; const loadedItem = await this.loadSchemaItem(schema, itemName, itemType, rawItem); - if (this.isSchemaItemLoaded(loadedItem) && this._visitorHelper) { - await this._visitorHelper.visitSchemaPart(loadedItem!); + if (this.isSchemaItemLoadedAndDefined(loadedItem) && this._visitorHelper) { + await this._visitorHelper.visitSchemaPart(loadedItem); } } @@ -205,8 +215,8 @@ export class SchemaReadHelper { // Load all schema items for (const [itemName, itemType, rawItem] of this._parser.getItems()) { const loadedItem = this.loadSchemaItemSync(schema, itemName, itemType, rawItem); - if (this.isSchemaItemLoaded(loadedItem) && this._visitorHelper) { - this._visitorHelper.visitSchemaPartSync(loadedItem!); + if (this.isSchemaItemLoadedAndDefined(loadedItem) && this._visitorHelper) { + this._visitorHelper.visitSchemaPartSync(loadedItem); } } @@ -252,13 +262,16 @@ export class SchemaReadHelper { private loadSchemaReferenceSync(ref: SchemaReferenceProps): void { const schemaKey = new SchemaKey(ref.name, ECVersion.fromString(ref.version)); const refSchema = this._context.getSchemaSync(schemaKey, SchemaMatchType.LatestWriteCompatible); + if (undefined === this._schema) { + throw new ECSchemaError(ECSchemaStatus.UnableToLoadSchema, `Schema is not defined when trying to load schema reference ${ref.name}.${ref.version}`); + } if (!refSchema) - throw new ECSchemaError(ECSchemaStatus.UnableToLocateSchema, `Could not locate the referenced schema, ${ref.name}.${ref.version}, of ${this._schema!.schemaKey.name}`); + throw new ECSchemaError(ECSchemaStatus.UnableToLocateSchema, `Could not locate the referenced schema, ${ref.name}.${ref.version}, of ${this._schema.schemaKey.name}`); (this._schema as MutableSchema).addReferenceSync(refSchema); - SchemaGraph.generateGraphSync(this._schema!).throwIfCycles(); - const results = this.validateSchemaReferences(this._schema!); + SchemaGraph.generateGraphSync(this._schema).throwIfCycles(); + const results = this.validateSchemaReferences(this._schema); let errorMessage: string = ""; for (const result of results) { @@ -516,15 +529,18 @@ export class SchemaReadHelper { throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The SchemaItem ${name} is invalid without a schema name`); if (isInThisSchema) { + // isInThisSchema requires this._schema to be defined in order to be true. + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion schemaItem = await this._schema!.getItem(itemName); if (schemaItem) return schemaItem; const foundItem = this._parser.findItem(itemName); if (foundItem) { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion schemaItem = await this.loadSchemaItem(this._schema!, ...foundItem); - if (!skipVisitor && this.isSchemaItemLoaded(schemaItem) && this._visitorHelper) { - await this._visitorHelper.visitSchemaPart(schemaItem!); + if (!skipVisitor && this.isSchemaItemLoadedAndDefined(schemaItem) && this._visitorHelper) { + await this._visitorHelper.visitSchemaPart(schemaItem); } if (loadCallBack && schemaItem) loadCallBack(schemaItem); @@ -558,12 +574,15 @@ export class SchemaReadHelper { if (undefined === schemaName || schemaName.length === 0) throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The SchemaItem ${name} is invalid without a schema name`); + // isInThisSchema requires this._schema to be defined in order to be true. + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion if (isInThisSchema && undefined === this._schema!.getItemSync(itemName)) { const foundItem = this._parser.findItem(itemName); if (foundItem) { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion schemaItem = this.loadSchemaItemSync(this._schema!, ...foundItem); - if (!skipVisitor && this.isSchemaItemLoaded(schemaItem) && this._visitorHelper) { - this._visitorHelper.visitSchemaPartSync(schemaItem!); + if (!skipVisitor && this.isSchemaItemLoadedAndDefined(schemaItem) && this._visitorHelper) { + this._visitorHelper.visitSchemaPartSync(schemaItem); } if (loadCallBack && schemaItem) loadCallBack(schemaItem); diff --git a/core/ecschema-metadata/src/Deserialization/JsonParser.ts b/core/ecschema-metadata/src/Deserialization/JsonParser.ts index caff34044fba..e1b9cd5cf957 100644 --- a/core/ecschema-metadata/src/Deserialization/JsonParser.ts +++ b/core/ecschema-metadata/src/Deserialization/JsonParser.ts @@ -103,7 +103,7 @@ export class JsonParser extends AbstractParser { public *getReferences(): Iterable { if (undefined !== this._rawSchema.references) { if (!Array.isArray(this._rawSchema.references)) - throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The schema ${this._rawSchema.name} has an invalid 'references' attribute. It should be of type 'object[]'.`); + throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The schema ${String(this._rawSchema.name)} has an invalid 'references' attribute. It should be of type 'object[]'.`); for (const ref of this._rawSchema.references) { yield this.checkSchemaReference(ref); @@ -704,45 +704,45 @@ export class JsonParser extends AbstractParser { const propName = jsonObj.name; if (undefined !== jsonObj.label && typeof (jsonObj.label) !== "string") - throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The ECProperty ${this._currentItemFullName}.${propName} has an invalid 'label' attribute. It should be of type 'string'.`); + throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The ECProperty ${this._currentItemFullName}.${String(propName)} has an invalid 'label' attribute. It should be of type 'string'.`); if (undefined !== jsonObj.description && typeof (jsonObj.description) !== "string") - throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The ECProperty ${this._currentItemFullName}.${propName} has an invalid 'description' attribute. It should be of type 'string'.`); + throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The ECProperty ${this._currentItemFullName}.${String(propName)} has an invalid 'description' attribute. It should be of type 'string'.`); if (undefined !== jsonObj.priority && typeof (jsonObj.priority) !== "number") - throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The ECProperty ${this._currentItemFullName}.${propName} has an invalid 'priority' attribute. It should be of type 'number'.`); + throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The ECProperty ${this._currentItemFullName}.${String(propName)} has an invalid 'priority' attribute. It should be of type 'number'.`); if (undefined !== jsonObj.isReadOnly && typeof (jsonObj.isReadOnly) !== "boolean") - throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The ECProperty ${this._currentItemFullName}.${propName} has an invalid 'isReadOnly' attribute. It should be of type 'boolean'.`); + throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The ECProperty ${this._currentItemFullName}.${String(propName)} has an invalid 'isReadOnly' attribute. It should be of type 'boolean'.`); if (undefined !== jsonObj.category && typeof (jsonObj.category) !== "string") - throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The ECProperty ${this._currentItemFullName}.${propName} has an invalid 'category' attribute. It should be of type 'string'.`); + throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The ECProperty ${this._currentItemFullName}.${String(propName)} has an invalid 'category' attribute. It should be of type 'string'.`); if (undefined !== jsonObj.kindOfQuantity && typeof (jsonObj.kindOfQuantity) !== "string") - throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The ECProperty ${this._currentItemFullName}.${propName} has an invalid 'kindOfQuantity' attribute. It should be of type 'string'.`); + throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The ECProperty ${this._currentItemFullName}.${String(propName)} has an invalid 'kindOfQuantity' attribute. It should be of type 'string'.`); if (undefined !== jsonObj.inherited && typeof (jsonObj.inherited) !== "boolean") - throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The ECProperty ${this._currentItemFullName}.${propName} has an invalid 'inherited' attribute. It should be of type 'boolean'.`); + throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The ECProperty ${this._currentItemFullName}.${String(propName)} has an invalid 'inherited' attribute. It should be of type 'boolean'.`); if (undefined !== jsonObj.customAttributes && !Array.isArray(jsonObj.customAttributes)) - throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The ECProperty ${this._currentItemFullName}.${propName} has an invalid 'customAttributes' attribute. It should be of type 'array'.`); + throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The ECProperty ${this._currentItemFullName}.${String(propName)} has an invalid 'customAttributes' attribute. It should be of type 'array'.`); return (jsonObj as unknown) as PropertyProps; } private checkPropertyTypename(jsonObj: UnknownObject): void { const propName = jsonObj.name; if (undefined === jsonObj.typeName) - throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The ECProperty ${this._currentItemFullName}.${propName} is missing the required 'typeName' attribute.`); + throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The ECProperty ${this._currentItemFullName}.${String(propName)} is missing the required 'typeName' attribute.`); if (typeof (jsonObj.typeName) !== "string") - throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The ECProperty ${this._currentItemFullName}.${propName} has an invalid 'typeName' attribute. It should be of type 'string'.`); + throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The ECProperty ${this._currentItemFullName}.${String(propName)} has an invalid 'typeName' attribute. It should be of type 'string'.`); } private checkPropertyMinAndMaxOccurs(jsonObj: UnknownObject): void { const propName = jsonObj.name; if (undefined !== jsonObj.minOccurs && typeof (jsonObj.minOccurs) !== "number") - throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The ECProperty ${this._currentItemFullName}.${propName} has an invalid 'minOccurs' attribute. It should be of type 'number'.`); + throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The ECProperty ${this._currentItemFullName}.${String(propName)} has an invalid 'minOccurs' attribute. It should be of type 'number'.`); if (undefined !== jsonObj.maxOccurs && typeof (jsonObj.maxOccurs) !== "number") - throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The ECProperty ${this._currentItemFullName}.${propName} has an invalid 'maxOccurs' attribute. It should be of type 'number'.`); + throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The ECProperty ${this._currentItemFullName}.${String(propName)} has an invalid 'maxOccurs' attribute. It should be of type 'number'.`); } /** @@ -756,19 +756,19 @@ export class JsonParser extends AbstractParser { const propName = jsonObj.name; if (undefined !== jsonObj.minLength && typeof (jsonObj.minLength) !== "number") - throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The ECProperty ${this._currentItemFullName}.${propName} has an invalid 'minLength' attribute. It should be of type 'number'.`); + throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The ECProperty ${this._currentItemFullName}.${String(propName)} has an invalid 'minLength' attribute. It should be of type 'number'.`); if (undefined !== jsonObj.maxLength && typeof (jsonObj.maxLength) !== "number") - throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The ECProperty ${this._currentItemFullName}.${propName} has an invalid 'maxLength' attribute. It should be of type 'number'.`); + throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The ECProperty ${this._currentItemFullName}.${String(propName)} has an invalid 'maxLength' attribute. It should be of type 'number'.`); if (undefined !== jsonObj.minValue && typeof (jsonObj.minValue) !== "number") - throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The ECProperty ${this._currentItemFullName}.${propName} has an invalid 'minValue' attribute. It should be of type 'number'.`); + throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The ECProperty ${this._currentItemFullName}.${String(propName)} has an invalid 'minValue' attribute. It should be of type 'number'.`); if (undefined !== jsonObj.maxValue && typeof (jsonObj.maxValue) !== "number") - throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The ECProperty ${this._currentItemFullName}.${propName} has an invalid 'maxValue' attribute. It should be of type 'number'.`); + throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The ECProperty ${this._currentItemFullName}.${String(propName)} has an invalid 'maxValue' attribute. It should be of type 'number'.`); if (undefined !== jsonObj.extendedTypeName && typeof (jsonObj.extendedTypeName) !== "string") - throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The ECProperty ${this._currentItemFullName}.${propName} has an invalid 'extendedTypeName' attribute. It should be of type 'string'.`); + throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The ECProperty ${this._currentItemFullName}.${String(propName)} has an invalid 'extendedTypeName' attribute. It should be of type 'string'.`); return (jsonObj as unknown) as PrimitiveOrEnumPropertyBaseProps; } @@ -823,7 +823,7 @@ export class JsonParser extends AbstractParser { */ public parseNavigationProperty(jsonObj: UnknownObject): NavigationPropertyProps { this.checkPropertyProps(jsonObj); - const fullname = `${this._currentItemFullName}.${jsonObj.name}`; + const fullname = `${this._currentItemFullName}.${String(jsonObj.name)}`; if (undefined === jsonObj.relationshipName) throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The Navigation Property ${fullname} is missing the required 'relationshipName' property.`); @@ -847,7 +847,7 @@ export class JsonParser extends AbstractParser { } public getPropertyCustomAttributeProviders(jsonObj: UnknownObject): Iterable { - return this.getCustomAttributeProviders(jsonObj, "ECProperty", `${this._currentItemFullName}.${jsonObj.name}`); + return this.getCustomAttributeProviders(jsonObj, "ECProperty", `${this._currentItemFullName}.${String(jsonObj.name)}`); } public getRelationshipConstraintCustomAttributeProviders(jsonObj: UnknownObject): [Iterable /* source */, Iterable /* target */] { diff --git a/core/ecschema-metadata/src/IncrementalLoading/ECSqlSchemaLocater.ts b/core/ecschema-metadata/src/IncrementalLoading/ECSqlSchemaLocater.ts index 2735c51bc920..b3e4508d0dbf 100644 --- a/core/ecschema-metadata/src/IncrementalLoading/ECSqlSchemaLocater.ts +++ b/core/ecschema-metadata/src/IncrementalLoading/ECSqlSchemaLocater.ts @@ -3,6 +3,7 @@ * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ +import { expectDefined } from "@itwin/core-bentley"; import { SchemaContext } from "../Context"; import { ConstantProps, CustomAttributeClassProps, EntityClassProps, EnumerationProps, InvertedUnitProps, KindOfQuantityProps, MixinProps, PhenomenonProps, PropertyCategoryProps, RelationshipClassProps, SchemaItemFormatProps, SchemaItemProps, SchemaItemUnitProps, SchemaProps, @@ -406,7 +407,10 @@ export abstract class ECSqlSchemaLocater extends IncrementalSchemaLocater { Object.assign(schemaStub, { items: {} }); } + // Apparently the compiler does not understand that Object.assign guarantees that the items property is defined. + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const existingItem = schemaStub.items![itemInfo.name] || {}; + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion Object.assign(schemaStub.items!, { [itemInfo.name]: Object.assign(existingItem, itemInfo) }); }; @@ -460,7 +464,7 @@ export abstract class ECSqlSchemaLocater extends IncrementalSchemaLocater { return undefined; schema.items = {}; - await Promise.all([ + const itemResults = await Promise.all([ this.getEntities(schemaKey.name, context), this.getMixins(schemaKey.name, context), this.getStructs(schemaKey.name, context), @@ -475,12 +479,11 @@ export abstract class ECSqlSchemaLocater extends IncrementalSchemaLocater { this.getConstants(schemaKey.name, context), this.getPhenomenon(schemaKey.name, context), this.getFormats(schemaKey.name, context) - ]).then((itemResults) => { - const flatItemList = itemResults.reduce((acc, item) => acc.concat(item)); - flatItemList.forEach((schemaItem) => { - schema.items![schemaItem.name!] = schemaItem; - }); - }); + ]); + const flatItemList = itemResults.reduce((acc, item) => acc.concat(item)); + for (const schemaItem of flatItemList) { + schema.items[expectDefined(schemaItem.name)] = schemaItem; + } return schema; } @@ -507,8 +510,8 @@ async function parseSchemaItemStubs(schemaName: string, context: SchemaContext, const schemaItem = await SchemaParser.parseItem(currentItem, currentItem.schema, context); await addItemsHandler(currentItem.schema, { ...schemaItem, - name: schemaItem.name!, - schemaItemType: parseSchemaItemType(schemaItem.schemaItemType!)!, + name: expectDefined(schemaItem.name), + schemaItemType: expectDefined(parseSchemaItemType(expectDefined(schemaItem.schemaItemType))), baseClass: baseClassName, }); } @@ -518,8 +521,8 @@ async function parseSchemaItemStubs(schemaName: string, context: SchemaContext, const schemaItem = await SchemaParser.parseItem(itemRow, schemaName, context); await addItemsHandler(schemaName, { ...schemaItem, - name: schemaItem.name!, - schemaItemType: parseSchemaItemType(schemaItem.schemaItemType!)!, + name: expectDefined(schemaItem.name), + schemaItemType: expectDefined(parseSchemaItemType(expectDefined(schemaItem.schemaItemType))), mixins: itemRow.mixins ? itemRow.mixins.map(mixin => { return `${mixin.schema}.${mixin.name}`; }) : undefined, @@ -531,8 +534,8 @@ async function parseSchemaItemStubs(schemaName: string, context: SchemaContext, const mixinItem = await SchemaParser.parseItem(mixinRow, mixinRow.schema, context); await addItemsHandler(mixinRow.schema, { ...mixinItem, - name: mixinItem.name!, - schemaItemType: parseSchemaItemType(mixinItem.schemaItemType!)!, + name: expectDefined(mixinItem.name), + schemaItemType: expectDefined(parseSchemaItemType(expectDefined(mixinItem.schemaItemType))), }); await parseBaseClasses(mixinRow.baseClasses); } diff --git a/core/ecschema-metadata/src/IncrementalLoading/IncrementalSchemaLocater.ts b/core/ecschema-metadata/src/IncrementalLoading/IncrementalSchemaLocater.ts index a133dc34d98f..5a28e47baf3a 100644 --- a/core/ecschema-metadata/src/IncrementalLoading/IncrementalSchemaLocater.ts +++ b/core/ecschema-metadata/src/IncrementalLoading/IncrementalSchemaLocater.ts @@ -2,6 +2,7 @@ * Copyright (c) Bentley Systems, Incorporated. All rights reserved. * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ +import { expectDefined } from "@itwin/core-bentley"; import { ECSchemaNamespaceUris } from "../Constants"; import { ISchemaLocater, SchemaContext } from "../Context"; import { SchemaProps } from "../Deserialization/JsonProps"; @@ -139,7 +140,7 @@ export abstract class IncrementalSchemaLocater implements ISchemaLocater { // to fetch the whole schema json. if (!await this.supportPartialSchemaLoading(schemaContext)) { const schemaJson = await this.getSchemaJson(schemaInfo.schemaKey, schemaContext); - return Schema.fromJson(schemaJson!, schemaContext); + return Schema.fromJson(expectDefined(schemaJson), schemaContext); } // Fetches the schema partials for the given schema key. The first item in the array is the @@ -186,9 +187,9 @@ export abstract class IncrementalSchemaLocater implements ISchemaLocater { if (!schemaProps.references) throw new Error(`Schema references is undefined for the Schema ${schemaInfo.schemaKey.name}`); - schemaInfo.references.forEach((ref) => { - schemaProps.references!.push({ name: ref.schemaKey.name, version: ref.schemaKey.version.toString() }); - }); + for (const ref of schemaInfo.references) { + schemaProps.references.push({ name: ref.schemaKey.name, version: ref.schemaKey.version.toString() }); + } return schemaProps; } diff --git a/core/ecschema-metadata/src/IncrementalLoading/IncrementalSchemaReader.ts b/core/ecschema-metadata/src/IncrementalLoading/IncrementalSchemaReader.ts index e6031d1cb131..dcc1d8826295 100644 --- a/core/ecschema-metadata/src/IncrementalLoading/IncrementalSchemaReader.ts +++ b/core/ecschema-metadata/src/IncrementalLoading/IncrementalSchemaReader.ts @@ -2,6 +2,7 @@ * Copyright (c) Bentley Systems, Incorporated. All rights reserved. * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ +import { assert } from "@itwin/core-bentley"; import { SchemaContext } from "../Context"; import { SchemaReadHelper } from "../Deserialization/Helper"; import { JsonParser } from "../Deserialization/JsonParser"; @@ -74,13 +75,14 @@ export class IncrementalSchemaReader extends SchemaReadHelper { if (schemaItem.loadingController === undefined) { const controller = new SchemaLoadingController(); schemaItem.setLoadingController(controller); + assert(undefined !== schemaItem.loadingController); } if (ECClass.isECClass(schemaItem) || schemaItem.schemaItemType === SchemaItemType.KindOfQuantity || schemaItem.schemaItemType === SchemaItemType.Format) - schemaItem.loadingController!.isComplete = !this._incremental; + schemaItem.loadingController.isComplete = !this._incremental; else - schemaItem.loadingController!.isComplete = true; + schemaItem.loadingController.isComplete = true; } } \ No newline at end of file diff --git a/core/ecschema-metadata/src/IncrementalLoading/SchemaParser.ts b/core/ecschema-metadata/src/IncrementalLoading/SchemaParser.ts index a1f1621474c7..f25a010f1ebb 100644 --- a/core/ecschema-metadata/src/IncrementalLoading/SchemaParser.ts +++ b/core/ecschema-metadata/src/IncrementalLoading/SchemaParser.ts @@ -3,6 +3,7 @@ * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ +import { expectDefined } from "@itwin/core-bentley"; import { ECSchemaNamespaceUris } from "../Constants"; import { SchemaContext } from "../Context"; import { SchemaItemProps, SchemaProps } from "../Deserialization/JsonProps"; @@ -72,7 +73,7 @@ export class SchemaParser { const items: { [name: string]: SchemaItemProps } = {}; for (const itemProps of schemaItemProps) { const props = await this.parseItem(itemProps, schemaName, context); - items[props.name!] = props; + items[expectDefined(props.name)] = props; delete (props as any).name; } diff --git a/core/ecschema-metadata/src/Metadata/Class.ts b/core/ecschema-metadata/src/Metadata/Class.ts index 316f0af8fb63..ba1747bbad79 100644 --- a/core/ecschema-metadata/src/Metadata/Class.ts +++ b/core/ecschema-metadata/src/Metadata/Class.ts @@ -373,7 +373,7 @@ export abstract class ECClass extends SchemaItem implements CustomAttributeConta if (!correctType) // eslint-disable-next-line @typescript-eslint/no-base-to-string - throw new ECSchemaError(ECSchemaStatus.InvalidType, `The provided Struct type, ${structType}, is not a valid StructClass.`); + throw new ECSchemaError(ECSchemaStatus.InvalidType, `The provided Struct type, ${String(structType)}, is not a valid StructClass.`); return correctType; } @@ -395,7 +395,7 @@ export abstract class ECClass extends SchemaItem implements CustomAttributeConta if (!correctType) // eslint-disable-next-line @typescript-eslint/no-base-to-string - throw new ECSchemaError(ECSchemaStatus.InvalidType, `The provided Struct type, ${structType}, is not a valid StructClass.`); + throw new ECSchemaError(ECSchemaStatus.InvalidType, `The provided Struct type, ${String(structType)}, is not a valid StructClass.`); return correctType; } diff --git a/core/ecschema-metadata/src/Metadata/EntityClass.ts b/core/ecschema-metadata/src/Metadata/EntityClass.ts index 5f75a0c44425..f8a6b5b68cb4 100644 --- a/core/ecschema-metadata/src/Metadata/EntityClass.ts +++ b/core/ecschema-metadata/src/Metadata/EntityClass.ts @@ -294,7 +294,7 @@ export async function createNavigationProperty(ecClass: ECClass, name: string, r resolvedRelationship = relationship; if (!resolvedRelationship) - throw new ECSchemaError(ECSchemaStatus.InvalidType, `The provided RelationshipClass, ${relationship}, is not a valid RelationshipClassInterface.`); // eslint-disable-line @typescript-eslint/no-base-to-string + throw new ECSchemaError(ECSchemaStatus.InvalidType, `The provided RelationshipClass, ${String(relationship)}, is not a valid RelationshipClassInterface.`); // eslint-disable-line @typescript-eslint/no-base-to-string if (typeof (direction) === "string") { const tmpDirection = parseStrengthDirection(direction); @@ -319,7 +319,7 @@ export function createNavigationPropertySync(ecClass: ECClass, name: string, rel resolvedRelationship = relationship; if (!resolvedRelationship) - throw new ECSchemaError(ECSchemaStatus.InvalidType, `The provided RelationshipClass, ${relationship}, is not a valid RelationshipClassInterface.`); // eslint-disable-line @typescript-eslint/no-base-to-string + throw new ECSchemaError(ECSchemaStatus.InvalidType, `The provided RelationshipClass, ${String(relationship)}, is not a valid RelationshipClassInterface.`); // eslint-disable-line @typescript-eslint/no-base-to-string if (typeof (direction) === "string") { const tmpDirection = parseStrengthDirection(direction); diff --git a/core/ecschema-metadata/src/Metadata/InvertedUnit.ts b/core/ecschema-metadata/src/Metadata/InvertedUnit.ts index 71f9d1f17036..233c0c697f64 100644 --- a/core/ecschema-metadata/src/Metadata/InvertedUnit.ts +++ b/core/ecschema-metadata/src/Metadata/InvertedUnit.ts @@ -6,6 +6,7 @@ * @module Metadata */ +import { expectDefined } from "@itwin/core-bentley"; import { DelayedPromiseWithProps } from "../DelayedPromise"; import { InvertedUnitProps } from "../Deserialization/JsonProps"; import { XmlSerializationUtils } from "../Deserialization/XmlSerializationUtils"; @@ -61,8 +62,8 @@ export class InvertedUnit extends SchemaItem { */ public override toJSON(standalone: boolean = false, includeSchemaVersion: boolean = false): InvertedUnitProps { const schemaJson = super.toJSON(standalone, includeSchemaVersion) as any; - schemaJson.invertsUnit = this.invertsUnit!.fullName; - schemaJson.unitSystem = this.unitSystem!.fullName; + schemaJson.invertsUnit = expectDefined(this.invertsUnit).fullName; + schemaJson.unitSystem = expectDefined(this.unitSystem).fullName; return schemaJson; } diff --git a/core/ecschema-metadata/src/Metadata/KindOfQuantity.ts b/core/ecschema-metadata/src/Metadata/KindOfQuantity.ts index dbba46ef7f9f..83c5ce308f54 100644 --- a/core/ecschema-metadata/src/Metadata/KindOfQuantity.ts +++ b/core/ecschema-metadata/src/Metadata/KindOfQuantity.ts @@ -6,6 +6,7 @@ * @module Metadata */ +import { expectDefined } from "@itwin/core-bentley"; import { DelayedPromiseWithProps } from "../DelayedPromise"; import { KindOfQuantityProps } from "../Deserialization/JsonProps"; import { XmlSerializationUtils } from "../Deserialization/XmlSerializationUtils"; @@ -151,7 +152,7 @@ export class KindOfQuantity extends SchemaItem { public override toJSON(standalone: boolean = false, includeSchemaVersion: boolean = false): KindOfQuantityProps { const schemaJson = super.toJSON(standalone, includeSchemaVersion) as any; schemaJson.relativeError = this.relativeError; - schemaJson.persistenceUnit = this.persistenceUnit!.fullName; + schemaJson.persistenceUnit = expectDefined(this.persistenceUnit).fullName; if (undefined !== this.presentationFormats && 0 < this.presentationFormats.length) schemaJson.presentationUnits = this.presentationFormats.map((format) => format.fullName); return schemaJson; diff --git a/core/ecschema-metadata/src/Metadata/OverrideFormat.ts b/core/ecschema-metadata/src/Metadata/OverrideFormat.ts index 0c23f42dcc95..8c52c8bce19c 100644 --- a/core/ecschema-metadata/src/Metadata/OverrideFormat.ts +++ b/core/ecschema-metadata/src/Metadata/OverrideFormat.ts @@ -93,7 +93,7 @@ export class OverrideFormat { for (const [unit, unitLabel] of this._units) { const unitSchema = koqSchema.context.getSchemaSync(unit.schemaKey); if(unitSchema === undefined) - throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The unit schema ${unit.schemaKey} is not found in the context.`); + throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The unit schema ${String(unit.schemaKey)} is not found in the context.`); fullName += "["; fullName += XmlSerializationUtils.createXmlTypedName(koqSchema, unitSchema, unit.name); diff --git a/core/ecschema-metadata/src/Metadata/Property.ts b/core/ecschema-metadata/src/Metadata/Property.ts index 9ee23b92c0aa..1e5359c51639 100644 --- a/core/ecschema-metadata/src/Metadata/Property.ts +++ b/core/ecschema-metadata/src/Metadata/Property.ts @@ -6,6 +6,7 @@ * @module Metadata */ +import { expectDefined } from "@itwin/core-bentley"; import { DelayedPromiseWithProps } from "../DelayedPromise"; import { ArrayPropertyProps, EnumerationPropertyProps, NavigationPropertyProps, PrimitiveArrayPropertyProps, PrimitiveOrEnumPropertyBaseProps, @@ -515,7 +516,7 @@ export class EnumerationProperty extends PrimitiveOrEnumPropertyBase { */ public override toJSON(): EnumerationPropertyProps { const schemaJson = super.toJSON() as any; - schemaJson.typeName = this.enumeration!.fullName; + schemaJson.typeName = expectDefined(this.enumeration).fullName; return schemaJson; } @@ -529,9 +530,9 @@ export class EnumerationProperty extends PrimitiveOrEnumPropertyBase { public override fromJSONSync(enumerationPropertyProps: EnumerationPropertyProps) { super.fromJSONSync(enumerationPropertyProps); if (undefined !== enumerationPropertyProps.typeName) { - if (!(this.enumeration!.fullName).match(enumerationPropertyProps.typeName)) // need to match {schema}.{version}.{itemName} on typeName + if (!(expectDefined(this.enumeration).fullName).match(enumerationPropertyProps.typeName)) // need to match {schema}.{version}.{itemName} on typeName throw new ECSchemaError(ECSchemaStatus.InvalidECJson, ``); - const enumSchemaItemKey = this.class.schema.getSchemaItemKey(this.enumeration!.fullName); + const enumSchemaItemKey = this.class.schema.getSchemaItemKey(expectDefined(this.enumeration).fullName); if (!enumSchemaItemKey) throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `Unable to locate the enumeration ${enumerationPropertyProps.typeName}.`); this._enumeration = new DelayedPromiseWithProps(enumSchemaItemKey, @@ -547,8 +548,8 @@ export class EnumerationProperty extends PrimitiveOrEnumPropertyBase { /** @internal */ public override async toXml(schemaXml: Document): Promise { const itemElement = await super.toXml(schemaXml); - const enumeration = await this.enumeration; - const enumerationName = XmlSerializationUtils.createXmlTypedName(this.schema, enumeration!.schema, enumeration!.name); + const enumeration = expectDefined(await this.enumeration); + const enumerationName = XmlSerializationUtils.createXmlTypedName(this.schema, enumeration.schema, enumeration.name); itemElement.setAttribute("typeName", enumerationName); return itemElement; } diff --git a/core/ecschema-metadata/src/Metadata/RelationshipClass.ts b/core/ecschema-metadata/src/Metadata/RelationshipClass.ts index 13e32907829c..635c249b3757 100644 --- a/core/ecschema-metadata/src/Metadata/RelationshipClass.ts +++ b/core/ecschema-metadata/src/Metadata/RelationshipClass.ts @@ -6,6 +6,7 @@ * @module Metadata */ +import { expectDefined } from "@itwin/core-bentley"; import { DelayedPromiseWithProps } from "../DelayedPromise"; import { ECSpecVersion, SchemaReadHelper } from "../Deserialization/Helper"; import { RelationshipClassProps, RelationshipConstraintProps } from "../Deserialization/JsonProps"; @@ -344,7 +345,7 @@ export class RelationshipConstraint implements CustomAttributeContainerProps { throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `Unable to locate the abstractConstraint ${relationshipConstraintProps.abstractConstraint}.`); this.setAbstractConstraint(new DelayedPromiseWithProps(abstractConstraintSchemaItemKey, async () => { - const tempAbstractConstraint = await relClassSchema.lookupItem(relationshipConstraintProps.abstractConstraint!); + const tempAbstractConstraint = await relClassSchema.lookupItem(expectDefined(relationshipConstraintProps.abstractConstraint)); if (undefined === tempAbstractConstraint || (!EntityClass.isEntityClass(tempAbstractConstraint) && !Mixin.isMixin(tempAbstractConstraint) && !RelationshipClass.isRelationshipClass(tempAbstractConstraint))) throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `Unable to locate the abstractConstraint ${relationshipConstraintProps.abstractConstraint}.`); diff --git a/core/ecschema-metadata/src/Metadata/Schema.ts b/core/ecschema-metadata/src/Metadata/Schema.ts index 1b59bd8b2ec5..96a28da9bbb9 100644 --- a/core/ecschema-metadata/src/Metadata/Schema.ts +++ b/core/ecschema-metadata/src/Metadata/Schema.ts @@ -820,7 +820,7 @@ export class Schema implements CustomAttributeContainerProps { if (schemaProps.name.toLowerCase() !== this.name.toLowerCase()) throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The Schema ${this.name} does not match the provided name, '${schemaProps.name}'.`); if (this.schemaKey.version.compare(ECVersion.fromString(schemaProps.version))) - throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The Schema ${this.name} has the version '${this.schemaKey.version}' that does not match the provided version '${schemaProps.version}'.`); + throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The Schema ${this.name} has the version '${String(this.schemaKey.version)}' that does not match the provided version '${schemaProps.version}'.`); } if (schemaProps.$schema.match(`https://dev\\.bentley\\.com/json_schemas/ec/([0-9]+)/ecschema`) == null && schemaProps.$schema.match(`http://www\\.bentley\\.com/schemas/Bentley\\.ECXML\\.([0-9]+)`) == null) diff --git a/core/ecschema-metadata/src/Metadata/SchemaItem.ts b/core/ecschema-metadata/src/Metadata/SchemaItem.ts index 72de61b24309..b66a36451285 100644 --- a/core/ecschema-metadata/src/Metadata/SchemaItem.ts +++ b/core/ecschema-metadata/src/Metadata/SchemaItem.ts @@ -108,7 +108,7 @@ export abstract class SchemaItem { if (undefined !== schemaItemProps.schemaVersion) { if (this.key.schemaKey.version.compare(ECVersion.fromString(schemaItemProps.schemaVersion))) - throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `Unable to deserialize the SchemaItem '${this.fullName}' with a different schema version, ${schemaItemProps.schemaVersion}, than the current Schema version of this SchemaItem, ${this.key.schemaKey.version}.`); + throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `Unable to deserialize the SchemaItem '${this.fullName}' with a different schema version, ${schemaItemProps.schemaVersion}, than the current Schema version of this SchemaItem, ${String(this.key.schemaKey.version)}.`); } } @@ -125,7 +125,7 @@ export abstract class SchemaItem { if (undefined !== schemaItemProps.schemaVersion) { if (this.key.schemaKey.version.compare(ECVersion.fromString(schemaItemProps.schemaVersion))) - throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `Unable to deserialize the SchemaItem '${this.fullName}' with a different schema version, ${schemaItemProps.schemaVersion}, than the current Schema version of this SchemaItem, ${this.key.schemaKey.version}.`); + throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `Unable to deserialize the SchemaItem '${this.fullName}' with a different schema version, ${schemaItemProps.schemaVersion}, than the current Schema version of this SchemaItem, ${String(this.key.schemaKey.version)}.`); } } diff --git a/core/ecschema-metadata/src/Metadata/Unit.ts b/core/ecschema-metadata/src/Metadata/Unit.ts index 9ea038cf7bdb..bbf0d7c20a5d 100644 --- a/core/ecschema-metadata/src/Metadata/Unit.ts +++ b/core/ecschema-metadata/src/Metadata/Unit.ts @@ -6,6 +6,7 @@ * @module Metadata */ +import { expectDefined } from "@itwin/core-bentley"; import { DelayedPromiseWithProps } from "../DelayedPromise"; import { SchemaItemUnitProps } from "../Deserialization/JsonProps"; import { XmlSerializationUtils } from "../Deserialization/XmlSerializationUtils"; @@ -82,8 +83,8 @@ export class Unit extends SchemaItem { */ public override toJSON(standalone: boolean = false, includeSchemaVersion: boolean = false): SchemaItemUnitProps { const schemaJson = super.toJSON(standalone, includeSchemaVersion) as any; - schemaJson.phenomenon = this.phenomenon!.fullName; - schemaJson.unitSystem = this.unitSystem!.fullName; + schemaJson.phenomenon = expectDefined(this.phenomenon).fullName; + schemaJson.unitSystem = expectDefined(this.unitSystem).fullName; schemaJson.definition = this.definition; if (this.hasNumerator) schemaJson.numerator = this.numerator; diff --git a/core/ecschema-metadata/src/SchemaFormatsProvider.ts b/core/ecschema-metadata/src/SchemaFormatsProvider.ts index 6fd990b52c8a..6a2a260d82b9 100644 --- a/core/ecschema-metadata/src/SchemaFormatsProvider.ts +++ b/core/ecschema-metadata/src/SchemaFormatsProvider.ts @@ -113,6 +113,8 @@ export class SchemaFormatsProvider implements FormatsProvider { const persistenceUnitSystem = await persistenceUnit?.unitSystem; if (persistenceUnitSystem && unitSystemMatchers.some((matcher) => matcher(persistenceUnitSystem))) { this._formatsRetrieved.add(itemKey.fullName); + // It is only possible to get here if persistenceUnit is defined. + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const props = getPersistenceUnitFormatProps(persistenceUnit!); return this.convertToFormatDefinition(props, kindOfQuantity); } diff --git a/core/ecschema-metadata/src/UnitConversion/Parser.ts b/core/ecschema-metadata/src/UnitConversion/Parser.ts index 66bf077ba9d9..680bc90f4a2c 100644 --- a/core/ecschema-metadata/src/UnitConversion/Parser.ts +++ b/core/ecschema-metadata/src/UnitConversion/Parser.ts @@ -30,8 +30,8 @@ export function parseDefinition(definition: string): Map { it("should find alternate display labels of Units.US_SURVEY_FT", () => { const altDisplayLabels = provider.getAlternateDisplayLabels("Units.US_SURVEY_FT"); const expectedLabels = ["ft", "SF", "USF", "ft (US Survey)"]; - expect(altDisplayLabels, `Alternate display labels should be ${expectedLabels}`).to.include.members(expectedLabels); + expect(altDisplayLabels, `Alternate display labels should be ${JSON.stringify(expectedLabels)}`).to.include.members(expectedLabels); expect(altDisplayLabels).to.have.lengthOf(4); }); it("should find alternate display labels of Units.CUB_US_SURVEY_FT", () => { const altDisplayLabels = provider.getAlternateDisplayLabels("Units.CUB_US_SURVEY_FT"); const expectedLabels = ["cf"]; - expect(altDisplayLabels, `Alternate display labels should be ${expectedLabels}`).to.include.members(expectedLabels); + expect(altDisplayLabels, `Alternate display labels should be ${JSON.stringify(expectedLabels)}`).to.include.members(expectedLabels); expect(altDisplayLabels).to.have.lengthOf(1); }); it("should not find any alternate display labels of Unit", () => { const altDisplayLabels = provider.getAlternateDisplayLabels("Units.CELSIUS"); const expectedLabels: string[] = []; - expect(altDisplayLabels, `Alternate display labels should be ${expectedLabels}`).to.include.members(expectedLabels); + expect(altDisplayLabels, `Alternate display labels should be ${JSON.stringify(expectedLabels)}`).to.include.members(expectedLabels); expect(altDisplayLabels).to.have.lengthOf(0); }); diff --git a/core/ecsql/common/src/ECSqlAst.ts b/core/ecsql/common/src/ECSqlAst.ts index 44f660561df7..34eebd021ffb 100644 --- a/core/ecsql/common/src/ECSqlAst.ts +++ b/core/ecsql/common/src/ECSqlAst.ts @@ -825,7 +825,7 @@ export class QualifiedJoinExpr extends ClassRefExpr { writer.appendKeyword("INNER").appendSpace(); writer.appendKeyword("JOIN").appendSpace(); } else { - throw new Error(`not supported join type ${this.joinType}`); + throw new Error(`not supported join type ${String(this.joinType)}`); } writer.appendExp(this.to); if (this.spec) { From cd148a2c80ed51a7833983786f9a5b823001d753 Mon Sep 17 00:00:00 2001 From: "Travis.Cobbs" <77415528+tcobbs-bentley@users.noreply.github.com> Date: Fri, 8 Aug 2025 15:17:22 -0600 Subject: [PATCH 02/15] Fix indentation --- core/ecschema-editing/src/Validation/SchemaChanges.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/ecschema-editing/src/Validation/SchemaChanges.ts b/core/ecschema-editing/src/Validation/SchemaChanges.ts index 0537e64cab59..2fd51373d007 100644 --- a/core/ecschema-editing/src/Validation/SchemaChanges.ts +++ b/core/ecschema-editing/src/Validation/SchemaChanges.ts @@ -479,7 +479,7 @@ export class SchemaChanges extends BaseSchemaChanges { } private addChangeToEntityClassMap(change: ISchemaChange, ecClass: EntityClass) { - const existingChanges = this.entityClassChanges.get(ecClass.name); + const existingChanges = this.entityClassChanges.get(ecClass.name); if (undefined !== existingChanges) { existingChanges.addChange(change); } else { From 755d4d173ffa96c336dff1eebee1838610598843 Mon Sep 17 00:00:00 2001 From: "Travis.Cobbs" <77415528+tcobbs-bentley@users.noreply.github.com> Date: Fri, 8 Aug 2025 15:18:36 -0600 Subject: [PATCH 03/15] Improve comment --- core/ecschema-locaters/src/StubSchemaXmlFileLocater.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/ecschema-locaters/src/StubSchemaXmlFileLocater.ts b/core/ecschema-locaters/src/StubSchemaXmlFileLocater.ts index 3d4ff15dc703..ca5f3666a9c2 100644 --- a/core/ecschema-locaters/src/StubSchemaXmlFileLocater.ts +++ b/core/ecschema-locaters/src/StubSchemaXmlFileLocater.ts @@ -84,7 +84,7 @@ export class StubSchemaXmlFileLocater extends SchemaFileLocater implements ISche return undefined; const maxCandidate = candidates.sort(this.compareSchemaKeyByVersion)[candidates.length - 1]; - // Note: if maxCandidate.schemaText is undefined, getSchemaAlias will throw an ECSchemaError. + // Note: if maxCandidate.schemaText is undefined, the "" passed to getSchemaAlias will throw an ECSchemaError. const alias = this.getSchemaAlias(maxCandidate.schemaText ?? ""); const schema = new Schema(context, maxCandidate, alias); context.addSchemaSync(schema); From b3172d0479e3204810261440762fdbea5068f3b8 Mon Sep 17 00:00:00 2001 From: "Travis.Cobbs" <77415528+tcobbs-bentley@users.noreply.github.com> Date: Fri, 8 Aug 2025 15:37:06 -0600 Subject: [PATCH 04/15] Use toString() where appropriate --- core/ecschema-metadata/src/Metadata/OverrideFormat.ts | 2 +- core/ecschema-metadata/src/Metadata/Schema.ts | 2 +- core/ecschema-metadata/src/Metadata/SchemaItem.ts | 4 ++-- .../src/test/UnitProvider/UnitProvider.test.ts | 6 +++--- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/core/ecschema-metadata/src/Metadata/OverrideFormat.ts b/core/ecschema-metadata/src/Metadata/OverrideFormat.ts index 8c52c8bce19c..bd4c6065a50d 100644 --- a/core/ecschema-metadata/src/Metadata/OverrideFormat.ts +++ b/core/ecschema-metadata/src/Metadata/OverrideFormat.ts @@ -93,7 +93,7 @@ export class OverrideFormat { for (const [unit, unitLabel] of this._units) { const unitSchema = koqSchema.context.getSchemaSync(unit.schemaKey); if(unitSchema === undefined) - throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The unit schema ${String(unit.schemaKey)} is not found in the context.`); + throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The unit schema ${unit.schemaKey.toString()} is not found in the context.`); fullName += "["; fullName += XmlSerializationUtils.createXmlTypedName(koqSchema, unitSchema, unit.name); diff --git a/core/ecschema-metadata/src/Metadata/Schema.ts b/core/ecschema-metadata/src/Metadata/Schema.ts index 96a28da9bbb9..aa2b51112b57 100644 --- a/core/ecschema-metadata/src/Metadata/Schema.ts +++ b/core/ecschema-metadata/src/Metadata/Schema.ts @@ -820,7 +820,7 @@ export class Schema implements CustomAttributeContainerProps { if (schemaProps.name.toLowerCase() !== this.name.toLowerCase()) throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The Schema ${this.name} does not match the provided name, '${schemaProps.name}'.`); if (this.schemaKey.version.compare(ECVersion.fromString(schemaProps.version))) - throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The Schema ${this.name} has the version '${String(this.schemaKey.version)}' that does not match the provided version '${schemaProps.version}'.`); + throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The Schema ${this.name} has the version '${this.schemaKey.version.toString()}' that does not match the provided version '${schemaProps.version}'.`); } if (schemaProps.$schema.match(`https://dev\\.bentley\\.com/json_schemas/ec/([0-9]+)/ecschema`) == null && schemaProps.$schema.match(`http://www\\.bentley\\.com/schemas/Bentley\\.ECXML\\.([0-9]+)`) == null) diff --git a/core/ecschema-metadata/src/Metadata/SchemaItem.ts b/core/ecschema-metadata/src/Metadata/SchemaItem.ts index b66a36451285..2c8a0729b2bf 100644 --- a/core/ecschema-metadata/src/Metadata/SchemaItem.ts +++ b/core/ecschema-metadata/src/Metadata/SchemaItem.ts @@ -108,7 +108,7 @@ export abstract class SchemaItem { if (undefined !== schemaItemProps.schemaVersion) { if (this.key.schemaKey.version.compare(ECVersion.fromString(schemaItemProps.schemaVersion))) - throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `Unable to deserialize the SchemaItem '${this.fullName}' with a different schema version, ${schemaItemProps.schemaVersion}, than the current Schema version of this SchemaItem, ${String(this.key.schemaKey.version)}.`); + throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `Unable to deserialize the SchemaItem '${this.fullName}' with a different schema version, ${schemaItemProps.schemaVersion}, than the current Schema version of this SchemaItem, ${this.key.schemaKey.version.toString()}.`); } } @@ -125,7 +125,7 @@ export abstract class SchemaItem { if (undefined !== schemaItemProps.schemaVersion) { if (this.key.schemaKey.version.compare(ECVersion.fromString(schemaItemProps.schemaVersion))) - throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `Unable to deserialize the SchemaItem '${this.fullName}' with a different schema version, ${schemaItemProps.schemaVersion}, than the current Schema version of this SchemaItem, ${String(this.key.schemaKey.version)}.`); + throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `Unable to deserialize the SchemaItem '${this.fullName}' with a different schema version, ${schemaItemProps.schemaVersion}, than the current Schema version of this SchemaItem, ${this.key.schemaKey.version.toString()}.`); } } diff --git a/core/ecschema-metadata/src/test/UnitProvider/UnitProvider.test.ts b/core/ecschema-metadata/src/test/UnitProvider/UnitProvider.test.ts index 1aecbde41952..300d79e32f37 100644 --- a/core/ecschema-metadata/src/test/UnitProvider/UnitProvider.test.ts +++ b/core/ecschema-metadata/src/test/UnitProvider/UnitProvider.test.ts @@ -149,21 +149,21 @@ describe("Unit Provider tests", () => { it("should find alternate display labels of Units.US_SURVEY_FT", () => { const altDisplayLabels = provider.getAlternateDisplayLabels("Units.US_SURVEY_FT"); const expectedLabels = ["ft", "SF", "USF", "ft (US Survey)"]; - expect(altDisplayLabels, `Alternate display labels should be ${JSON.stringify(expectedLabels)}`).to.include.members(expectedLabels); + expect(altDisplayLabels, `Alternate display labels should be ${expectedLabels.toString()}`).to.include.members(expectedLabels); expect(altDisplayLabels).to.have.lengthOf(4); }); it("should find alternate display labels of Units.CUB_US_SURVEY_FT", () => { const altDisplayLabels = provider.getAlternateDisplayLabels("Units.CUB_US_SURVEY_FT"); const expectedLabels = ["cf"]; - expect(altDisplayLabels, `Alternate display labels should be ${JSON.stringify(expectedLabels)}`).to.include.members(expectedLabels); + expect(altDisplayLabels, `Alternate display labels should be ${expectedLabels.toString()}`).to.include.members(expectedLabels); expect(altDisplayLabels).to.have.lengthOf(1); }); it("should not find any alternate display labels of Unit", () => { const altDisplayLabels = provider.getAlternateDisplayLabels("Units.CELSIUS"); const expectedLabels: string[] = []; - expect(altDisplayLabels, `Alternate display labels should be ${JSON.stringify(expectedLabels)}`).to.include.members(expectedLabels); + expect(altDisplayLabels, `Alternate display labels should be ${expectedLabels.toString()}`).to.include.members(expectedLabels); expect(altDisplayLabels).to.have.lengthOf(0); }); From b6493af30713e015eb7956b23b106be18766bb4e Mon Sep 17 00:00:00 2001 From: "Travis.Cobbs" <77415528+tcobbs-bentley@users.noreply.github.com> Date: Wed, 13 Aug 2025 10:48:14 -0600 Subject: [PATCH 05/15] rush extract-api --- common/api/ecschema-metadata.api.md | 1 + 1 file changed, 1 insertion(+) diff --git a/common/api/ecschema-metadata.api.md b/common/api/ecschema-metadata.api.md index f3dc7a69a628..5e0387fd8aa4 100644 --- a/common/api/ecschema-metadata.api.md +++ b/common/api/ecschema-metadata.api.md @@ -2216,6 +2216,7 @@ export class SchemaReadHelper { // (undocumented) static isECSpecVersionNewer(ecSpecVersion?: ECSpecVersion): boolean; protected isSchemaItemLoaded(schemaItem: SchemaItem | undefined): boolean; + protected isSchemaItemLoadedAndDefined(schemaItem: SchemaItem | undefined): schemaItem is SchemaItem; protected loadCustomAttributes(container: AnyCAContainer, caProviders: Iterable): Promise; protected loadSchemaItem(schema: Schema, name: string, itemType: string, schemaItemObject?: Readonly): Promise; readSchema(schema: Schema, rawSchema: T, addSchemaToCache?: boolean): Promise; From 595cdafabe7dbe26aca752dac7cfb32df666e1b3 Mon Sep 17 00:00:00 2001 From: "Travis.Cobbs" <77415528+tcobbs-bentley@users.noreply.github.com> Date: Wed, 13 Aug 2025 10:48:38 -0600 Subject: [PATCH 06/15] rush change --- ...cobbs-lint-warning-cleanup-ec_2025-08-13-16-48.json | 10 ++++++++++ ...cobbs-lint-warning-cleanup-ec_2025-08-13-16-48.json | 10 ++++++++++ ...cobbs-lint-warning-cleanup-ec_2025-08-13-16-48.json | 10 ++++++++++ ...cobbs-lint-warning-cleanup-ec_2025-08-13-16-48.json | 10 ++++++++++ 4 files changed, 40 insertions(+) create mode 100644 common/changes/@itwin/ecschema-editing/tcobbs-lint-warning-cleanup-ec_2025-08-13-16-48.json create mode 100644 common/changes/@itwin/ecschema-locaters/tcobbs-lint-warning-cleanup-ec_2025-08-13-16-48.json create mode 100644 common/changes/@itwin/ecschema-metadata/tcobbs-lint-warning-cleanup-ec_2025-08-13-16-48.json create mode 100644 common/changes/@itwin/ecsql-common/tcobbs-lint-warning-cleanup-ec_2025-08-13-16-48.json diff --git a/common/changes/@itwin/ecschema-editing/tcobbs-lint-warning-cleanup-ec_2025-08-13-16-48.json b/common/changes/@itwin/ecschema-editing/tcobbs-lint-warning-cleanup-ec_2025-08-13-16-48.json new file mode 100644 index 000000000000..b0e7d3b96542 --- /dev/null +++ b/common/changes/@itwin/ecschema-editing/tcobbs-lint-warning-cleanup-ec_2025-08-13-16-48.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@itwin/ecschema-editing", + "comment": "", + "type": "none" + } + ], + "packageName": "@itwin/ecschema-editing" +} \ No newline at end of file diff --git a/common/changes/@itwin/ecschema-locaters/tcobbs-lint-warning-cleanup-ec_2025-08-13-16-48.json b/common/changes/@itwin/ecschema-locaters/tcobbs-lint-warning-cleanup-ec_2025-08-13-16-48.json new file mode 100644 index 000000000000..be9107090da4 --- /dev/null +++ b/common/changes/@itwin/ecschema-locaters/tcobbs-lint-warning-cleanup-ec_2025-08-13-16-48.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@itwin/ecschema-locaters", + "comment": "", + "type": "none" + } + ], + "packageName": "@itwin/ecschema-locaters" +} \ No newline at end of file diff --git a/common/changes/@itwin/ecschema-metadata/tcobbs-lint-warning-cleanup-ec_2025-08-13-16-48.json b/common/changes/@itwin/ecschema-metadata/tcobbs-lint-warning-cleanup-ec_2025-08-13-16-48.json new file mode 100644 index 000000000000..5dd8c0e532c0 --- /dev/null +++ b/common/changes/@itwin/ecschema-metadata/tcobbs-lint-warning-cleanup-ec_2025-08-13-16-48.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@itwin/ecschema-metadata", + "comment": "", + "type": "none" + } + ], + "packageName": "@itwin/ecschema-metadata" +} \ No newline at end of file diff --git a/common/changes/@itwin/ecsql-common/tcobbs-lint-warning-cleanup-ec_2025-08-13-16-48.json b/common/changes/@itwin/ecsql-common/tcobbs-lint-warning-cleanup-ec_2025-08-13-16-48.json new file mode 100644 index 000000000000..7ce9dd6ca292 --- /dev/null +++ b/common/changes/@itwin/ecsql-common/tcobbs-lint-warning-cleanup-ec_2025-08-13-16-48.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@itwin/ecsql-common", + "comment": "", + "type": "none" + } + ], + "packageName": "@itwin/ecsql-common" +} \ No newline at end of file From 081c0b0d00c68bbf314bd3ad24b262bc8528e52f Mon Sep 17 00:00:00 2001 From: "Travis.Cobbs" <77415528+tcobbs-bentley@users.noreply.github.com> Date: Wed, 13 Aug 2025 15:00:14 -0600 Subject: [PATCH 07/15] Dont' use has followed by get with a Map --- core/ecschema-editing/src/Validation/DiagnosticReporter.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/ecschema-editing/src/Validation/DiagnosticReporter.ts b/core/ecschema-editing/src/Validation/DiagnosticReporter.ts index c9b84c85b813..e3c2b904be12 100644 --- a/core/ecschema-editing/src/Validation/DiagnosticReporter.ts +++ b/core/ecschema-editing/src/Validation/DiagnosticReporter.ts @@ -68,11 +68,11 @@ export abstract class SuppressionDiagnosticReporter implements IDiagnosticReport * @param diagnostic The diagnostic to report. */ public report(diagnostic: AnyDiagnostic) { - if (this._suppressions && this._suppressions.has(diagnostic.schema.fullName)) { + if (undefined !== this._suppressions) { const suppressedCodes = this._suppressions.get(diagnostic.schema.fullName); - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - if (suppressedCodes!.includes(diagnostic.code)) + if (undefined !== suppressedCodes && suppressedCodes.includes(diagnostic.code)) { return; + } } this.reportInternal(diagnostic); From 196efef6a1feddacc89e123384ded42846c4db79 Mon Sep 17 00:00:00 2001 From: "Travis.Cobbs" <77415528+tcobbs-bentley@users.noreply.github.com> Date: Wed, 13 Aug 2025 15:04:51 -0600 Subject: [PATCH 08/15] Clean up the cleanup --- .../src/Validation/DiagnosticReporter.ts | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/core/ecschema-editing/src/Validation/DiagnosticReporter.ts b/core/ecschema-editing/src/Validation/DiagnosticReporter.ts index e3c2b904be12..822ffec1cb2d 100644 --- a/core/ecschema-editing/src/Validation/DiagnosticReporter.ts +++ b/core/ecschema-editing/src/Validation/DiagnosticReporter.ts @@ -68,12 +68,9 @@ export abstract class SuppressionDiagnosticReporter implements IDiagnosticReport * @param diagnostic The diagnostic to report. */ public report(diagnostic: AnyDiagnostic) { - if (undefined !== this._suppressions) { - const suppressedCodes = this._suppressions.get(diagnostic.schema.fullName); - if (undefined !== suppressedCodes && suppressedCodes.includes(diagnostic.code)) { - return; - } - } + const suppressedCodes = this._suppressions?.get(diagnostic.schema.fullName); + if (suppressedCodes && suppressedCodes.includes(diagnostic.code)) + return; this.reportInternal(diagnostic); } From 70db5240e9bbad14852f7f905611ab748f222d61 Mon Sep 17 00:00:00 2001 From: "Travis.Cobbs" <77415528+tcobbs-bentley@users.noreply.github.com> Date: Wed, 13 Aug 2025 15:14:11 -0600 Subject: [PATCH 09/15] Tweak loadSchemaReferenceSync to take schema as param --- .../src/Deserialization/Helper.ts | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/core/ecschema-metadata/src/Deserialization/Helper.ts b/core/ecschema-metadata/src/Deserialization/Helper.ts index 539d783fa206..048f22b862f6 100644 --- a/core/ecschema-metadata/src/Deserialization/Helper.ts +++ b/core/ecschema-metadata/src/Deserialization/Helper.ts @@ -206,7 +206,7 @@ export class SchemaReadHelper { // Load schema references first // Need to figure out if other schemas are present. for (const reference of this._parser.getReferences()) { - this.loadSchemaReferenceSync(reference); + this.loadSchemaReferenceSync(schema, reference); } if (this._visitorHelper) @@ -259,19 +259,16 @@ export class SchemaReadHelper { * Ensures that the schema references can be located and adds them to the schema. * @param ref The object to read the SchemaReference's props from. */ - private loadSchemaReferenceSync(ref: SchemaReferenceProps): void { + private loadSchemaReferenceSync(schema: Schema, ref: SchemaReferenceProps): void { const schemaKey = new SchemaKey(ref.name, ECVersion.fromString(ref.version)); const refSchema = this._context.getSchemaSync(schemaKey, SchemaMatchType.LatestWriteCompatible); - if (undefined === this._schema) { - throw new ECSchemaError(ECSchemaStatus.UnableToLoadSchema, `Schema is not defined when trying to load schema reference ${ref.name}.${ref.version}`); - } if (!refSchema) - throw new ECSchemaError(ECSchemaStatus.UnableToLocateSchema, `Could not locate the referenced schema, ${ref.name}.${ref.version}, of ${this._schema.schemaKey.name}`); + throw new ECSchemaError(ECSchemaStatus.UnableToLocateSchema, `Could not locate the referenced schema, ${ref.name}.${ref.version}, of ${schema.schemaKey.name}`); - (this._schema as MutableSchema).addReferenceSync(refSchema); + (schema as MutableSchema).addReferenceSync(refSchema); - SchemaGraph.generateGraphSync(this._schema).throwIfCycles(); - const results = this.validateSchemaReferences(this._schema); + SchemaGraph.generateGraphSync(schema).throwIfCycles(); + const results = this.validateSchemaReferences(schema); let errorMessage: string = ""; for (const result of results) { From 2a557250ff32504a7f553693c136ba2e9b6b3ebf Mon Sep 17 00:00:00 2001 From: "Travis.Cobbs" <77415528+tcobbs-bentley@users.noreply.github.com> Date: Thu, 14 Aug 2025 13:35:41 -0600 Subject: [PATCH 10/15] Get rid of isSchemaItemLoadedAndDefined --- .../src/Deserialization/Helper.ts | 19 +++++-------------- .../IncrementalSchemaReader.ts | 2 +- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/core/ecschema-metadata/src/Deserialization/Helper.ts b/core/ecschema-metadata/src/Deserialization/Helper.ts index 048f22b862f6..2f96212584c2 100644 --- a/core/ecschema-metadata/src/Deserialization/Helper.ts +++ b/core/ecschema-metadata/src/Deserialization/Helper.ts @@ -139,19 +139,10 @@ export class SchemaReadHelper { * @param schemaItem The SchemaItem to check. * @returns True if the SchemaItem has been fully loaded, false otherwise. */ - protected isSchemaItemLoaded(schemaItem: SchemaItem | undefined): boolean { + protected isSchemaItemLoaded(schemaItem: SchemaItem | undefined): schemaItem is SchemaItem { return schemaItem !== undefined; } - /** - * Same as isSchemaItemLoaded, but also asserts that the schema item is defined using a type predicate. - * @note isSchemaItemLoaded already checks if the item is defined, but updating it to be a type predicate - * would break existing code that uses it. - */ - protected isSchemaItemLoadedAndDefined(schemaItem: SchemaItem | undefined): schemaItem is SchemaItem { - return this.isSchemaItemLoaded(schemaItem) && schemaItem !== undefined; - } - /* Finish loading the rest of the schema */ private async loadSchema(schemaInfo: SchemaInfo, schema: Schema): Promise { // Verify that there are no schema reference cycles, this will start schema loading by loading their headers @@ -173,7 +164,7 @@ export class SchemaReadHelper { continue; const loadedItem = await this.loadSchemaItem(schema, itemName, itemType, rawItem); - if (this.isSchemaItemLoadedAndDefined(loadedItem) && this._visitorHelper) { + if (this.isSchemaItemLoaded(loadedItem) && this._visitorHelper) { await this._visitorHelper.visitSchemaPart(loadedItem); } } @@ -215,7 +206,7 @@ export class SchemaReadHelper { // Load all schema items for (const [itemName, itemType, rawItem] of this._parser.getItems()) { const loadedItem = this.loadSchemaItemSync(schema, itemName, itemType, rawItem); - if (this.isSchemaItemLoadedAndDefined(loadedItem) && this._visitorHelper) { + if (this.isSchemaItemLoaded(loadedItem) && this._visitorHelper) { this._visitorHelper.visitSchemaPartSync(loadedItem); } } @@ -536,7 +527,7 @@ export class SchemaReadHelper { if (foundItem) { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion schemaItem = await this.loadSchemaItem(this._schema!, ...foundItem); - if (!skipVisitor && this.isSchemaItemLoadedAndDefined(schemaItem) && this._visitorHelper) { + if (!skipVisitor && this.isSchemaItemLoaded(schemaItem) && this._visitorHelper) { await this._visitorHelper.visitSchemaPart(schemaItem); } if (loadCallBack && schemaItem) @@ -578,7 +569,7 @@ export class SchemaReadHelper { if (foundItem) { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion schemaItem = this.loadSchemaItemSync(this._schema!, ...foundItem); - if (!skipVisitor && this.isSchemaItemLoadedAndDefined(schemaItem) && this._visitorHelper) { + if (!skipVisitor && this.isSchemaItemLoaded(schemaItem) && this._visitorHelper) { this._visitorHelper.visitSchemaPartSync(schemaItem); } if (loadCallBack && schemaItem) diff --git a/core/ecschema-metadata/src/IncrementalLoading/IncrementalSchemaReader.ts b/core/ecschema-metadata/src/IncrementalLoading/IncrementalSchemaReader.ts index dcc1d8826295..01eb50ea7225 100644 --- a/core/ecschema-metadata/src/IncrementalLoading/IncrementalSchemaReader.ts +++ b/core/ecschema-metadata/src/IncrementalLoading/IncrementalSchemaReader.ts @@ -36,7 +36,7 @@ export class IncrementalSchemaReader extends SchemaReadHelper { * @param schemaItem The SchemaItem to check. * @returns True if the item has been loaded, false if still in progress. */ - protected override isSchemaItemLoaded(schemaItem: SchemaItem | undefined): boolean { + protected override isSchemaItemLoaded(schemaItem: SchemaItem | undefined): schemaItem is SchemaItem { return schemaItem !== undefined && schemaItem.loadingController !== undefined && schemaItem.loadingController.isComplete; From 5ae544779497311caa030ecb88135c4893f5632e Mon Sep 17 00:00:00 2001 From: "Travis.Cobbs" <77415528+tcobbs-bentley@users.noreply.github.com> Date: Thu, 14 Aug 2025 13:35:59 -0600 Subject: [PATCH 11/15] rush extract-api --- common/api/ecschema-metadata.api.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/common/api/ecschema-metadata.api.md b/common/api/ecschema-metadata.api.md index 5e0387fd8aa4..c3219183d975 100644 --- a/common/api/ecschema-metadata.api.md +++ b/common/api/ecschema-metadata.api.md @@ -2215,8 +2215,7 @@ export class SchemaReadHelper { constructor(parserType: AbstractParserConstructor, context?: SchemaContext, visitor?: ISchemaPartVisitor); // (undocumented) static isECSpecVersionNewer(ecSpecVersion?: ECSpecVersion): boolean; - protected isSchemaItemLoaded(schemaItem: SchemaItem | undefined): boolean; - protected isSchemaItemLoadedAndDefined(schemaItem: SchemaItem | undefined): schemaItem is SchemaItem; + protected isSchemaItemLoaded(schemaItem: SchemaItem | undefined): schemaItem is SchemaItem; protected loadCustomAttributes(container: AnyCAContainer, caProviders: Iterable): Promise; protected loadSchemaItem(schema: Schema, name: string, itemType: string, schemaItemObject?: Readonly): Promise; readSchema(schema: Schema, rawSchema: T, addSchemaToCache?: boolean): Promise; From da61e3dc84de7d953b2da1716ede85d1e7619b68 Mon Sep 17 00:00:00 2001 From: "Travis.Cobbs" <77415528+tcobbs-bentley@users.noreply.github.com> Date: Fri, 15 Aug 2025 09:04:48 -0600 Subject: [PATCH 12/15] Work around apparent compiler bug --- core/ecschema-editing/src/Validation/ECRules.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/core/ecschema-editing/src/Validation/ECRules.ts b/core/ecschema-editing/src/Validation/ECRules.ts index a5dbf186b4a9..084f0188d226 100644 --- a/core/ecschema-editing/src/Validation/ECRules.ts +++ b/core/ecschema-editing/src/Validation/ECRules.ts @@ -6,7 +6,6 @@ * @module Validation */ -import { expectDefined } from "@itwin/core-bentley"; import { AnyClass, AnyProperty, CustomAttribute, CustomAttributeContainerProps, ECClass, ECClassModifier, ECStringConstants, EntityClass, Enumeration, Mixin, PrimitiveProperty, PrimitiveType, primitiveTypeToString, @@ -309,10 +308,14 @@ export async function* incompatibleValueTypePropertyOverride(property: AnyProper if (!property.class.baseClass) return; - const primitiveType = getPrimitiveType(property); - if (!primitiveType) + const primitiveTypeOrUndefined = getPrimitiveType(property); + if (undefined === primitiveTypeOrUndefined) return; + // For some reason, even though the compiler KNOWS that primitiveTypeOrUndefined is defined here, + // if we use it directly in callback below it reverts to thinking it might be undefined. Adding + // a second variable fixes the apparent compiler bug. + const primitiveType = primitiveTypeOrUndefined; async function callback(baseClass: ECClass): Promise | undefined> { const baseProperty = await baseClass.getProperty(property.name, true); if (!baseProperty) @@ -329,7 +332,7 @@ export async function* incompatibleValueTypePropertyOverride(property: AnyProper if (!baseType || primitiveType === baseType) return; - return new Diagnostics.IncompatibleValueTypePropertyOverride(property, [property.class.fullName, property.name, baseClass.fullName, primitiveTypeToString(baseType), primitiveTypeToString(expectDefined(primitiveType))]); + return new Diagnostics.IncompatibleValueTypePropertyOverride(property, [property.class.fullName, property.name, baseClass.fullName, primitiveTypeToString(baseType), primitiveTypeToString(primitiveType)]); } for await (const baseClass of property.class.getAllBaseClasses()) { From 8e11ba7fda3289218f273c358c59cd6d18dabbf2 Mon Sep 17 00:00:00 2001 From: christophermlawson <32881725+christophermlawson@users.noreply.github.com> Date: Tue, 19 Aug 2025 14:24:22 -0400 Subject: [PATCH 13/15] wip --- .../src/Editing/RelationshipClasses.ts | 10 ++++--- .../src/Validation/DiagnosticReporter.ts | 2 +- .../src/Validation/ECRules.ts | 16 +++++------- .../test/Editing/RelationshipClasses.test.ts | 10 +++++++ .../src/SchemaJsonFileLocater.ts | 17 +++--------- .../src/SchemaXmlFileLocater.ts | 16 +++--------- .../src/Metadata/Enumeration.ts | 26 +++++++------------ .../src/test/Metadata/Enumeration.test.ts | 1 + 8 files changed, 43 insertions(+), 55 deletions(-) diff --git a/core/ecschema-editing/src/Editing/RelationshipClasses.ts b/core/ecschema-editing/src/Editing/RelationshipClasses.ts index 93413fba5298..c280c59721ef 100644 --- a/core/ecschema-editing/src/Editing/RelationshipClasses.ts +++ b/core/ecschema-editing/src/Editing/RelationshipClasses.ts @@ -6,7 +6,6 @@ * @module Editing */ -import { expectDefined } from "@itwin/core-bentley"; import { CustomAttribute, DelayedPromiseWithProps, ECClass, ECClassModifier, EntityClass, LazyLoadedRelationshipConstraintClass, Mixin, NavigationPropertyProps, RelationshipClass, RelationshipClassProps, RelationshipConstraint, RelationshipEnd, RelationshipMultiplicity, SchemaItemKey, SchemaItemType, @@ -117,14 +116,19 @@ export class RelationshipClasses extends ECClasses { .catch((e) => { throw new SchemaEditingError(ECEditingStatus.SetBaseClass, new ClassId(this.schemaItemType, itemKey), e); }); + + if (!relClass) { + throw new SchemaEditingError(ECEditingStatus.SetBaseClass, new ClassId(SchemaItemType.RelationshipClass, itemKey), new SchemaEditingError(ECEditingStatus.SchemaItemNotFoundInContext, new ClassId(this.schemaItemType, itemKey))); + } + const baseClass = relClass?.baseClass; await super.setBaseClass(itemKey, baseClassKey); try { - await this.validate(expectDefined(relClass)); + await this.validate(relClass); } catch(e: any) { - await (expectDefined(relClass) as ECClass as MutableClass).setBaseClass(baseClass); + await (relClass as ECClass as MutableClass).setBaseClass(baseClass); throw new SchemaEditingError(ECEditingStatus.SetBaseClass, new ClassId(SchemaItemType.RelationshipClass, itemKey), e); } } diff --git a/core/ecschema-editing/src/Validation/DiagnosticReporter.ts b/core/ecschema-editing/src/Validation/DiagnosticReporter.ts index 822ffec1cb2d..4eb7e6918359 100644 --- a/core/ecschema-editing/src/Validation/DiagnosticReporter.ts +++ b/core/ecschema-editing/src/Validation/DiagnosticReporter.ts @@ -68,7 +68,7 @@ export abstract class SuppressionDiagnosticReporter implements IDiagnosticReport * @param diagnostic The diagnostic to report. */ public report(diagnostic: AnyDiagnostic) { - const suppressedCodes = this._suppressions?.get(diagnostic.schema.fullName); + const suppressedCodes = this._suppressions ? this._suppressions.get(diagnostic.schema.fullName) : undefined; if (suppressedCodes && suppressedCodes.includes(diagnostic.code)) return; diff --git a/core/ecschema-editing/src/Validation/ECRules.ts b/core/ecschema-editing/src/Validation/ECRules.ts index 084f0188d226..d43daedbf6b1 100644 --- a/core/ecschema-editing/src/Validation/ECRules.ts +++ b/core/ecschema-editing/src/Validation/ECRules.ts @@ -308,15 +308,11 @@ export async function* incompatibleValueTypePropertyOverride(property: AnyProper if (!property.class.baseClass) return; - const primitiveTypeOrUndefined = getPrimitiveType(property); - if (undefined === primitiveTypeOrUndefined) + const primitiveType = getPrimitiveType(property); + if (undefined === primitiveType) return; - // For some reason, even though the compiler KNOWS that primitiveTypeOrUndefined is defined here, - // if we use it directly in callback below it reverts to thinking it might be undefined. Adding - // a second variable fixes the apparent compiler bug. - const primitiveType = primitiveTypeOrUndefined; - async function callback(baseClass: ECClass): Promise | undefined> { + async function callback(baseClass: ECClass, childType: PrimitiveType): Promise | undefined> { const baseProperty = await baseClass.getProperty(property.name, true); if (!baseProperty) return; @@ -329,14 +325,14 @@ export async function* incompatibleValueTypePropertyOverride(property: AnyProper const baseType = getPrimitiveType(baseProperty); // Return if rule passed - if (!baseType || primitiveType === baseType) + if (!baseType || childType === baseType) return; - return new Diagnostics.IncompatibleValueTypePropertyOverride(property, [property.class.fullName, property.name, baseClass.fullName, primitiveTypeToString(baseType), primitiveTypeToString(primitiveType)]); + return new Diagnostics.IncompatibleValueTypePropertyOverride(property, [property.class.fullName, property.name, baseClass.fullName, primitiveTypeToString(baseType), primitiveTypeToString(childType)]); } for await (const baseClass of property.class.getAllBaseClasses()) { - const result = await callback(baseClass); + const result = await callback(baseClass, primitiveType); if (result) yield result; } diff --git a/core/ecschema-editing/src/test/Editing/RelationshipClasses.test.ts b/core/ecschema-editing/src/test/Editing/RelationshipClasses.test.ts index 2a587bae1307..18d637dfb235 100644 --- a/core/ecschema-editing/src/test/Editing/RelationshipClasses.test.ts +++ b/core/ecschema-editing/src/test/Editing/RelationshipClasses.test.ts @@ -792,6 +792,16 @@ describe("Relationship tests from an existing schema", () => { }); }); + it("try adding relationship base class to non-relationship class, returns error", async () => { + const entityClassRes = await testEditor.entities.create(testKey, "testEntityClass", ECClassModifier.None); + const baseClassRes = await testEditor.relationships.create(testKey, "testRelationship", ECClassModifier.None, StrengthType.Holding, StrengthDirection.Forward); + await expect(testEditor.relationships.setBaseClass(entityClassRes, baseClassRes)).to.be.eventually.rejected.then(function (error) { + expect(error).to.have.property("errorNumber", ECEditingStatus.SetBaseClass); + expect(error).to.have.nested.property("innerError.message", `RelationshipClass ${entityClassRes.fullName} could not be found in the schema context.`); + expect(error).to.have.nested.property("innerError.errorNumber", ECEditingStatus.SchemaItemNotFoundInContext); + }); + }); + it("try adding base class to a relationship class where the base class cannot be located, returns error", async () => { const baseClassKey = new SchemaItemKey("testBaseClass", testKey); const relRes = await testEditor.relationships.create(testKey, "testRelationship", ECClassModifier.None, StrengthType.Referencing, StrengthDirection.Forward); diff --git a/core/ecschema-locaters/src/SchemaJsonFileLocater.ts b/core/ecschema-locaters/src/SchemaJsonFileLocater.ts index 5c643472abba..32b6da613798 100644 --- a/core/ecschema-locaters/src/SchemaJsonFileLocater.ts +++ b/core/ecschema-locaters/src/SchemaJsonFileLocater.ts @@ -75,16 +75,12 @@ export class SchemaJsonFileLocater extends SchemaFileLocater implements ISchemaL const schemaPath = maxCandidate.fileName; // Load the file - if (!await this.fileExists(schemaPath)) - return undefined; - - const schemaText = await this.readUtf8FileToString(schemaPath); - if (!schemaText) + if (!await this.fileExists(schemaPath) || !maxCandidate.schemaText) return undefined; this.addSchemaSearchPaths([path.dirname(schemaPath)]); - return Schema.startLoadingFromJson(schemaText, context); + return Schema.startLoadingFromJson(maxCandidate.schemaText, context); } /** @@ -103,17 +99,12 @@ export class SchemaJsonFileLocater extends SchemaFileLocater implements ISchemaL const maxCandidate = candidates.sort(this.compareSchemaKeyByVersion)[candidates.length - 1]; const schemaPath = maxCandidate.fileName; - // Load the file - if (!fs.existsSync(schemaPath)) - return undefined; - - const schemaText = fs.readFileSync(schemaPath, "utf-8"); - if (!schemaText) + if (!fs.existsSync(schemaPath) || !maxCandidate.schemaText) return undefined; this.addSchemaSearchPaths([path.dirname(schemaPath)]); - const schema = Schema.fromJsonSync(schemaText, context); + const schema = Schema.fromJsonSync(maxCandidate.schemaText, context); return schema; } } diff --git a/core/ecschema-locaters/src/SchemaXmlFileLocater.ts b/core/ecschema-locaters/src/SchemaXmlFileLocater.ts index 24123892a441..60bd95448c7a 100644 --- a/core/ecschema-locaters/src/SchemaXmlFileLocater.ts +++ b/core/ecschema-locaters/src/SchemaXmlFileLocater.ts @@ -52,15 +52,11 @@ export class SchemaXmlFileLocater extends SchemaFileLocater implements ISchemaLo const schemaPath = maxCandidate.fileName; // Load the file - if (undefined === await this.fileExists(schemaPath)) - return undefined; - - const schemaText = await this.readUtf8FileToString(schemaPath); - if (undefined === schemaText) + if (undefined === await this.fileExists(schemaPath) || !maxCandidate.schemaText) return undefined; const parser = new DOMParser(); - const document = parser.parseFromString(schemaText); + const document = parser.parseFromString(maxCandidate.schemaText); this.addSchemaSearchPaths([path.dirname(schemaPath)]); const reader = new SchemaReadHelper(XmlParser, context); @@ -86,15 +82,11 @@ export class SchemaXmlFileLocater extends SchemaFileLocater implements ISchemaLo const schemaPath = maxCandidate.fileName; // Load the file - if (!this.fileExistsSync(schemaPath)) - return undefined; - - const schemaText = this.readUtf8FileToStringSync(schemaPath); - if (!schemaText) + if (!this.fileExistsSync(schemaPath) || !maxCandidate.schemaText) return undefined; const parser = new DOMParser(); - const document = parser.parseFromString(schemaText); + const document = parser.parseFromString(maxCandidate.schemaText); this.addSchemaSearchPaths([path.dirname(schemaPath)]); const reader = new SchemaReadHelper(XmlParser, context); diff --git a/core/ecschema-metadata/src/Metadata/Enumeration.ts b/core/ecschema-metadata/src/Metadata/Enumeration.ts index 736de03aff80..f25e4a26af0a 100644 --- a/core/ecschema-metadata/src/Metadata/Enumeration.ts +++ b/core/ecschema-metadata/src/Metadata/Enumeration.ts @@ -33,7 +33,7 @@ export class Enumeration extends SchemaItem { public override readonly schemaItemType = Enumeration.schemaItemType; /** @internal */ public static override get schemaItemType() { return SchemaItemType.Enumeration; } - private _type?: PrimitiveType.Integer | PrimitiveType.String; + private _type: PrimitiveType.Integer | PrimitiveType.String; private _isStrict: boolean; private _enumerators: AnyEnumerator[]; @@ -42,7 +42,7 @@ export class Enumeration extends SchemaItem { public get isStrict() { return this._isStrict; } /** @internal */ - constructor(schema: Schema, name: string, primitiveType?: PrimitiveType.Integer | PrimitiveType.String) { + constructor(schema: Schema, name: string, primitiveType: PrimitiveType.Integer | PrimitiveType.String = PrimitiveType.String) { super(schema, name); this._type = primitiveType; this._isStrict = true; @@ -158,21 +158,15 @@ export class Enumeration extends SchemaItem { public override fromJSONSync(enumerationProps: EnumerationProps) { super.fromJSONSync(enumerationProps); - if (undefined === this._type) { - if (/int/i.test(enumerationProps.type)) { - this._type = PrimitiveType.Integer; - } else if (/string/i.test(enumerationProps.type)) { - this._type = PrimitiveType.String; - } else { - if (SchemaReadHelper.isECSpecVersionNewer({ readVersion: enumerationProps.originalECSpecMajorVersion, writeVersion: enumerationProps.originalECSpecMinorVersion } as ECSpecVersion)) - this._type = PrimitiveType.String; - else - throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The Enumeration ${this.name} has an invalid 'type' attribute. It should be either "int" or "string".`); - } + if (/int/i.test(enumerationProps.type)) { + this._type = PrimitiveType.Integer; + } else if (/string/i.test(enumerationProps.type)) { + this._type = PrimitiveType.String; } else { - const primitiveTypePattern = (this.isInt) ? /int/i : /string/i; - if (!primitiveTypePattern.test(enumerationProps.type)) - throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The Enumeration ${this.name} has an incompatible type. It must be "${(this.isInt) ? "int" : "string"}", not "${(this.isInt) ? "string" : "int"}".`); + if (SchemaReadHelper.isECSpecVersionNewer({ readVersion: enumerationProps.originalECSpecMajorVersion, writeVersion: enumerationProps.originalECSpecMinorVersion } as ECSpecVersion)) + this._type = PrimitiveType.String; + else + throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `The Enumeration ${this.name} has an invalid 'type' attribute. It should be either "int" or "string".`); } this._isStrict = enumerationProps.isStrict; diff --git a/core/ecschema-metadata/src/test/Metadata/Enumeration.test.ts b/core/ecschema-metadata/src/test/Metadata/Enumeration.test.ts index 23911259f5e0..0d374a491808 100644 --- a/core/ecschema-metadata/src/test/Metadata/Enumeration.test.ts +++ b/core/ecschema-metadata/src/test/Metadata/Enumeration.test.ts @@ -152,6 +152,7 @@ describe("Enumeration", () => { expect(testEnum.description).equal("Test description"); expect(testEnum.label).equal("Test Enumeration"); expect(testEnum.isStrict).equal(true); + expect(testEnum.type).equal(PrimitiveType.String); }); it("with enumerators", async () => { From 3dba84f5394ddef131d90f894703555a226806bc Mon Sep 17 00:00:00 2001 From: christophermlawson <32881725+christophermlawson@users.noreply.github.com> Date: Tue, 19 Aug 2025 15:37:58 -0400 Subject: [PATCH 14/15] wip --- .../IncrementalSchemaLocater.ts | 6 ++++-- .../src/Metadata/InvertedUnit.ts | 11 +++++++--- .../src/Metadata/KindOfQuantity.ts | 6 ++++-- .../src/Metadata/Property.ts | 20 ++++++++++++++----- .../src/Metadata/RelationshipClass.ts | 7 +++++-- core/ecschema-metadata/src/Metadata/Unit.ts | 11 +++++++--- .../src/SchemaFormatsProvider.ts | 8 +++++--- 7 files changed, 49 insertions(+), 20 deletions(-) diff --git a/core/ecschema-metadata/src/IncrementalLoading/IncrementalSchemaLocater.ts b/core/ecschema-metadata/src/IncrementalLoading/IncrementalSchemaLocater.ts index 5a28e47baf3a..f809d58bdc7a 100644 --- a/core/ecschema-metadata/src/IncrementalLoading/IncrementalSchemaLocater.ts +++ b/core/ecschema-metadata/src/IncrementalLoading/IncrementalSchemaLocater.ts @@ -2,7 +2,6 @@ * Copyright (c) Bentley Systems, Incorporated. All rights reserved. * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ -import { expectDefined } from "@itwin/core-bentley"; import { ECSchemaNamespaceUris } from "../Constants"; import { ISchemaLocater, SchemaContext } from "../Context"; import { SchemaProps } from "../Deserialization/JsonProps"; @@ -140,7 +139,10 @@ export abstract class IncrementalSchemaLocater implements ISchemaLocater { // to fetch the whole schema json. if (!await this.supportPartialSchemaLoading(schemaContext)) { const schemaJson = await this.getSchemaJson(schemaInfo.schemaKey, schemaContext); - return Schema.fromJson(expectDefined(schemaJson), schemaContext); + if (!schemaJson) + throw new ECSchemaError(ECSchemaStatus.UnableToLocateSchema, `Could not locate the schema, ${schemaInfo.schemaKey.name}.${schemaInfo.schemaKey.version.toString()}`); + + return Schema.fromJson(schemaJson, schemaContext); } // Fetches the schema partials for the given schema key. The first item in the array is the diff --git a/core/ecschema-metadata/src/Metadata/InvertedUnit.ts b/core/ecschema-metadata/src/Metadata/InvertedUnit.ts index 233c0c697f64..6c4b62cebdc4 100644 --- a/core/ecschema-metadata/src/Metadata/InvertedUnit.ts +++ b/core/ecschema-metadata/src/Metadata/InvertedUnit.ts @@ -6,7 +6,6 @@ * @module Metadata */ -import { expectDefined } from "@itwin/core-bentley"; import { DelayedPromiseWithProps } from "../DelayedPromise"; import { InvertedUnitProps } from "../Deserialization/JsonProps"; import { XmlSerializationUtils } from "../Deserialization/XmlSerializationUtils"; @@ -61,9 +60,15 @@ export class InvertedUnit extends SchemaItem { * @param includeSchemaVersion Include the Schema's version information in the serialized object. */ public override toJSON(standalone: boolean = false, includeSchemaVersion: boolean = false): InvertedUnitProps { + if (undefined === this.invertsUnit) + throw new ECSchemaError(ECSchemaStatus.InvalidType, `InvertedUnit ${this.fullName} has an invalid invertsUnit.`); + + if (undefined === this.unitSystem) + throw new ECSchemaError(ECSchemaStatus.InvalidType, `InvertedUnit ${this.fullName} has an invalid unitSystem.`); + const schemaJson = super.toJSON(standalone, includeSchemaVersion) as any; - schemaJson.invertsUnit = expectDefined(this.invertsUnit).fullName; - schemaJson.unitSystem = expectDefined(this.unitSystem).fullName; + schemaJson.invertsUnit = this.invertsUnit.fullName; + schemaJson.unitSystem = this.unitSystem.fullName; return schemaJson; } diff --git a/core/ecschema-metadata/src/Metadata/KindOfQuantity.ts b/core/ecschema-metadata/src/Metadata/KindOfQuantity.ts index 83c5ce308f54..556053b2a6fd 100644 --- a/core/ecschema-metadata/src/Metadata/KindOfQuantity.ts +++ b/core/ecschema-metadata/src/Metadata/KindOfQuantity.ts @@ -6,7 +6,6 @@ * @module Metadata */ -import { expectDefined } from "@itwin/core-bentley"; import { DelayedPromiseWithProps } from "../DelayedPromise"; import { KindOfQuantityProps } from "../Deserialization/JsonProps"; import { XmlSerializationUtils } from "../Deserialization/XmlSerializationUtils"; @@ -150,9 +149,12 @@ export class KindOfQuantity extends SchemaItem { * @param includeSchemaVersion Include the Schema's version information in the serialized object. */ public override toJSON(standalone: boolean = false, includeSchemaVersion: boolean = false): KindOfQuantityProps { + if (undefined === this.persistenceUnit) + throw new ECSchemaError(ECSchemaStatus.InvalidType, `KindOfQuantity ${this.fullName} has an invalid persistenceUnit.`); + const schemaJson = super.toJSON(standalone, includeSchemaVersion) as any; schemaJson.relativeError = this.relativeError; - schemaJson.persistenceUnit = expectDefined(this.persistenceUnit).fullName; + schemaJson.persistenceUnit = this.persistenceUnit.fullName; if (undefined !== this.presentationFormats && 0 < this.presentationFormats.length) schemaJson.presentationUnits = this.presentationFormats.map((format) => format.fullName); return schemaJson; diff --git a/core/ecschema-metadata/src/Metadata/Property.ts b/core/ecschema-metadata/src/Metadata/Property.ts index 1e5359c51639..2a489596c0a7 100644 --- a/core/ecschema-metadata/src/Metadata/Property.ts +++ b/core/ecschema-metadata/src/Metadata/Property.ts @@ -6,7 +6,6 @@ * @module Metadata */ -import { expectDefined } from "@itwin/core-bentley"; import { DelayedPromiseWithProps } from "../DelayedPromise"; import { ArrayPropertyProps, EnumerationPropertyProps, NavigationPropertyProps, PrimitiveArrayPropertyProps, PrimitiveOrEnumPropertyBaseProps, @@ -515,8 +514,11 @@ export class EnumerationProperty extends PrimitiveOrEnumPropertyBase { * Save this EnumerationProperty's properties to an object for serializing to JSON. */ public override toJSON(): EnumerationPropertyProps { + if (undefined === this.enumeration) + throw new ECSchemaError(ECSchemaStatus.InvalidType, `EnumerationProperty ${this.fullName} has an invalid enumeration.`); + const schemaJson = super.toJSON() as any; - schemaJson.typeName = expectDefined(this.enumeration).fullName; + schemaJson.typeName = this.enumeration.fullName; return schemaJson; } @@ -530,11 +532,16 @@ export class EnumerationProperty extends PrimitiveOrEnumPropertyBase { public override fromJSONSync(enumerationPropertyProps: EnumerationPropertyProps) { super.fromJSONSync(enumerationPropertyProps); if (undefined !== enumerationPropertyProps.typeName) { - if (!(expectDefined(this.enumeration).fullName).match(enumerationPropertyProps.typeName)) // need to match {schema}.{version}.{itemName} on typeName + if (undefined === this.enumeration) + throw new ECSchemaError(ECSchemaStatus.InvalidType, `EnumerationProperty ${this.fullName} has an invalid enumeration.`); + + if (!(this.enumeration.fullName).match(enumerationPropertyProps.typeName)) // need to match {schema}.{version}.{itemName} on typeName throw new ECSchemaError(ECSchemaStatus.InvalidECJson, ``); - const enumSchemaItemKey = this.class.schema.getSchemaItemKey(expectDefined(this.enumeration).fullName); + + const enumSchemaItemKey = this.class.schema.getSchemaItemKey(this.enumeration.fullName); if (!enumSchemaItemKey) throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `Unable to locate the enumeration ${enumerationPropertyProps.typeName}.`); + this._enumeration = new DelayedPromiseWithProps(enumSchemaItemKey, async () => { const enumeration = await this.class.schema.lookupItem(enumSchemaItemKey, Enumeration); @@ -547,8 +554,11 @@ export class EnumerationProperty extends PrimitiveOrEnumPropertyBase { /** @internal */ public override async toXml(schemaXml: Document): Promise { + if (undefined === this.enumeration) + throw new ECSchemaError(ECSchemaStatus.InvalidType, `EnumerationProperty ${this.fullName} has an invalid enumeration.`); + const itemElement = await super.toXml(schemaXml); - const enumeration = expectDefined(await this.enumeration); + const enumeration = await this.enumeration; const enumerationName = XmlSerializationUtils.createXmlTypedName(this.schema, enumeration.schema, enumeration.name); itemElement.setAttribute("typeName", enumerationName); return itemElement; diff --git a/core/ecschema-metadata/src/Metadata/RelationshipClass.ts b/core/ecschema-metadata/src/Metadata/RelationshipClass.ts index 635c249b3757..38ea541e9208 100644 --- a/core/ecschema-metadata/src/Metadata/RelationshipClass.ts +++ b/core/ecschema-metadata/src/Metadata/RelationshipClass.ts @@ -6,7 +6,7 @@ * @module Metadata */ -import { expectDefined } from "@itwin/core-bentley"; +import { assert } from "@itwin/core-bentley"; import { DelayedPromiseWithProps } from "../DelayedPromise"; import { ECSpecVersion, SchemaReadHelper } from "../Deserialization/Helper"; import { RelationshipClassProps, RelationshipConstraintProps } from "../Deserialization/JsonProps"; @@ -343,9 +343,12 @@ export class RelationshipConstraint implements CustomAttributeContainerProps { const abstractConstraintSchemaItemKey = relClassSchema.getSchemaItemKey(relationshipConstraintProps.abstractConstraint); if (!abstractConstraintSchemaItemKey) throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `Unable to locate the abstractConstraint ${relationshipConstraintProps.abstractConstraint}.`); + this.setAbstractConstraint(new DelayedPromiseWithProps(abstractConstraintSchemaItemKey, async () => { - const tempAbstractConstraint = await relClassSchema.lookupItem(expectDefined(relationshipConstraintProps.abstractConstraint)); + // This should never occur due to outer if clause + assert(relationshipConstraintProps.abstractConstraint !== undefined) + const tempAbstractConstraint = await relClassSchema.lookupItem(relationshipConstraintProps.abstractConstraint); if (undefined === tempAbstractConstraint || (!EntityClass.isEntityClass(tempAbstractConstraint) && !Mixin.isMixin(tempAbstractConstraint) && !RelationshipClass.isRelationshipClass(tempAbstractConstraint))) throw new ECSchemaError(ECSchemaStatus.InvalidECJson, `Unable to locate the abstractConstraint ${relationshipConstraintProps.abstractConstraint}.`); diff --git a/core/ecschema-metadata/src/Metadata/Unit.ts b/core/ecschema-metadata/src/Metadata/Unit.ts index bbf0d7c20a5d..15ffdd765dca 100644 --- a/core/ecschema-metadata/src/Metadata/Unit.ts +++ b/core/ecschema-metadata/src/Metadata/Unit.ts @@ -6,7 +6,6 @@ * @module Metadata */ -import { expectDefined } from "@itwin/core-bentley"; import { DelayedPromiseWithProps } from "../DelayedPromise"; import { SchemaItemUnitProps } from "../Deserialization/JsonProps"; import { XmlSerializationUtils } from "../Deserialization/XmlSerializationUtils"; @@ -82,9 +81,15 @@ export class Unit extends SchemaItem { * @param includeSchemaVersion Include the Schema's version information in the serialized object. */ public override toJSON(standalone: boolean = false, includeSchemaVersion: boolean = false): SchemaItemUnitProps { + if (undefined === this.phenomenon) + throw new ECSchemaError(ECSchemaStatus.InvalidType, `Unit ${this.fullName} has an invalid phenomenon.`); + + if (undefined === this.unitSystem) + throw new ECSchemaError(ECSchemaStatus.InvalidType, `Unit ${this.fullName} has an invalid unitSystem.`); + const schemaJson = super.toJSON(standalone, includeSchemaVersion) as any; - schemaJson.phenomenon = expectDefined(this.phenomenon).fullName; - schemaJson.unitSystem = expectDefined(this.unitSystem).fullName; + schemaJson.phenomenon = this.phenomenon.fullName; + schemaJson.unitSystem = this.unitSystem.fullName; schemaJson.definition = this.definition; if (this.hasNumerator) schemaJson.numerator = this.numerator; diff --git a/core/ecschema-metadata/src/SchemaFormatsProvider.ts b/core/ecschema-metadata/src/SchemaFormatsProvider.ts index 6a2a260d82b9..d12eef725d56 100644 --- a/core/ecschema-metadata/src/SchemaFormatsProvider.ts +++ b/core/ecschema-metadata/src/SchemaFormatsProvider.ts @@ -110,12 +110,14 @@ export class SchemaFormatsProvider implements FormatsProvider { // If no matching presentation format was found, use persistence unit format if it matches unit system. const persistenceUnit = await kindOfQuantity.persistenceUnit; - const persistenceUnitSystem = await persistenceUnit?.unitSystem; + if (!persistenceUnit) + throw Error(`KindOfQuantity ${kindOfQuantity.fullName} has an invalid persistenceUnit.`); + + const persistenceUnitSystem = await persistenceUnit.unitSystem; if (persistenceUnitSystem && unitSystemMatchers.some((matcher) => matcher(persistenceUnitSystem))) { this._formatsRetrieved.add(itemKey.fullName); // It is only possible to get here if persistenceUnit is defined. - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const props = getPersistenceUnitFormatProps(persistenceUnit!); + const props = getPersistenceUnitFormatProps(persistenceUnit); return this.convertToFormatDefinition(props, kindOfQuantity); } From 844e03b87e998d3d914e896569920ed08120af09 Mon Sep 17 00:00:00 2001 From: christophermlawson <32881725+christophermlawson@users.noreply.github.com> Date: Tue, 19 Aug 2025 15:41:16 -0400 Subject: [PATCH 15/15] wip --- core/ecschema-editing/src/Editing/RelationshipClasses.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/ecschema-editing/src/Editing/RelationshipClasses.ts b/core/ecschema-editing/src/Editing/RelationshipClasses.ts index c280c59721ef..46d6689628d9 100644 --- a/core/ecschema-editing/src/Editing/RelationshipClasses.ts +++ b/core/ecschema-editing/src/Editing/RelationshipClasses.ts @@ -121,7 +121,7 @@ export class RelationshipClasses extends ECClasses { throw new SchemaEditingError(ECEditingStatus.SetBaseClass, new ClassId(SchemaItemType.RelationshipClass, itemKey), new SchemaEditingError(ECEditingStatus.SchemaItemNotFoundInContext, new ClassId(this.schemaItemType, itemKey))); } - const baseClass = relClass?.baseClass; + const baseClass = relClass.baseClass; await super.setBaseClass(itemKey, baseClassKey);