@itwin/ecschema-metadata
Version:
ECObjects core concepts in typescript
765 lines • 33.1 kB
JavaScript
"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
* @module Metadata
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.MutableSchema = exports.Schema = void 0;
const Helper_1 = require("../Deserialization/Helper");
const JsonParser_1 = require("../Deserialization/JsonParser");
const XmlParser_1 = require("../Deserialization/XmlParser");
const XmlSerializationUtils_1 = require("../Deserialization/XmlSerializationUtils");
const ECObjects_1 = require("../ECObjects");
const Exception_1 = require("../Exception");
const SchemaKey_1 = require("../SchemaKey");
const ECName_1 = require("../ECName");
const Class_1 = require("./Class");
const Constant_1 = require("./Constant");
const CustomAttribute_1 = require("./CustomAttribute");
const CustomAttributeClass_1 = require("./CustomAttributeClass");
const EntityClass_1 = require("./EntityClass");
const Enumeration_1 = require("./Enumeration");
const Format_1 = require("./Format");
const InvertedUnit_1 = require("./InvertedUnit");
const KindOfQuantity_1 = require("./KindOfQuantity");
const Mixin_1 = require("./Mixin");
const Phenomenon_1 = require("./Phenomenon");
const PropertyCategory_1 = require("./PropertyCategory");
const RelationshipClass_1 = require("./RelationshipClass");
const SchemaItem_1 = require("./SchemaItem");
const Unit_1 = require("./Unit");
const UnitSystem_1 = require("./UnitSystem");
const Constants_1 = require("../Constants");
/**
* @public @preview
*/
class Schema {
static _currentECSpecVersion = "3.2";
_context;
_schemaKey;
_alias;
_label;
_description;
references;
_items;
_customAttributes;
_originalECSpecMajorVersion;
_originalECSpecMinorVersion;
_loadingController;
/** @internal */
constructor(context, nameOrKey, alias, readVer, writeVer, minorVer) {
this._schemaKey = (typeof (nameOrKey) === "string") ? new SchemaKey_1.SchemaKey(nameOrKey, new SchemaKey_1.ECVersion(readVer, writeVer, minorVer)) : nameOrKey;
this._context = context;
this.references = [];
this._items = new Map();
if (alias !== undefined && ECName_1.ECName.validate(alias)) {
this._alias = alias;
}
else if (nameOrKey !== undefined) {
throw new Exception_1.ECSchemaError(Exception_1.ECSchemaStatus.InvalidECJson, `The Schema ${this.name} does not have the required 'alias' attribute.`);
}
this._originalECSpecMajorVersion = Schema.currentECSpecMajorVersion;
this._originalECSpecMinorVersion = Schema.currentECSpecMinorVersion;
}
get schemaKey() {
if (undefined === this._schemaKey)
throw new Exception_1.ECSchemaError(Exception_1.ECSchemaStatus.InvalidECJson, `The schema has an invalid or missing SchemaKey.`);
return this._schemaKey;
}
get name() {
if (this._schemaKey === undefined)
throw new Exception_1.ECSchemaError(Exception_1.ECSchemaStatus.InvalidECJson, `The schema has an invalid or missing SchemaKey.`);
return this.schemaKey.name;
}
get readVersion() {
if (this._schemaKey === undefined)
throw new Exception_1.ECSchemaError(Exception_1.ECSchemaStatus.InvalidECJson, `The schema has an invalid or missing SchemaKey.`);
return this.schemaKey.readVersion;
}
get writeVersion() {
if (this._schemaKey === undefined)
throw new Exception_1.ECSchemaError(Exception_1.ECSchemaStatus.InvalidECJson, `The schema has an invalid or missing SchemaKey.`);
return this.schemaKey.writeVersion;
}
get minorVersion() {
if (this._schemaKey === undefined)
throw new Exception_1.ECSchemaError(Exception_1.ECSchemaStatus.InvalidECJson, `The schema has an invalid or missing SchemaKey.`);
return this.schemaKey.minorVersion;
}
get originalECSpecMajorVersion() { return this._originalECSpecMajorVersion; }
get originalECSpecMinorVersion() { return this._originalECSpecMinorVersion; }
static get currentECSpecMajorVersion() { return parseInt(Schema._currentECSpecVersion.split(".")[0], 10); }
static get currentECSpecMinorVersion() { return parseInt(Schema._currentECSpecVersion.split(".")[1], 10); }
get _isECSpecVersionUnsupported() {
return (this.originalECSpecMajorVersion !== 3 || this.originalECSpecMinorVersion === undefined
|| (this.originalECSpecMinorVersion < 2 || this.originalECSpecMinorVersion > Schema.currentECSpecMinorVersion));
}
get alias() {
if (this._alias === undefined || this._alias === null) {
throw new Exception_1.ECSchemaError(Exception_1.ECSchemaStatus.InvalidECJson, `The Schema ${this.name} does not have the required 'alias' attribute.`);
}
else {
return this._alias;
}
}
get label() { return this._label; }
get description() { return this._description; }
get customAttributes() { return this._customAttributes; }
/** Returns the schema name. */
get fullName() { return this.schemaKey.name; }
/** Returns the schema. */
get schema() { return this; }
/** Returns the schema context this schema is within. */
get context() { return this._context; }
/**
* Returns the SchemaLoadingController for this Schema. This would only be set if the schema is
* loaded incrementally.
* @internal
*/
get loadingController() {
return this._loadingController;
}
/**
* Returns a SchemaItemKey given the item name and the schema it belongs to
* @param fullName fully qualified name {Schema name}.{Item Name}
*/
getSchemaItemKey(fullName) {
const [schemaName, itemName] = SchemaItem_1.SchemaItem.parseFullName(fullName);
let schemaKey = this.schemaKey;
if (this.name !== schemaName) {
const newSchemaRef = this.getReferenceSync(schemaName);
if (undefined === newSchemaRef)
throw new Exception_1.ECSchemaError(Exception_1.ECSchemaStatus.InvalidECJson, `Unable to find the referenced SchemaItem ${itemName}.`);
schemaKey = newSchemaRef.schemaKey;
}
return new SchemaKey_1.SchemaItemKey(itemName, schemaKey);
}
/** @internal */
addItem(item) {
if (undefined !== this.getItemSync(item.name))
throw new Exception_1.ECSchemaError(Exception_1.ECSchemaStatus.DuplicateItem, `The SchemaItem ${item.name} cannot be added to the schema ${this.name} because it already exists`);
this._items.set(item.name.toUpperCase(), item);
}
/**
* @internal
*/
createClass(type, name, modifier) {
const item = new type(this, name, modifier);
this.addItem(item);
return item;
}
/**
* Deletes a class from within this schema.
* @param name the local (unqualified) class name, lookup is case-insensitive
* @internal
*/
async deleteClass(name) {
const schemaItem = await this.getItem(name);
if (Class_1.ECClass.isECClass(schemaItem)) {
this._items.delete(name.toUpperCase());
}
}
/**
* Deletes a class from within this schema.
* @param name the local (unqualified) class name, lookup is case-insensitive
* @internal
*/
deleteClassSync(name) {
const schemaItem = this.getItemSync(name);
if (Class_1.ECClass.isECClass(schemaItem))
this._items.delete(name.toUpperCase());
}
/**
* Deletes a SchemaItem from within this schema.
* @param name the local (unqualified) class name, lookup is case-insensitive
* @internal
*/
async deleteSchemaItem(name) {
const schemaItem = await this.getItem(name);
if (SchemaItem_1.SchemaItem.isSchemaItem(schemaItem)) {
this._items.delete(name.toUpperCase());
}
}
/**
* Deletes a SchemaItem from within this schema.
* @param name the local (unqualified) class name, lookup is case-insensitive
* @internal
*/
deleteSchemaItemSync(name) {
const schemaItem = this.getItemSync(name);
if (SchemaItem_1.SchemaItem.isSchemaItem(schemaItem))
this._items.delete(name.toUpperCase());
}
/** @internal */
createItem(type, name) {
const item = new type(this, name);
this.addItem(item);
return item;
}
/** @internal */
addCustomAttribute(customAttribute) {
if (!this._customAttributes)
this._customAttributes = new Map();
this._customAttributes.set(customAttribute.className, customAttribute);
}
/**
* Creates a EntityClass with the provided name in this schema.
* @param name
* @param modifier
* @internal
*/
async createEntityClass(name, modifier) {
return this.createClass(EntityClass_1.EntityClass, name, modifier);
}
/** @internal */
createEntityClassSync(name, modifier) {
return this.createClass(EntityClass_1.EntityClass, name, modifier);
}
/**
* Creates a Mixin with the provided name in this schema.
* @param name
* @internal
*/
async createMixinClass(name) { return this.createClass(Mixin_1.Mixin, name); }
/** @internal */
createMixinClassSync(name) { return this.createClass(Mixin_1.Mixin, name); }
/**
* Creates a StructClass with the provided name in this schema.
* @param name
* @param modifier
* @internal
*/
async createStructClass(name, modifier) {
return this.createClass(Class_1.StructClass, name, modifier);
}
/** @internal */
createStructClassSync(name, modifier) {
return this.createClass(Class_1.StructClass, name, modifier);
}
/**
* Creates a CustomAttributeClass with the provided name in this schema.
* @param name
* @param modifier
* @internal
*/
async createCustomAttributeClass(name, modifier) {
return this.createClass(CustomAttributeClass_1.CustomAttributeClass, name, modifier);
}
/** @internal */
createCustomAttributeClassSync(name, modifier) {
return this.createClass(CustomAttributeClass_1.CustomAttributeClass, name, modifier);
}
/**
* Creates a RelationshipClass with the provided name in this schema.
* @param name
* @param modifier
* @internal
*/
async createRelationshipClass(name, modifier) {
return this.createRelationshipClassSync(name, modifier);
}
/** @internal */
createRelationshipClassSync(name, modifier) {
return this.createClass(RelationshipClass_1.RelationshipClass, name, modifier);
}
/**
* Creates an Enumeration with the provided name in this schema.
* @param name
* @param primitiveType
*
* @internal
*/
async createEnumeration(name, primitiveType) {
return this.createEnumerationSync(name, primitiveType);
}
/** @internal */
createEnumerationSync(name, primitiveType) {
const item = new Enumeration_1.Enumeration(this, name, primitiveType);
this.addItem(item);
return item;
}
/**
* Creates an KindOfQuantity with the provided name in this schema.
* @param name
* @internal
*/
async createKindOfQuantity(name) {
return this.createKindOfQuantitySync(name);
}
/** @internal */
createKindOfQuantitySync(name) {
return this.createItem(KindOfQuantity_1.KindOfQuantity, name);
}
/**
* Creates a Constant with the provided name in this schema.
* @param name
* @internal
*/
async createConstant(name) {
return this.createItem(Constant_1.Constant, name);
}
/** @internal */
createConstantSync(name) {
return this.createItem(Constant_1.Constant, name);
}
/**
* Creates a Inverted Unit with the provided name in this schema.
* @param name
* @internal
*/
async createInvertedUnit(name) {
return this.createItem(InvertedUnit_1.InvertedUnit, name);
}
/** @internal */
createInvertedUnitSync(name) {
return this.createItem(InvertedUnit_1.InvertedUnit, name);
}
/**
* Creates an Format with the provided name in this schema.
* @param name
* @internal
*/
async createFormat(name) {
return this.createItem(Format_1.Format, name);
}
/** @internal */
createFormatSync(name) {
return this.createItem(Format_1.Format, name);
}
/**
* Creates a UnitSystem with the provided name in this schema.
* @param name
* @internal
*/
async createUnitSystem(name) {
return this.createItem(UnitSystem_1.UnitSystem, name);
}
/** @internal */
createUnitSystemSync(name) {
return this.createItem(UnitSystem_1.UnitSystem, name);
}
/**
* Creates a Phenomenon with the provided name in this schema.
* @param name
* @internal
*/
async createPhenomenon(name) {
return this.createItem(Phenomenon_1.Phenomenon, name);
}
/** @internal */
createPhenomenonSync(name) {
return this.createItem(Phenomenon_1.Phenomenon, name);
}
/**
* Creates a Unit with the provided name in this schema.
* @param name
* @internal
*/
async createUnit(name) {
return this.createItem(Unit_1.Unit, name);
}
/** @internal */
createUnitSync(name) {
return this.createItem(Unit_1.Unit, name);
}
/**
* Creates an PropertyCategory with the provided name in this schema.
* @param name
* @internal
*/
async createPropertyCategory(name) {
return this.createItem(PropertyCategory_1.PropertyCategory, name);
}
/** @internal */
createPropertyCategorySync(name) {
return this.createItem(PropertyCategory_1.PropertyCategory, name);
}
/**
*
* @param refSchema
* @internal
*/
async addReference(refSchema) {
// TODO validation of reference schema. For now just adding
this.addReferenceSync(refSchema);
}
/** @internal */
addReferenceSync(refSchema) {
this.references.push(refSchema);
}
/** @internal */
setContext(context) {
this._context = context;
}
/**
* Sets the version of the SchemaKey identifying the schema.
* @param readVersion The read version of the schema. If undefined, the value from the existing SchemaKey will be used.
* @param writeVersion The write version of the schema. If undefined, the value from the existing SchemaKey will be used.
* @param minorVersion The minor version of the schema. If undefined, the value from the existing SchemaKey will be used.
* @internal
*/
setVersion(readVersion, writeVersion, minorVersion) {
if (!this._schemaKey)
throw new Exception_1.ECSchemaError(Exception_1.ECSchemaStatus.InvalidSchemaKey, `The schema '${this.name}' has an invalid SchemaKey.`);
const newVersion = new SchemaKey_1.ECVersion(readVersion ?? this._schemaKey.readVersion, writeVersion ?? this._schemaKey.writeVersion, minorVersion ?? this._schemaKey.minorVersion);
this._schemaKey = new SchemaKey_1.SchemaKey(this._schemaKey.name, newVersion);
}
/**
* Shortcut for calling getItem with EntityClass.
* @param name The local (unqualified) name of the item to return.
* @returns The requested EntityClass or undefined if not found.
*/
async getEntityClass(name) { return this.getItem(name, EntityClass_1.EntityClass); }
/**
* Shortcut for calling getItem with Mixin.
* @param name The local (unqualified) name of the item to return.
* @returns The requested Mixin or undefined if not found.
*/
async getMixin(name) { return this.getItem(name, Mixin_1.Mixin); }
/**
* Shortcut for calling getItem with StructClass.
* @param name The local (unqualified) name of the item to return.
* @returns The requested StructClass or undefined if not found.
*/
async getStructClass(name) { return this.getItem(name, Class_1.StructClass); }
/**
* Shortcut for calling getItem with CustomAttributeClass.
* @param name The local (unqualified) name of the item to return.
* @returns The requested CustomAttributeClass or undefined if not found.
*/
async getCustomAttributeClass(name) { return this.getItem(name, CustomAttributeClass_1.CustomAttributeClass); }
/**
* Shortcut for calling getItem with RelationshipClass.
* @param name The local (unqualified) name of the item to return.
* @returns The requested RelationshipClass or undefined if not found.
*/
async getRelationshipClass(name) { return this.getItem(name, RelationshipClass_1.RelationshipClass); }
/**
* Shortcut for calling getItem with Enumeration.
* @param name The local (unqualified) name of the item to return.
* @returns The requested Enumeration or undefined if not found.
*/
async getEnumeration(name) { return this.getItem(name, Enumeration_1.Enumeration); }
/**
* Shortcut for calling getItem with KindOfQuantity.
* @param name The local (unqualified) name of the item to return.
* @returns The requested KindOfQuantity or undefined if not found.
*/
async getKindOfQuantity(name) { return this.getItem(name, KindOfQuantity_1.KindOfQuantity); }
/**
* Shortcut for calling getItem with PropertyCategory.
* @param name The local (unqualified) name of the item to return.
* @returns The requested PropertyCategory or undefined if not found.
*/
async getPropertyCategory(name) { return this.getItem(name, PropertyCategory_1.PropertyCategory); }
/**
* Shortcut for calling getItem with Unit.
* @param name The local (unqualified) name of the item to return.
* @returns The requested Unit or undefined if not found.
*/
async getUnit(name) { return this.getItem(name, Unit_1.Unit); }
/**
* Shortcut for calling getItem with InvertedUnit.
* @param name The local (unqualified) name of the item to return.
* @returns The requested InvertedUnit or undefined if not found.
*/
async getInvertedUnit(name) { return this.getItem(name, InvertedUnit_1.InvertedUnit); }
/**
* Shortcut for calling getItem with Constant.
* @param name The local (unqualified) name of the item to return.
* @returns The requested Constant or undefined if not found.
*/
async getConstant(name) { return this.getItem(name, Constant_1.Constant); }
/**
* Shortcut for calling getItem with Phenomenon.
* @param name The local (unqualified) name of the item to return.
* @returns The requested Phenomenon or undefined if not found.
*/
async getPhenomenon(name) { return this.getItem(name, Phenomenon_1.Phenomenon); }
/**
* Shortcut for calling getItem with UnitSystem.
* @param name The local (unqualified) name of the item to return.
* @returns The requested UnitSystem or undefined if not found.
*/
async getUnitSystem(name) { return this.getItem(name, UnitSystem_1.UnitSystem); }
/**
* Shortcut for calling getItem with Format.
* @param name The local (unqualified) name of the item to return.
* @returns The requested Format or undefined if not found.
*/
async getFormat(name) { return this.getItem(name, Format_1.Format); }
async getItem(name, itemConstructor) {
// this method exists so we can rewire it later when we load partial schemas, for now it is identical to the sync version
if (itemConstructor === undefined)
return this.getItemSync(name);
return this.getItemSync(name, itemConstructor);
}
getItemSync(name, itemConstructor) {
const value = this._items.get(name.toUpperCase());
if (value === undefined || itemConstructor === undefined)
return value;
if ((0, ECObjects_1.isSupportedSchemaItemType)(value.schemaItemType, itemConstructor.schemaItemType))
return value;
return undefined;
}
async lookupItem(key, itemConstructor) {
let schemaName, itemName;
if (typeof (key) === "string") {
[schemaName, itemName] = SchemaItem_1.SchemaItem.parseFullName(key);
}
else {
itemName = key.name;
schemaName = key.schemaName;
}
if (!schemaName || schemaName.toUpperCase() === this.name.toUpperCase()) {
return itemConstructor
? this.getItem(itemName, itemConstructor)
: this.getItem(itemName);
}
const refSchema = await this.getReference(schemaName);
if (!refSchema)
return undefined;
return itemConstructor
? refSchema.getItem(itemName, itemConstructor)
: refSchema.getItem(itemName);
}
lookupItemSync(key, itemConstructor) {
let schemaName, itemName;
if (typeof (key) === "string") {
[schemaName, itemName] = SchemaItem_1.SchemaItem.parseFullName(key);
}
else {
itemName = key.name;
schemaName = key.schemaName;
}
if (!schemaName || schemaName.toUpperCase() === this.name.toUpperCase()) {
return itemConstructor
? this.getItemSync(itemName, itemConstructor)
: this.getItemSync(itemName);
}
const refSchema = this.getReferenceSync(schemaName);
if (!refSchema)
return undefined;
return itemConstructor
? refSchema.getItemSync(itemName, itemConstructor)
: refSchema.getItemSync(itemName);
}
*getItems(itemConstructor) {
if (!this._items)
return;
for (const item of this._items.values()) {
if (itemConstructor === undefined || (0, ECObjects_1.isSupportedSchemaItemType)(item.schemaItemType, itemConstructor.schemaItemType))
yield item;
}
}
/**
* Gets a referenced schema by name
* @param refSchemaName schema name to find
*/
async getReference(refSchemaName) {
if (this.references.length === 0)
return undefined;
return this.references.find((ref) => ref.name.toLowerCase() === refSchemaName.toLowerCase());
}
/**
* Gets a referenced schema by alias
* @param alias alias to find
*/
getReferenceNameByAlias(alias) {
if (this.references.length === 0)
return undefined;
const schema = this.references.find((ref) => ref.alias ? ref.alias.toLowerCase() === alias.toLowerCase() : false);
return schema ? schema.name : undefined;
}
/**
* Gets a referenced schema by name
* @param refSchemaName schema name to find
*/
getReferenceSync(refSchemaName) {
if (this.references.length === 0)
return undefined;
return this.references.find((ref) => ref.name.toLowerCase() === refSchemaName.toLowerCase());
}
/**
* Save this Schema's properties to an object for serializing to JSON.
*/
toJSON() {
if (this._isECSpecVersionUnsupported)
throw new Exception_1.ECSchemaError(Exception_1.ECSchemaStatus.NewerECSpecVersion, `The Schema '${this.name}' has an unsupported ECSpecVersion and cannot be serialized.`);
const schemaJson = {};
schemaJson.$schema = Constants_1.ECSchemaNamespaceUris.SCHEMAURL3_2_JSON; // $schema is required
schemaJson.name = this.name; // name is required
schemaJson.version = this.schemaKey.version.toString(true);
schemaJson.alias = this.alias; // alias is required
if (undefined !== this.label) // label is optional
schemaJson.label = this.label;
if (undefined !== this.description) // description is optional
schemaJson.description = this.description;
if (undefined !== this.references && this.references.length > 0) // references is optional
schemaJson.references = this.references.map(({ name, schemaKey }) => ({ name, version: schemaKey.version.toString() }));
const customAttributes = (0, CustomAttribute_1.serializeCustomAttributes)(this.customAttributes);
if (undefined !== customAttributes)
schemaJson.customAttributes = customAttributes;
if (this._items.size > 0) {
schemaJson.items = {};
this._items.forEach((schemaItem) => {
schemaJson.items[schemaItem.name] = schemaItem.toJSON(false, true);
});
}
return schemaJson;
}
/**
* Converts the schema to a DOM XML Document.
* @param schemaXml An empty DOM document to which the schema will be written
*/
async toXml(schemaXml) {
if (this._isECSpecVersionUnsupported)
throw new Exception_1.ECSchemaError(Exception_1.ECSchemaStatus.NewerECSpecVersion, `The Schema '${this.name}' has an unsupported ECSpecVersion and cannot be serialized.`);
const schemaMetadata = schemaXml.createElement("ECSchema");
schemaMetadata.setAttribute("xmlns", Constants_1.ECSchemaNamespaceUris.SCHEMAURL3_2_XML);
schemaMetadata.setAttribute("version", this.schemaKey.version.toString());
schemaMetadata.setAttribute("schemaName", this.name);
schemaMetadata.setAttribute("alias", this.alias ? this.alias : "");
if (undefined !== this.label)
schemaMetadata.setAttribute("displayLabel", this.label);
if (undefined !== this.description)
schemaMetadata.setAttribute("description", this.description);
// Map used for CA serialization
const refSchemaMap = new Map();
this.references.forEach(({ name, schemaKey, alias }) => {
const schemaRef = schemaXml.createElement("ECSchemaReference");
schemaRef.setAttribute("name", name);
schemaRef.setAttribute("version", schemaKey.version.toString());
schemaRef.setAttribute("alias", alias ? alias : "");
schemaMetadata.appendChild(schemaRef);
refSchemaMap.set(name, schemaKey.version.toString());
});
if (this._customAttributes) {
const parentElem = schemaXml.createElement("ECCustomAttributes");
for (const [name, attribute] of this._customAttributes) {
const caElem = await XmlSerializationUtils_1.XmlSerializationUtils.writeCustomAttribute(name, attribute, schemaXml, this);
parentElem.appendChild(caElem);
}
schemaMetadata.appendChild(parentElem);
}
for (const [, item] of this._items) {
const itemXml = await item.toXml(schemaXml);
schemaMetadata.appendChild(itemXml);
}
schemaXml.appendChild(schemaMetadata);
return schemaXml;
}
/**
* Loads the schema header (name, version alias, label and description) from the input SchemaProps
*/
fromJSONSync(schemaProps) {
if (undefined === this._schemaKey) {
const schemaName = schemaProps.name;
const version = SchemaKey_1.ECVersion.fromString(schemaProps.version);
this._schemaKey = new SchemaKey_1.SchemaKey(schemaName, version);
}
else {
if (schemaProps.name.toLowerCase() !== this.name.toLowerCase())
throw new Exception_1.ECSchemaError(Exception_1.ECSchemaStatus.InvalidECJson, `The Schema ${this.name} does not match the provided name, '${schemaProps.name}'.`);
if (this.schemaKey.version.compare(SchemaKey_1.ECVersion.fromString(schemaProps.version)))
throw new Exception_1.ECSchemaError(Exception_1.ECSchemaStatus.InvalidECJson, `The Schema ${this.name} has the version '${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)
throw new Exception_1.ECSchemaError(Exception_1.ECSchemaStatus.MissingSchemaUrl, `The Schema '${this.name}' has an unsupported namespace '${schemaProps.$schema}'.`);
// The schema props have not been parsed. Parse the ECXml version from the $schema attribute
let ecVersion;
if (schemaProps.ecSpecMajorVersion === undefined || schemaProps.ecSpecMinorVersion === undefined) {
ecVersion = ((schemaProps.$schema.search("ECXML") !== -1) ? XmlParser_1.XmlParser.parseXmlNamespace(schemaProps.$schema) : JsonParser_1.JsonParser.parseJSUri(schemaProps.$schema));
}
else {
ecVersion = { readVersion: schemaProps.ecSpecMajorVersion, writeVersion: schemaProps.ecSpecMinorVersion };
}
this._originalECSpecMajorVersion = ecVersion.readVersion;
this._originalECSpecMinorVersion = ecVersion.writeVersion;
if (ecVersion.readVersion !== 3 || (ecVersion.readVersion === 3 && ecVersion.writeVersion < 2))
throw new Exception_1.ECSchemaError(Exception_1.ECSchemaStatus.InvalidECVersion, `The Schema '${this.name}' has an unsupported ECVersion ${ecVersion.readVersion}.${ecVersion.writeVersion} and cannot be loaded.`);
if (ECName_1.ECName.validate(schemaProps.alias)) {
this._alias = schemaProps.alias;
}
else {
throw new Exception_1.ECSchemaError(Exception_1.ECSchemaStatus.InvalidECJson, `The Schema ${schemaProps.name} does not have the required 'alias' attribute.`);
}
if (undefined !== schemaProps.label)
this._label = schemaProps.label;
if (undefined !== schemaProps.description)
this._description = schemaProps.description;
}
/**
* Loads the schema header (name, version alias, label and description) from the input SchemaProps
*/
async fromJSON(schemaProps) {
this.fromJSONSync(schemaProps);
}
/**
* Completely loads the SchemaInfo from the input json and starts loading the entire schema. The complete schema can be retrieved from the
* schema context using the getCachedSchema method
*/
static async startLoadingFromJson(jsonObj, context) {
const schema = new Schema(context);
const reader = new Helper_1.SchemaReadHelper(JsonParser_1.JsonParser, context);
const rawSchema = typeof jsonObj === "string" ? JSON.parse(jsonObj) : jsonObj;
return reader.readSchemaInfo(schema, rawSchema);
}
static async fromJson(jsonObj, context) {
let schema = new Schema(context);
const reader = new Helper_1.SchemaReadHelper(JsonParser_1.JsonParser, context);
const rawSchema = typeof jsonObj === "string" ? JSON.parse(jsonObj) : jsonObj;
schema = await reader.readSchema(schema, rawSchema);
return schema;
}
/**
* Completely loads the Schema from the input json. The schema is cached in the schema context.
*/
static fromJsonSync(jsonObj, context) {
let schema = new Schema(context);
const reader = new Helper_1.SchemaReadHelper(JsonParser_1.JsonParser, context);
const rawSchema = typeof jsonObj === "string" ? JSON.parse(jsonObj) : jsonObj;
schema = reader.readSchemaSync(schema, rawSchema);
return schema;
}
/**
* @internal
*/
static isSchema(object) {
const schema = object;
return schema !== undefined && schema.schemaKey !== undefined && schema.context !== undefined;
}
/** @internal */
setDisplayLabel(displayLabel) {
this._label = displayLabel;
}
/** @internal */
setDescription(description) {
this._description = description;
}
/** @internal */
setAlias(alias) {
if (!ECName_1.ECName.validate(alias)) {
throw new Exception_1.ECSchemaError(Exception_1.ECSchemaStatus.InvalidECName, "The specified schema alias is invalid.");
}
this._alias = alias;
}
/** @internal */
setLoadingController(controller) {
this._loadingController = controller;
}
}
exports.Schema = Schema;
/**
* Hackish approach that works like a "friend class" so we can access protected members without making them public.
* We cannot put this into Helper.ts and make it non-export, because we are importing Helper.ts from this file, and the circular import
* would prevent this class from extending Schema.
* @internal
*/
class MutableSchema extends Schema {
}
exports.MutableSchema = MutableSchema;
//# sourceMappingURL=Schema.js.map