From bce557cc2dc767628bed6aac87301a1be7c5431b Mon Sep 17 00:00:00 2001 From: rxliuli Date: Tue, 4 Nov 2025 05:03:50 +0800 Subject: init commit --- .../media-api/src/models/attributes.ts | 289 +++++++++++++++++++++ 1 file changed, 289 insertions(+) create mode 100644 node_modules/@apple-media-services/media-api/src/models/attributes.ts (limited to 'node_modules/@apple-media-services/media-api/src/models/attributes.ts') diff --git a/node_modules/@apple-media-services/media-api/src/models/attributes.ts b/node_modules/@apple-media-services/media-api/src/models/attributes.ts new file mode 100644 index 0000000..edb5fca --- /dev/null +++ b/node_modules/@apple-media-services/media-api/src/models/attributes.ts @@ -0,0 +1,289 @@ +import { Opt, isNothing } from "@jet/environment/types/optional"; +import * as serverData from "./server-data"; +import * as media from "./data-structure"; +import { JSONValue, MapLike, JSONData } from "./json-types"; +import * as errors from "./errors"; + +// region Generic Attribute retrieval + +// region Attribute retrieval + +/** + * Retrieve the specified attribute from the data, coercing it to a JSONData dictionary + * + * @param data The data from which to retrieve the attribute. + * @param attributePath The path of the attribute. + * @param defaultValue The object to return if the path search fails. + * @returns The dictionary of data + */ +export function attributeAsDictionary( + data: media.Data, + attributePath?: serverData.ObjectPath, + defaultValue?: MapLike, +): MapLike | null { + if (serverData.isNull(data)) { + return null; + } + return serverData.asDictionary(data.attributes, attributePath, defaultValue); +} + +/** + * Retrieve the specified attribute from the data, coercing it to an Interface + * + * @param data The data from which to retrieve the attribute. + * @param attributePath The path of the attribute. + * @param defaultValue The object to return if the path search fails. + * @returns The dictionary of data as an interface + */ +export function attributeAsInterface( + data: media.Data, + attributePath?: serverData.ObjectPath, + defaultValue?: JSONData, +): Interface | null { + return attributeAsDictionary(data, attributePath, defaultValue) as unknown as Interface; +} + +/** + * Retrieve the specified attribute from the data as an array, coercing to an empty array if the object is not an array. + * + * @param data The data from which to retrieve the attribute. + * @param attributePath The path of the attribute. + * @returns {any[]} The attribute value as an array. + */ +export function attributeAsArrayOrEmpty( + data: media.Data, + attributePath?: serverData.ObjectPath, +): T[] { + if (serverData.isNull(data)) { + return []; + } + return serverData.asArrayOrEmpty(data.attributes, attributePath); +} + +/** + * Retrieve the specified attribute from the data as a string. + * + * @param data The data from which to retrieve the attribute. + * @param attributePath The object path for the attribute. + * @param policy The validation policy to use when resolving this value. + * @returns {string} The attribute value as a string. + */ +export function attributeAsString( + data: media.Data, + attributePath?: serverData.ObjectPath, + policy: serverData.ValidationPolicy = "coercible", +): Opt { + if (serverData.isNull(data)) { + return null; + } + return serverData.asString(data.attributes, attributePath, policy); +} + +/** + * Retrieve the specified meta from the data as a string. + * + * @param data The data from which to retrieve the attribute. + * @param metaPath The object path for the meta. + * @param policy The validation policy to use when resolving this value. + * @returns {string} The meta value as a string. + */ +export function metaAsString( + data: media.Data, + metaPath?: serverData.ObjectPath, + policy: serverData.ValidationPolicy = "coercible", +): Opt { + if (serverData.isNull(data)) { + return null; + } + return serverData.asString(data.meta, metaPath, policy); +} + +/** + * Retrieve the specified attribute from the data as a date. + * + * @param data The data from which to retrieve the attribute. + * @param attributePath The object path for the attribute. + * @param policy The validation policy to use when resolving this value. + * @returns {Date} The attribute value as a date. + */ +export function attributeAsDate( + data: media.Data, + attributePath?: serverData.ObjectPath, + policy: serverData.ValidationPolicy = "coercible", +): Opt { + if (serverData.isNull(data)) { + return null; + } + const dateString = serverData.asString(data.attributes, attributePath, policy); + if (isNothing(dateString)) { + return null; + } + return new Date(dateString); +} + +/** + * Retrieve the specified attribute from the data as a boolean. + * + * @param data The data from which to retrieve the attribute. + * @param attributePath The path of the attribute. + * @param policy The validation policy to use when resolving this value. + * @returns {boolean} The attribute value as a boolean. + */ +export function attributeAsBoolean( + data: media.Data, + attributePath?: serverData.ObjectPath, + policy: serverData.ValidationPolicy = "coercible", +): boolean | null { + if (serverData.isNull(data)) { + return null; + } + return serverData.asBoolean(data.attributes, attributePath, policy); +} + +/** + * Retrieve the specified attribute from the data as a boolean, which will be `false` if the attribute does not exist. + * + * @param data The data from which to retrieve the attribute. + * @param attributePath The path of the attribute. + * @returns {boolean} The attribute value as a boolean, coercing to `false` if the value is not present.. + */ +export function attributeAsBooleanOrFalse(data: media.Data, attributePath?: serverData.ObjectPath): boolean { + if (serverData.isNull(data)) { + return false; + } + return serverData.asBooleanOrFalse(data.attributes, attributePath); +} + +/** + * Retrieve the specified attribute from the data as a number. + * + * @param data The data from which to retrieve the attribute. + * @param attributePath The path of the attribute. + * @param policy The validation policy to use when resolving this value. + * @returns {boolean} The attribute value as a number. + */ +export function attributeAsNumber( + data: media.Data, + attributePath?: serverData.ObjectPath, + policy: serverData.ValidationPolicy = "coercible", +): Opt { + if (serverData.isNull(data)) { + return null; + } + return serverData.asNumber(data.attributes, attributePath, policy); +} + +export function hasAttributes(data: media.Data): boolean { + return !serverData.isNull(serverData.asDictionary(data, "attributes")); +} + +/** + * The canonical way to detect if an item from Media API is hydrated or not. + * + * @param data The data from which to retrieve the attributes. + */ +export function isNotHydrated(data: media.Data): boolean { + return !hasAttributes(data); +} + +// region Custom Attributes + +/** + * Performs conversion for a custom variant of given attribute, if any are available. + * @param attribute Attribute to get custom attribute key for, if any. + */ +export function attributeKeyAsCustomAttributeKey(attribute: string): string | undefined { + return customAttributeMapping[attribute]; +} + +/** + * Whether or not given custom attributes key allows fallback to default page with AB testing treatment within a nondefault page. + * This is to allow AB testing to affect only icons within custom product pages. + */ +export function attributeAllowsNonDefaultTreatmentInNonDefaultPage(customAttribute: string): boolean { + return customAttribute === "customArtwork" || customAttribute === "customIconArtwork"; // Only the icon artwork. +} + +/** + * Defines mapping of attribute to custom attribute. + */ +const customAttributeMapping: { [key: string]: string } = { + artwork: "customArtwork", + iconArtwork: "customIconArtwork", + screenshotsByType: "customScreenshotsByType", + promotionalText: "customPromotionalText", + videoPreviewsByType: "customVideoPreviewsByType", + customScreenshotsByTypeForAd: "customScreenshotsByTypeForAd", + customVideoPreviewsByTypeForAd: "customVideoPreviewsByTypeForAd", +}; + +export function requiredAttributeAsString(data: media.Data, attributePath: serverData.ObjectPath): string { + const value = attributeAsString(data, attributePath); + if (isNothing(value)) { + throw new errors.MissingFieldError(data, concatObjectPaths("attributes", attributePath)); + } + return value; +} + +export function requiredAttributeAsDate(data: media.Data, attributePath: serverData.ObjectPath): Date { + const value = attributeAsDate(data, attributePath); + if (isNothing(value)) { + throw new errors.MissingFieldError(data, concatObjectPaths("attributes", attributePath)); + } + return value; +} + +export function requiredAttributeAsDictionary( + data: media.Data, + attributePath: serverData.ObjectPath, +): MapLike { + const value: MapLike | null = attributeAsDictionary(data, attributePath); + if (isNothing(value)) { + throw new errors.MissingFieldError(data, concatObjectPaths("attributes", attributePath)); + } + return value; +} + +export function requiredMeta(data: media.Data): MapLike { + const value = serverData.asDictionary(data, "meta"); + if (isNothing(value)) { + throw new errors.MissingFieldError(data, "meta"); + } + return value; +} + +export function requiredMetaAttributeAsString(data: media.Data, attributePath: serverData.ObjectPath): string { + const meta = requiredMeta(data); + const value = serverData.asString(meta, attributePath); + if (isNothing(value)) { + throw new errors.MissingFieldError(data, concatObjectPaths("meta", attributePath)); + } + return value; +} + +export function requiredMetaAttributeAsNumber(data: media.Data, attributePath: serverData.ObjectPath): number { + const meta = requiredMeta(data); + const value = serverData.asNumber(meta, attributePath); + if (isNothing(value)) { + throw new errors.MissingFieldError(data, concatObjectPaths("meta", attributePath)); + } + return value; +} + +export function concatObjectPaths(prefix: serverData.ObjectPath, suffix: serverData.ObjectPath): serverData.ObjectPath { + let finalPath: string[]; + if (Array.isArray(prefix)) { + finalPath = prefix; + } else { + finalPath = [prefix]; + } + + if (Array.isArray(suffix)) { + finalPath.push(...suffix); + } else { + finalPath.push(suffix); + } + return finalPath; +} + +// endregion -- cgit v1.2.3