summaryrefslogtreecommitdiff
path: root/node_modules/@jet-app/app-store/tmp/src/common/content/attributes.js
blob: 1cae53a2baa224fc155e5493e0537bb4b02782f1 (plain)
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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
import { isNothing, isSome } from "@jet/environment/types/optional";
import * as derivedData from "../../foundation/json-parsing/derived-data";
import * as serverData from "../../foundation/json-parsing/server-data";
import * as mediaAttributes from "../../foundation/media/attributes";
import * as mediaPlatformAttributes from "../../foundation/media/platform-attributes";
import { variantAttributeForKey } from "../product-page/product-page-variants";
import * as contentDeviceFamily from "./device-family";
/**
 * 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 attributePlatform The specific platform attribute to get content for. Omit to infer from the data's structure.
 * @param defaultValue The object to return if the path search fails.
 * @returns The dictionary of data
 */
export function contentAttributeAsDictionary(objectGraph, data, attributePath, attributePlatform, defaultValue) {
    if (!attributePlatform) {
        attributePlatform = bestAttributePlatformFromData(objectGraph, data);
    }
    if (isNothing(attributePlatform)) {
        return null;
    }
    let value = mediaPlatformAttributes.platformAttributeAsDictionary(data, attributePlatform, attributePath);
    if (!value) {
        value = mediaAttributes.attributeAsDictionary(data, attributePath, defaultValue);
    }
    return value;
}
/**
 * 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.
 * @param attributePlatformOverride An override platform, from which to fetch the attribute.
 * @returns {any[]} The attribute value as an array.
 */
export function contentAttributeAsArrayOrEmpty(objectGraph, data, attributePath, attributePlatformOverride = undefined) {
    const attributePlatform = attributePlatformOverride !== null && attributePlatformOverride !== void 0 ? attributePlatformOverride : bestAttributePlatformFromData(objectGraph, data);
    if (isNothing(attributePlatform)) {
        return [];
    }
    let value = mediaPlatformAttributes.platformAttributeAsArrayOrEmpty(data, attributePlatform, attributePath);
    if (serverData.isNullOrEmpty(value)) {
        value = mediaAttributes.attributeAsArrayOrEmpty(data, attributePath);
    }
    return value;
}
/**
 * Retrieve the specified attribute from the data as an array.
 *
 * @param data The data from which to retrieve the attribute.
 * @param attributePath The path of the attribute.
 * @param attributePlatformOverride An override platform, from which to fetch the attribute.
 * @returns {any[]} The attribute value as an array.
 */
export function contentAttributeAsArray(objectGraph, data, attributePath, attributePlatformOverride = undefined) {
    const attributePlatform = attributePlatformOverride !== null && attributePlatformOverride !== void 0 ? attributePlatformOverride : bestAttributePlatformFromData(objectGraph, data);
    if (isNothing(attributePlatform)) {
        return null;
    }
    let value = mediaPlatformAttributes.platformAttributeAsArray(data, attributePlatform, attributePath);
    if (isNothing(value)) {
        value = mediaAttributes.attributeAsArray(data, attributePath);
    }
    return value;
}
/**
 * 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 attributePlatformOverride An override platform, from which to fetch the attribute.
 * @param policy The validation policy to use when resolving this value.
 * @returns {string} The attribute value as a string.
 */
export function contentAttributeAsString(objectGraph, data, attributePath, attributePlatformOverride = undefined, policy = "coercible") {
    let value;
    const attributePlatform = attributePlatformOverride !== null && attributePlatformOverride !== void 0 ? attributePlatformOverride : bestAttributePlatformFromData(objectGraph, data);
    if (isSome(attributePlatform)) {
        value = mediaPlatformAttributes.platformAttributeAsString(data, attributePlatform, attributePath, policy);
    }
    if (!value) {
        value = mediaAttributes.attributeAsString(data, attributePath, policy);
    }
    return value;
}
/**
 * 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 contentAttributeAsBoolean(objectGraph, data, attributePath, attributePlatform, policy = "coercible") {
    if (!attributePlatform) {
        attributePlatform = bestAttributePlatformFromData(objectGraph, data);
    }
    if (isNothing(attributePlatform)) {
        return null;
    }
    let value = mediaPlatformAttributes.platformAttributeAsBoolean(data, attributePlatform, attributePath, policy);
    if (serverData.isNull(value)) {
        value = mediaAttributes.attributeAsBoolean(data, attributePath, policy);
    }
    return value;
}
/**
 * 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.
 * @param attributePlatform The specific platform attribute to get content for. Omit to infer from the data's structure.
 * @returns {boolean} The attribute value as a boolean, coercing to `false` if the value is not present..
 */
