function MetadataClassProperty(options) {
  options = options ?? Frozen.EMPTY_OBJECT;
  const id = options.id;
  const type = options.type;

  //>>includeStart('debug', pragmas.debug);
  Check.typeOf.string("options.id", id);
  Check.typeOf.string("options.type", type);
  //>>includeEnd('debug');

  const componentType = options.componentType;
  const enumType = options.enumType;

  const normalized =
    defined(componentType) &&
    MetadataComponentType.isIntegerType(componentType) &&
    (options.normalized ?? false);

  // Basic information about this property
  this._id = id;
  this._name = options.name;
  this._description = options.description;
  this._semantic = options.semantic;

  // Only for unit testing purposes, not documented in the API
  this._isLegacyExtension = options.isLegacyExtension;

  // Details about basic types
  this._type = type;
  this._componentType = componentType;
  this._enumType = enumType;
  this._valueType = defined(enumType) ? enumType.valueType : componentType;

  // Details about arrays
  this._isArray = options.isArray ?? false;
  this._isVariableLengthArray = options.isVariableLengthArray ?? false;
  this._arrayLength = options.arrayLength;

  // min and max allowed values
  this._min = clone(options.min, true);
  this._max = clone(options.max, true);

  // properties that adjust the range of metadata values
  this._normalized = normalized;

  let offset = clone(options.offset, true);
  let scale = clone(options.scale, true);
  const hasValueTransform = defined(offset) || defined(scale);

  const enableNestedArrays = true;
  if (!defined(offset)) {
    offset = this.expandConstant(0, enableNestedArrays);
  }

  if (!defined(scale)) {
    scale = this.expandConstant(1, enableNestedArrays);
  }

  this._offset = offset;
  this._scale = scale;
  this._hasValueTransform = hasValueTransform;

  // sentinel value for missing data, and a default value to use
  // in its place if needed.
  this._noData = clone(options.noData, true);
  // For vector and array types, this is stored as an array of values.
  this._default = clone(options.default, true);

  this._required = options.required ?? true;

  // extras and extensions
  this._extras = clone(options.extras, true);
  this._extensions = clone(options.extensions, true);
}
A metadata property, as part of a {@link MetadataClass}.
<p>
See the {@link https://github.com/CesiumGS/3d-tiles/tree/main/specification/Metadata|3D Metadata Specification} for 3D Tiles
</p>

@param {object} options Object with the following properties:
@param {string} options.id The ID of the property.
@param {MetadataType} options.type The type of the property such as SCALAR, VEC2, VEC3.
@param {MetadataComponentType} [options.componentType] The component type of the property. This includes integer (e.g. INT8 or UINT16), and floating point (FLOAT32 and FLOAT64) values.
@param {MetadataEnum} [options.enumType] The enum type of the property. Only defined when type is ENUM.
@param {boolean} [options.isArray=false] True if a property is an array (either fixed length or variable length), false otherwise.
@param {boolean} [options.isVariableLengthArray=false] True if a property is a variable length array, false otherwise.
@param {number} [options.arrayLength] The number of array elements. Only defined for fixed length arrays.
@param {boolean} [options.normalized=false] Whether the property is normalized.
@param {number|number[]|number[][]} [options.min] A number or an array of numbers storing the minimum allowable value of this property. Only defined when type is a numeric type.
@param {number|number[]|number[][]} [options.max] A number or an array of numbers storing the maximum allowable value of this property. Only defined when type is a numeric type.
@param {number|number[]|number[][]} [options.offset] The offset to be added to property values as part of the value transform.
@param {number|number[]|number[][]} [options.scale] The scale to be multiplied to property values as part of the value transform.
@param {boolean|number|string|Array} [options.noData] The no-data sentinel value that represents null values.
@param {boolean|number|string|Array} [options.default] A default value to use when an entity's property value is not defined.
@param {boolean} [options.required=false] Whether the property is required.
@param {string} [options.name] The name of the property.
@param {string} [options.description] The description of the property.
@param {string} [options.semantic] An identifier that describes how this property should be interpreted.
@param {*} [options.extras] Extra user-defined properties.
@param {object} [options.extensions] An object containing extensions.

@alias MetadataClassProperty
@constructor
@experimental This feature is using part of the 3D Tiles spec that is not final and is subject to change without Cesium's standard deprecation policy.