/
SchemaItem.ts
166 lines (139 loc) · 7.23 KB
/
SchemaItem.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
/*---------------------------------------------------------------------------------------------
* 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
*/
import { SchemaItemProps } from "../Deserialization/JsonProps";
import { SchemaItemType, schemaItemTypeToXmlString } from "../ECObjects";
import { ECObjectsError, ECObjectsStatus } from "../Exception";
import { ECVersion, SchemaItemKey } from "../SchemaKey";
import { Schema } from "./Schema";
const SCHEMAURL3_2 = "https://dev.bentley.com/json_schemas/ec/32/schemaitem";
/**
* An abstract class that supplies all of the common parts of a SchemaItem.
* @beta
*/
export abstract class SchemaItem {
public readonly schemaItemType!: SchemaItemType; // allow the derived classes to define their own schemaItemType
public readonly schema: Schema;
protected _key: SchemaItemKey;
protected _description?: string;
protected _label?: string;
constructor(schema: Schema, name: string) {
this._key = new SchemaItemKey(name, schema.schemaKey);
this.schema = schema;
}
public get name() { return this.key.name; }
public get fullName() { return this.key.schemaKey ? `${this.key.schemaName}.${this.name}` : this.name; }
public get key() { return this._key; }
public get label() { return this._label; }
public get description() { return this._description; }
// Proposal: Create protected setter methods for description and label? For UnitSystems as an example, where using createFromProps isn't that necessary and can just use basic create().
/**
* Save this SchemaItem's properties to an object for serializing to JSON.
* @param standalone Serialization includes only this object (as opposed to the full schema).
* @param includeSchemaVersion Include the Schema's version information in the serialized object.
*/
public toJSON(standalone: boolean = false, includeSchemaVersion: boolean = false) {
const itemJson: { [value: string]: any } = {};
if (standalone) {
itemJson.$schema = SCHEMAURL3_2; // $schema is required
itemJson.schema = this.schema.name;
itemJson.name = this.name; // name is required
if (includeSchemaVersion) // check flag to see if we should output version
itemJson.schemaVersion = this.key.schemaKey.version.toString();
}
itemJson.schemaItemType = this.schemaItemType;
if (undefined !== this.label)
itemJson.label = this.label;
if (undefined !== this.description)
itemJson.description = this.description;
return itemJson as SchemaItemProps;
}
/** @internal */
public async toXml(schemaXml: Document): Promise<Element> {
const itemType = schemaItemTypeToXmlString(this.schemaItemType);
const itemElement = schemaXml.createElement(itemType);
itemElement.setAttribute("typeName", this.name);
if (undefined !== this.label)
itemElement.setAttribute("displayLabel", this.label);
if (undefined !== this.description)
itemElement.setAttribute("description", this.description);
// When all schema items support custom attributes they should be added here rather than in ECClass
return itemElement;
}
public fromJSONSync(schemaItemProps: SchemaItemProps) {
if (undefined !== schemaItemProps.label)
this._label = schemaItemProps.label;
this._description = schemaItemProps.description;
if (undefined !== schemaItemProps.schema) {
if (schemaItemProps.schema.toLowerCase() !== this.schema.name.toLowerCase())
throw new ECObjectsError(ECObjectsStatus.InvalidECJson, `Unable to deserialize the SchemaItem '${this.fullName}' with a different schema name, ${schemaItemProps.schema}, than the current Schema of this SchemaItem, ${this.schema.fullName}.`);
}
if (undefined !== schemaItemProps.schemaVersion) {
if (this.key.schemaKey.version.compare(ECVersion.fromString(schemaItemProps.schemaVersion)))
throw new ECObjectsError(ECObjectsStatus.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}.`);
}
}
public async fromJSON(schemaItemProps: SchemaItemProps) {
if (undefined !== schemaItemProps.label)
this._label = schemaItemProps.label;
this._description = schemaItemProps.description;
if (undefined !== schemaItemProps.schema) {
if (schemaItemProps.schema.toLowerCase() !== this.schema.name.toLowerCase())
throw new ECObjectsError(ECObjectsStatus.InvalidECJson, `Unable to deserialize the SchemaItem ${this.fullName}' with a different schema name, ${schemaItemProps.schema}, than the current Schema of this SchemaItem, ${this.schema.fullName}`);
}
if (undefined !== schemaItemProps.schemaVersion) {
if (this.key.schemaKey.version.compare(ECVersion.fromString(schemaItemProps.schemaVersion)))
throw new ECObjectsError(ECObjectsStatus.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}.`);
}
}
/**
* Parses the given full name, {schemaName}.{schemaItemName} or {schemaName}:{schemaItemName}, into two separate strings.
* @note The schema name can be a schema alias.
* @param fullName The full name to be parsed.
* @returns A tuple of the parsed Schema name and Schema Item name. If the full name does not contain a '.' or ':', the second string in the tuple will returned the exact string pass in.
*/
public static parseFullName(fullName: string): [string, string] {
const matches = /^([a-zA-Z_]+[a-zA-Z0-9_]*(\.\d+\.\d+\.\d+)?)[.:]([a-zA-Z_]+[a-zA-Z0-9_]*)$/.exec(fullName);
// The first match will be the full string match, the second three will be the three groups
if (matches === null || matches.length !== 4)
return ["", fullName];
return [matches[1], matches[3]];
}
/**
* Indicates if the two SchemaItem objects are equal by comparing their respective [[key]] properties.
* @param thisSchemaItem The first SchemaItem.
* @param thatSchemaItemOrKey The second SchemaItem or SchemaItemKey.
*/
public static equalByKey(thisSchemaItem: SchemaItem, thatSchemaItemOrKey?: SchemaItem | SchemaItemKey): boolean {
if (!thatSchemaItemOrKey)
return true;
const key = SchemaItem.isSchemaItem(thatSchemaItemOrKey) ? thatSchemaItemOrKey.key : thatSchemaItemOrKey;
return thisSchemaItem.key.matches(key);
}
/**
* @internal
*/
public static isSchemaItem(object: any): object is SchemaItem {
const schemaItem = object as SchemaItem;
return schemaItem !== undefined && schemaItem.key !== undefined && schemaItem.schema !== undefined
&& schemaItem.schemaItemType !== undefined;
}
/**
* @alpha
* Used for schema editing.
*/
protected setDisplayLabel(displayLabel: string) {
this._label = displayLabel;
}
/**
* @alpha
* Used for schema editing.
*/
protected setDescription(description: string) {
this._description = description;
}
}