export function contentAttributeAsBooleanOrFalse(objectGraph, data, attributePath, attributePlatform) {
    if (!attributePlatform) {
        attributePlatform = bestAttributePlatformFromData(objectGraph, data);
    }
    if (isNothing(attributePlatform)) {
        return false;
    }
    let value = mediaPlatformAttributes.platformAttributeAsBoolean(data, attributePlatform, attributePath);
    if (serverData.isNull(value)) {
        value = mediaAttributes.attributeAsBooleanOrFalse(data, attributePath);
    }
    return value;
}
/**
 * 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 contentAttributeAsNumber(objectGraph, data, attributePath, policy = "coercible") {
    const attributePlatform = bestAttributePlatformFromData(objectGraph, data);
    if (isNothing(attributePlatform)) {
        return null;
    }
    let value = mediaPlatformAttributes.platformAttributeAsNumber(data, attributePlatform, attributePath, policy);
    if (serverData.isNull(value)) {
        value = mediaAttributes.attributeAsNumber(data, attributePath);
    }
    return value;
}
/**
 * Computes the best attribute platform for a given piece of content
 *
 * @param {Data} data The media API data representing the content
 * @returns {AttributePlatform}
 */
export function bestAttributePlatformFromData(objectGraph, data, clientIdentifierOverride) {
    const baseCacheKey = "bestAttributePlatformFromData";
    const cacheKey = isSome(clientIdentifierOverride) ? `${baseCacheKey}.${clientIdentifierOverride}` : baseCacheKey;
    return derivedData.value(data, cacheKey, () => {
        const isIOSOnly = contentDeviceFamily.dataOnlyHasDeviceFamilies(objectGraph, data, ["iphone", "ipad", "ipod"], true);
        const isTvOnly = contentDeviceFamily.dataOnlyHasDeviceFamily(objectGraph, data, "tvos");
        const isMacOnly = contentDeviceFamily.dataOnlyHasDeviceFamily(objectGraph, data, "mac");
        const isWatchOnly = contentDeviceFamily.dataOnlyHasDeviceFamily(objectGraph, data, "watch");
        const isVisionOnly = contentDeviceFamily.dataOnlyHasDeviceFamily(objectGraph, data, "realityDevice");
        // 1. The data is for a single platform only.
        let dedicatedPlatform = null;
        if (isTvOnly) {
            dedicatedPlatform = "appletvos";
        }
        else if (isMacOnly) {
            dedicatedPlatform = "osx";
        }
        else if (isIOSOnly) {
            dedicatedPlatform = "ios";
        }
        else if (isWatchOnly) {
            dedicatedPlatform = "watch";
        }
        else if (isVisionOnly) {
            dedicatedPlatform = "xros";
        }
        if (!serverData.isNull(dedicatedPlatform)) {
            return dedicatedPlatform;
        }
        // 2. Loop through our preferred ordering of platforms and use the first one that has platformAttributes present.
        const alternatePlatforms = defaultAttributePlatformOrdering(objectGraph, clientIdentifierOverride);
        for (const candidatePlatform of alternatePlatforms) {
            if (mediaPlatformAttributes.hasPlatformAttribute(data, candidatePlatform)) {
                return candidatePlatform;
            }
        }
        // 3. Catch-All
        return defaultAttributePlatform(objectGraph);
    });
}
/**
 * Computes the best attribute platform for a given Media API Marketplace
 * response. Since Marketplace responses don't contain a top-level
 * `deviceFamilies` property, this employs an alternative method from
 * `bestAttributePlatformFromData()` to get the attribute platform.
 *
 * @param objectGraph The App Store object graph
 * @param data The Media API Marketplace response to search for an attribute platform.
 * @returns The most appropriate attribute platform available for the current client.
 */
export function bestAttributePlatformFromMarketplaceData(objectGraph, data) {
    // 1. Iterate through the client's preferred platform ordering until we
    // find the first one present in the response.
    const preferredAttributePlatforms = defaultAttributePlatformOrdering(objectGraph);
    for (const attributePlatform of preferredAttributePlatforms) {
        const versionsAttributes = contentAttributeAsDictionary(objectGraph, data, "versionAttributes", attributePlatform);
        if (serverData.isDefinedNonNullNonEmpty(versionsAttributes)) {
            return attributePlatform;
        }
    }
    // 2. Catch-All
    return defaultAttributePlatform(objectGraph);
}
/**
 * The default attribute platform for the current client
 */
export function defaultAttributePlatform(objectGraph) {
    var _a;
    if ((_a = objectGraph.activeIntent) === null || _a === void 0 ? void 0 : _a.attributePlatform) {
        return objectGraph.activeIntent.attributePlatform;
    }
    switch (objectGraph.client.deviceType) {
        case "phone":
        case "pad":
            return "ios";
        case "tv":
            return "appletvos";
        case "mac":
            return "osx";
        case "watch":
            return "watch";
        case "vision":
            return "xros";
        default:
            return null;
    }
}
/**
 * The preferred ordering to use given our default platform.
 */
