diff --git a/common/api/ecschema-metadata.api.md b/common/api/ecschema-metadata.api.md index f3dc7a69a628..c3219183d975 100644 --- a/common/api/ecschema-metadata.api.md +++ b/common/api/ecschema-metadata.api.md @@ -2215,7 +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 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; 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 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..46d6689628d9 100644 --- a/core/ecschema-editing/src/Editing/RelationshipClasses.ts +++ b/core/ecschema-editing/src/Editing/RelationshipClasses.ts @@ -102,7 +102,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); } } @@ -116,14 +116,19 @@ export class RelationshipClasses extends ECClasses { .catch((e) => { throw new SchemaEditingError(ECEditingStatus.SetBaseClass, new ClassId(this.schemaItemType, itemKey), e); }); - const baseClass = relClass?.baseClass; + + 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(relClass!); + await this.validate(relClass); } catch(e: any) { - await (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/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..4eb7e6918359 100644 --- a/core/ecschema-editing/src/Validation/DiagnosticReporter.ts +++ b/core/ecschema-editing/src/Validation/DiagnosticReporter.ts @@ -68,11 +68,9 @@ 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)) { - const suppressedCodes = this._suppressions.get(diagnostic.schema.fullName); - if (suppressedCodes!.includes(diagnostic.code)) - return; - } + const suppressedCodes = this._suppressions ? this._suppressions.get(diagnostic.schema.fullName) : undefined; + if (suppressedCodes && suppressedCodes.includes(diagnostic.code)) + return; this.reportInternal(diagnostic); } diff --git a/core/ecschema-editing/src/Validation/ECRules.ts b/core/ecschema-editing/src/Validation/ECRules.ts index 73e348f45733..d43daedbf6b1 100644 --- a/core/ecschema-editing/src/Validation/ECRules.ts +++ b/core/ecschema-editing/src/Validation/ECRules.ts @@ -309,10 +309,10 @@ export async function* incompatibleValueTypePropertyOverride(property: AnyProper return; const primitiveType = getPrimitiveType(property); - if (!primitiveType) + if (undefined === primitiveType) return; - 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; @@ -325,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/Validation/SchemaChanges.ts b/core/ecschema-editing/src/Validation/SchemaChanges.ts index 8b178e409119..2fd51373d007 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); + const existingChanges = this.entityClassChanges.get(ecClass.name); + 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-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-locaters/src/StubSchemaXmlFileLocater.ts b/core/ecschema-locaters/src/StubSchemaXmlFileLocater.ts index 5e47923b17f1..ca5f3666a9c2 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, the "" passed to 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..2f96212584c2 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()}`); @@ -138,7 +139,7 @@ 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; } @@ -164,7 +165,7 @@ export class SchemaReadHelper { const loadedItem = await this.loadSchemaItem(schema, itemName, itemType, rawItem); if (this.isSchemaItemLoaded(loadedItem) && this._visitorHelper) { - await this._visitorHelper.visitSchemaPart(loadedItem!); + await this._visitorHelper.visitSchemaPart(loadedItem); } } @@ -196,7 +197,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) @@ -206,7 +207,7 @@ export class SchemaReadHelper { 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!); + this._visitorHelper.visitSchemaPartSync(loadedItem); } } @@ -249,16 +250,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 (!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) { @@ -516,15 +517,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!); + await this._visitorHelper.visitSchemaPart(schemaItem); } if (loadCallBack && schemaItem) loadCallBack(schemaItem); @@ -558,12 +562,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!); + 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..f809d58bdc7a 100644 --- a/core/ecschema-metadata/src/IncrementalLoading/IncrementalSchemaLocater.ts +++ b/core/ecschema-metadata/src/IncrementalLoading/IncrementalSchemaLocater.ts @@ -139,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(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 @@ -186,9 +189,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..01eb50ea7225 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"; @@ -35,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; @@ -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/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/Metadata/InvertedUnit.ts b/core/ecschema-metadata/src/Metadata/InvertedUnit.ts index 71f9d1f17036..6c4b62cebdc4 100644 --- a/core/ecschema-metadata/src/Metadata/InvertedUnit.ts +++ b/core/ecschema-metadata/src/Metadata/InvertedUnit.ts @@ -60,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 = this.invertsUnit!.fullName; - schemaJson.unitSystem = 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 dbba46ef7f9f..556053b2a6fd 100644 --- a/core/ecschema-metadata/src/Metadata/KindOfQuantity.ts +++ b/core/ecschema-metadata/src/Metadata/KindOfQuantity.ts @@ -149,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 = 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/OverrideFormat.ts b/core/ecschema-metadata/src/Metadata/OverrideFormat.ts index 0c23f42dcc95..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 ${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/Property.ts b/core/ecschema-metadata/src/Metadata/Property.ts index 9ee23b92c0aa..2a489596c0a7 100644 --- a/core/ecschema-metadata/src/Metadata/Property.ts +++ b/core/ecschema-metadata/src/Metadata/Property.ts @@ -514,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 = this.enumeration!.fullName; + schemaJson.typeName = this.enumeration.fullName; return schemaJson; } @@ -529,11 +532,16 @@ 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 (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(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); @@ -546,9 +554,12 @@ 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 = await this.enumeration; - const enumerationName = XmlSerializationUtils.createXmlTypedName(this.schema, enumeration!.schema, enumeration!.name); + 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..38ea541e9208 100644 --- a/core/ecschema-metadata/src/Metadata/RelationshipClass.ts +++ b/core/ecschema-metadata/src/Metadata/RelationshipClass.ts @@ -6,6 +6,7 @@ * @module Metadata */ +import { assert } from "@itwin/core-bentley"; import { DelayedPromiseWithProps } from "../DelayedPromise"; import { ECSpecVersion, SchemaReadHelper } from "../Deserialization/Helper"; import { RelationshipClassProps, RelationshipConstraintProps } from "../Deserialization/JsonProps"; @@ -342,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(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/Schema.ts b/core/ecschema-metadata/src/Metadata/Schema.ts index 1b59bd8b2ec5..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 '${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 72de61b24309..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, ${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, ${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/Metadata/Unit.ts b/core/ecschema-metadata/src/Metadata/Unit.ts index 9ea038cf7bdb..15ffdd765dca 100644 --- a/core/ecschema-metadata/src/Metadata/Unit.ts +++ b/core/ecschema-metadata/src/Metadata/Unit.ts @@ -81,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 = this.phenomenon!.fullName; - schemaJson.unitSystem = 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 6fd990b52c8a..d12eef725d56 100644 --- a/core/ecschema-metadata/src/SchemaFormatsProvider.ts +++ b/core/ecschema-metadata/src/SchemaFormatsProvider.ts @@ -110,10 +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); - const props = getPersistenceUnitFormatProps(persistenceUnit!); + // It is only possible to get here if persistenceUnit is defined. + 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 { 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 () => { diff --git a/core/ecschema-metadata/src/test/UnitProvider/UnitProvider.test.ts b/core/ecschema-metadata/src/test/UnitProvider/UnitProvider.test.ts index faeac62b839b..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 ${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 ${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 ${expectedLabels}`).to.include.members(expectedLabels); + expect(altDisplayLabels, `Alternate display labels should be ${expectedLabels.toString()}`).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) {