Summary: ^ Reviewed By: jknoxville Differential Revision: D47548867 fbshipit-source-id: 462496da3d2668f9991e66381ca5ca0dd9c45ea9
278 lines
7.7 KiB
JavaScript
278 lines
7.7 KiB
JavaScript
/**
|
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*/
|
|
|
|
import $ from "autocomplete.js/zepto";
|
|
|
|
const utils = {
|
|
/*
|
|
* Move the content of an object key one level higher.
|
|
* eg.
|
|
* {
|
|
* name: 'My name',
|
|
* hierarchy: {
|
|
* lvl0: 'Foo',
|
|
* lvl1: 'Bar'
|
|
* }
|
|
* }
|
|
* Will be converted to
|
|
* {
|
|
* name: 'My name',
|
|
* lvl0: 'Foo',
|
|
* lvl1: 'Bar'
|
|
* }
|
|
* @param {Object} object Main object
|
|
* @param {String} property Main object key to move up
|
|
* @return {Object}
|
|
* @throws Error when key is not an attribute of Object or is not an object itself
|
|
*/
|
|
mergeKeyWithParent(object, property) {
|
|
if (object[property] === undefined) {
|
|
return object;
|
|
}
|
|
if (typeof object[property] !== 'object') {
|
|
return object;
|
|
}
|
|
const newObject = $.extend({}, object, object[property]);
|
|
delete newObject[property];
|
|
return newObject;
|
|
},
|
|
/*
|
|
* Group all objects of a collection by the value of the specified attribute
|
|
* If the attribute is a string, use the lowercase form.
|
|
*
|
|
* eg.
|
|
* groupBy([
|
|
* {name: 'Tim', category: 'dev'},
|
|
* {name: 'Vincent', category: 'dev'},
|
|
* {name: 'Ben', category: 'sales'},
|
|
* {name: 'Jeremy', category: 'sales'},
|
|
* {name: 'AlexS', category: 'dev'},
|
|
* {name: 'AlexK', category: 'sales'}
|
|
* ], 'category');
|
|
* =>
|
|
* {
|
|
* 'devs': [
|
|
* {name: 'Tim', category: 'dev'},
|
|
* {name: 'Vincent', category: 'dev'},
|
|
* {name: 'AlexS', category: 'dev'}
|
|
* ],
|
|
* 'sales': [
|
|
* {name: 'Ben', category: 'sales'},
|
|
* {name: 'Jeremy', category: 'sales'},
|
|
* {name: 'AlexK', category: 'sales'}
|
|
* ]
|
|
* }
|
|
* @param {array} collection Array of objects to group
|
|
* @param {String} property The attribute on which apply the grouping
|
|
* @return {array}
|
|
* @throws Error when one of the element does not have the specified property
|
|
*/
|
|
groupBy(collection, property) {
|
|
const newCollection = {};
|
|
$.each(collection, (index, item) => {
|
|
if (item[property] === undefined) {
|
|
throw new Error(`[groupBy]: Object has no key ${property}`);
|
|
}
|
|
let key = item[property];
|
|
if (typeof key === 'string') {
|
|
key = key.toLowerCase();
|
|
}
|
|
// fix #171 the given data type of docsearch hits might be conflict with the properties of the native Object,
|
|
// such as the constructor, so we need to do this check.
|
|
if (!Object.prototype.hasOwnProperty.call(newCollection, key)) {
|
|
newCollection[key] = [];
|
|
}
|
|
newCollection[key].push(item);
|
|
});
|
|
return newCollection;
|
|
},
|
|
/*
|
|
* Return an array of all the values of the specified object
|
|
* eg.
|
|
* values({
|
|
* foo: 42,
|
|
* bar: true,
|
|
* baz: 'yep'
|
|
* })
|
|
* =>
|
|
* [42, true, yep]
|
|
* @param {object} object Object to extract values from
|
|
* @return {array}
|
|
*/
|
|
values(object) {
|
|
return Object.keys(object).map(key => object[key]);
|
|
},
|
|
/*
|
|
* Flattens an array
|
|
* eg.
|
|
* flatten([1, 2, [3, 4], [5, 6]])
|
|
* =>
|
|
* [1, 2, 3, 4, 5, 6]
|
|
* @param {array} array Array to flatten
|
|
* @return {array}
|
|
*/
|
|
flatten(array) {
|
|
const results = [];
|
|
array.forEach(value => {
|
|
if (!Array.isArray(value)) {
|
|
results.push(value);
|
|
return;
|
|
}
|
|
value.forEach(subvalue => {
|
|
results.push(subvalue);
|
|
});
|
|
});
|
|
return results;
|
|
},
|
|
/*
|
|
* Flatten all values of an object into an array, marking each first element of
|
|
* each group with a specific flag
|
|
* eg.
|
|
* flattenAndFlagFirst({
|
|
* 'devs': [
|
|
* {name: 'Tim', category: 'dev'},
|
|
* {name: 'Vincent', category: 'dev'},
|
|
* {name: 'AlexS', category: 'dev'}
|
|
* ],
|
|
* 'sales': [
|
|
* {name: 'Ben', category: 'sales'},
|
|
* {name: 'Jeremy', category: 'sales'},
|
|
* {name: 'AlexK', category: 'sales'}
|
|
* ]
|
|
* , 'isTop');
|
|
* =>
|
|
* [
|
|
* {name: 'Tim', category: 'dev', isTop: true},
|
|
* {name: 'Vincent', category: 'dev', isTop: false},
|
|
* {name: 'AlexS', category: 'dev', isTop: false},
|
|
* {name: 'Ben', category: 'sales', isTop: true},
|
|
* {name: 'Jeremy', category: 'sales', isTop: false},
|
|
* {name: 'AlexK', category: 'sales', isTop: false}
|
|
* ]
|
|
* @param {object} object Object to flatten
|
|
* @param {string} flag Flag to set to true on first element of each group
|
|
* @return {array}
|
|
*/
|
|
flattenAndFlagFirst(object, flag) {
|
|
const values = this.values(object).map(collection =>
|
|
collection.map((item, index) => {
|
|
// eslint-disable-next-line no-param-reassign
|
|
item[flag] = index === 0;
|
|
return item;
|
|
})
|
|
);
|
|
return this.flatten(values);
|
|
},
|
|
/*
|
|
* Removes all empty strings, null, false and undefined elements array
|
|
* eg.
|
|
* compact([42, false, null, undefined, '', [], 'foo']);
|
|
* =>
|
|
* [42, [], 'foo']
|
|
* @param {array} array Array to compact
|
|
* @return {array}
|
|
*/
|
|
compact(array) {
|
|
const results = [];
|
|
array.forEach(value => {
|
|
if (!value) {
|
|
return;
|
|
}
|
|
results.push(value);
|
|
});
|
|
return results;
|
|
},
|
|
/*
|
|
* Returns the highlighted value of the specified key in the specified object.
|
|
* If no highlighted value is available, will return the key value directly
|
|
* eg.
|
|
* getHighlightedValue({
|
|
* _highlightResult: {
|
|
* text: {
|
|
* value: '<mark>foo</mark>'
|
|
* }
|
|
* },
|
|
* text: 'foo'
|
|
* }, 'text');
|
|
* =>
|
|
* '<mark>foo</mark>'
|
|
* @param {object} object Hit object returned by the Algolia API
|
|
* @param {string} property Object key to look for
|
|
* @return {string}
|
|
**/
|
|
getHighlightedValue(object, property) {
|
|
if (
|
|
object._highlightResult &&
|
|
object._highlightResult.hierarchy_camel &&
|
|
object._highlightResult.hierarchy_camel[property] &&
|
|
object._highlightResult.hierarchy_camel[property].matchLevel &&
|
|
object._highlightResult.hierarchy_camel[property].matchLevel !== 'none' &&
|
|
object._highlightResult.hierarchy_camel[property].value
|
|
) {
|
|
return object._highlightResult.hierarchy_camel[property].value;
|
|
}
|
|
if (
|
|
object._highlightResult &&
|
|
object._highlightResult &&
|
|
object._highlightResult[property] &&
|
|
object._highlightResult[property].value
|
|
) {
|
|
return object._highlightResult[property].value;
|
|
}
|
|
return object[property];
|
|
},
|
|
/*
|
|
* Returns the snippeted value of the specified key in the specified object.
|
|
* If no highlighted value is available, will return the key value directly.
|
|
* Will add starting and ending ellipsis (…) if we detect that a sentence is
|
|
* incomplete
|
|
* eg.
|
|
* getSnippetedValue({
|
|
* _snippetResult: {
|
|
* text: {
|
|
* value: '<mark>This is an unfinished sentence</mark>'
|
|
* }
|
|
* },
|
|
* text: 'This is an unfinished sentence'
|
|
* }, 'text');
|
|
* =>
|
|
* '<mark>This is an unfinished sentence</mark>…'
|
|
* @param {object} object Hit object returned by the Algolia API
|
|
* @param {string} property Object key to look for
|
|
* @return {string}
|
|
**/
|
|
getSnippetedValue(object, property) {
|
|
if (
|
|
!object._snippetResult ||
|
|
!object._snippetResult[property] ||
|
|
!object._snippetResult[property].value
|
|
) {
|
|
return object[property];
|
|
}
|
|
let snippet = object._snippetResult[property].value;
|
|
|
|
if (snippet[0] !== snippet[0].toUpperCase()) {
|
|
snippet = `…${snippet}`;
|
|
}
|
|
if (['.', '!', '?'].indexOf(snippet[snippet.length - 1]) === -1) {
|
|
snippet = `${snippet}…`;
|
|
}
|
|
return snippet;
|
|
},
|
|
/*
|
|
* Deep clone an object.
|
|
* Note: This will not clone functions and dates
|
|
* @param {object} object Object to clone
|
|
* @return {object}
|
|
*/
|
|
deepClone(object) {
|
|
return JSON.parse(JSON.stringify(object));
|
|
},
|
|
};
|
|
|
|
export default utils;
|