function defaultAttributePlatformOrdering(objectGraph, clientIdentifierOverride) {
    const defaultPlatform = defaultAttributePlatform(objectGraph);
    if (defaultPlatform === null) {
        // If the `"web"` client is active and there is not an "active intent" to
        // inform a default platform, fall back to a hard-coded ordering
        if (objectGraph.client.isWeb) {
            return ["ios", "osx", "xros", "watch", "appletvos"];
        }
        else {
            return [];
        }
    }
    switch (defaultPlatform) {
        case "ios":
            if (clientIdentifierOverride === "VisionAppStore" /* ClientIdentifier.VisionAppStore */ ||
                clientIdentifierOverride === "com.apple.visionproapp" /* ClientIdentifier.VisionCompanion */) {
                return ["xros", "ios", "appletvos", "osx"];
            }
            else {
                return ["ios", "appletvos", "osx", "xros"];
            }
        case "osx":
            return ["osx", "ios", "appletvos", "xros"];
        case "appletvos":
            return ["appletvos", "ios", "osx", "xros"];
        case "watch":
            // Per Hiren Kotadia on 2019-2-26, watch platform attributes will always be under ios.
            // We're going to promote ios to the head of the search list to speed up Media API
            // response parsing. We'll keep watch as #2 in the list so that if this changes in
            // the future, it should mostly just work. -km
            return ["ios", "watch", "osx", "xros"];
        case "xros":
            return ["xros", "ios", "appletvos", "osx"];
        default:
            return [defaultPlatform];
    }
}
// region Variant Attributes
/**
 * Retrieve the attribute for a specific platform's variant attribute as a dictionary, from custom attributes or standard attributes.
 * @param data Data to get attribute for.
 * @param productVariantData Variant data to use when finding item.
 * @param attributeKey The key to fetch in platform attributes. May be converted to custom attribute key.
 * @param attributePlatform The platform to fetch attribute for. Defaults to current platform if unspecified.
 */
export function customAttributeAsDictionary(objectGraph, data, productVariantData, attributeKey, attributePlatform) {
    // Use `customAttributes.${customAttributeKey}` for platform if present
    const customAttributeKey = mediaAttributes.attributeKeyAsCustomAttributeKey(attributeKey);
    if (isNothing(customAttributeKey)) {
        return null;
    }
    const customAttributes = contentAttributeAsDictionary(objectGraph, data, "customAttributes", attributePlatform);
    const allowNondefaultTreatmentInNondefaultPage = mediaAttributes.attributeAllowsNonDefaultTreatmentInNonDefaultPage(customAttributeKey);
    const customAttribute = variantAttributeForKey(objectGraph, customAttributes, productVariantData, customAttributeKey, allowNondefaultTreatmentInNondefaultPage);
    if (serverData.isDefinedNonNullNonEmpty(customAttribute)) {
        return serverData.asDictionary(customAttribute);
    }
    // Otherwise, use `${attributeKey}` for platform.
    return contentAttributeAsDictionary(objectGraph, data, attributeKey, attributePlatform);
}
/**
 * Retrieve the attribute for a specific platform's variant attribute as a dictionary, from custom attributes or standard attributes.
 * @param data Data to get attribute for.
 * @param productVariantData Variant data to use when finding item.
 * @param attributeKey The key to fetch in platform attributes when custom attributes are not present.
 * @param attributePlatform The platform to fetch attribute for. Defaults to current platform if unspecified.
 */
export function customAttributeAsString(objectGraph, data, productVariantData, attributeKey, attributePlatform) {
    // Use `customAttributes.${customAttributeKey}` for platform if present
    const customAttributeKey = mediaAttributes.attributeKeyAsCustomAttributeKey(attributeKey);
    if (isNothing(customAttributeKey)) {
        return null;
    }
    const customAttributes = contentAttributeAsDictionary(objectGraph, data, "customAttributes", attributePlatform);
    const allowNondefaultTreatmentInNondefaultPage = mediaAttributes.attributeAllowsNonDefaultTreatmentInNonDefaultPage(customAttributeKey);
    const customAttribute = variantAttributeForKey(objectGraph, customAttributes, productVariantData, customAttributeKey, allowNondefaultTreatmentInNondefaultPage);
    if (serverData.isDefinedNonNullNonEmpty(customAttribute)) {
        return serverData.asString(customAttribute);
    }
    // Otherwise, use `${attributeKey}` for platform.
    return contentAttributeAsString(objectGraph, data, attributeKey);
}
// endregion
//# sourceMappingURL=attributes.js.map