Get rid of Lodash mixins (#17737)

* Get rid of _.class mixin

* Get rid of _.flattenWith

* Get rid of _.isNumeric

* Get rid of _.toggleInOut

* Get rid of _.onceWithCb

* Get rid of _.callEach

* Get rid of _.organizeBy, _.pushAll, _.move

* Delete Lodash webpackShim
This commit is contained in:
Kim Joar Bekkelund 2018-04-18 07:24:06 +02:00 committed by GitHub
parent af300c9963
commit 5628ac3052
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
51 changed files with 463 additions and 598 deletions

View file

@ -1,14 +1,15 @@
import angular from 'angular';
import _ from 'lodash';
import { uiModules } from 'ui/modules';
import { createDashboardEditUrl } from 'plugins/kibana/dashboard/dashboard_constants';
import { createLegacyClass } from 'ui/utils/legacy_class';
const module = uiModules.get('app/dashboard');
// Used only by the savedDashboards service, usually no reason to change this
module.factory('SavedDashboard', function (courier, config) {
// SavedDashboard constructor. Usually you'd interact with an instance of this.
// ID is option, without it one will be generated on save.
_.class(SavedDashboard).inherits(courier.SavedObject);
createLegacyClass(SavedDashboard).inherits(courier.SavedObject);
function SavedDashboard(id) {
// Gives our SavedDashboard the properties of a SavedObject
SavedDashboard.Super.call(this, {

View file

@ -1,7 +1,6 @@
import _ from 'lodash';
import 'ui/notify';
import { uiModules } from 'ui/modules';
import { createLegacyClass } from 'ui/utils/legacy_class';
const module = uiModules.get('discover/saved_searches', [
'kibana/notify',
@ -9,7 +8,7 @@ const module = uiModules.get('discover/saved_searches', [
]);
module.factory('SavedSearch', function (courier) {
_.class(SavedSearch).inherits(courier.SavedObject);
createLegacyClass(SavedSearch).inherits(courier.SavedObject);
function SavedSearch(id) {
courier.SavedObject.call(this, {
type: SavedSearch.type,

View file

@ -9,6 +9,7 @@ import { fatalError, toastNotifications } from 'ui/notify';
import 'ui/accessibility/kbn_ui_ace_keyboard_mode';
import { castEsToKbnFieldTypeName } from '../../../../../../utils';
import { SavedObjectsClientProvider } from 'ui/saved_objects';
import { isNumeric } from 'ui/utils/numeric';
const location = 'SavedObject view';
@ -55,7 +56,7 @@ uiModules.get('apps/management')
} catch (err) {
field.value = field.value;
}
} else if (_.isNumeric(field.value)) {
} else if (isNumeric(field.value)) {
field.type = 'number';
} else if (Array.isArray(field.value)) {
field.type = 'array';

View file

@ -6,18 +6,18 @@
* NOTE: It's a type of SavedObject, but specific to visualizations.
*/
import _ from 'lodash';
import { VisProvider } from 'ui/vis';
import { uiModules } from 'ui/modules';
import { updateOldState } from 'ui/vis/vis_update_state';
import { VisualizeConstants } from 'plugins/kibana/visualize/visualize_constants';
import { createLegacyClass } from 'ui/utils/legacy_class';
uiModules
.get('app/visualize')
.factory('SavedVis', function (config, $injector, courier, Promise, savedSearches, Private) {
const Vis = Private(VisProvider);
_.class(SavedVis).inherits(courier.SavedObject);
createLegacyClass(SavedVis).inherits(courier.SavedObject);
function SavedVis(opts) {
const self = this;
opts = opts || {};

View file

@ -1,4 +1,5 @@
import _ from 'lodash';
import { move } from 'ui/utils/collection';
require('angular-sortable-view');
require('plugins/timelion/directives/chart/chart');
@ -27,7 +28,7 @@ app.directive('timelionCells', function () {
$scope.dropCell = function (item, partFrom, partTo, indexFrom, indexTo) {
$scope.onSelect(indexTo);
_.move($scope.sheet, indexFrom, indexTo);
move($scope.sheet, indexFrom, indexTo);
};
}

View file

@ -1,5 +1,5 @@
import { uiModules } from 'ui/modules';
import _ from 'lodash';
import { createLegacyClass } from 'ui/utils/legacy_class';
const module = uiModules.get('app/timelion');
// Used only by the savedSheets service, usually no reason to change this
@ -7,7 +7,7 @@ module.factory('SavedSheet', function (courier, config) {
// SavedSheet constructor. Usually you'd interact with an instance of this.
// ID is option, without it one will be generated on save.
_.class(SavedSheet).inherits(courier.SavedObject);
createLegacyClass(SavedSheet).inherits(courier.SavedObject);
function SavedSheet(id) {
// Gives our SavedSheet the properties of a SavedObject
courier.SavedObject.call(this, {

View file

@ -17,10 +17,7 @@ export function FieldFormat(params) {
}
FieldFormat.from = function (converter) {
_.class(FieldFormatFromConverter).inherits(FieldFormat);
function FieldFormatFromConverter(params) {
FieldFormatFromConverter.Super.call(this, params);
}
class FieldFormatFromConverter extends FieldFormat {}
FieldFormatFromConverter.prototype._convert = converter;
return FieldFormatFromConverter;
};

View file

@ -3,8 +3,9 @@ import AggConfigResult from 'ui/vis/agg_config_result';
import { TabifyTable } from 'ui/agg_response/tabify/_table';
import { TabifyTableGroup } from 'ui/agg_response/tabify/_table_group';
import { tabifyGetColumns } from 'ui/agg_response/tabify/_get_columns';
import { createLegacyClass } from '../../utils/legacy_class';
_.class(SplitAcr).inherits(AggConfigResult);
createLegacyClass(SplitAcr).inherits(AggConfigResult);
function SplitAcr(agg, parent, key) {
SplitAcr.Super.call(this, agg, parent, key, key);
}

View file

@ -3,12 +3,13 @@ import sinon from 'sinon';
import { BaseParamType } from '../../param_types/base';
import { FieldParamType } from '../../param_types/field';
import { OptionedParamType } from '../../param_types/optioned';
import { createLegacyClass } from '../../../utils/legacy_class';
function ParamClassStub(parent, body) {
const stub = sinon.spy(body || function () {
stub.Super && stub.Super.call(this);
});
if (parent) _.class(stub).inherits(parent);
if (parent) createLegacyClass(stub).inherits(parent);
return stub;
}

View file

@ -1,5 +1,4 @@
import 'ui/filters/label';
import _ from 'lodash';
import { IndexedArray } from 'ui/indexed_array';
import { FieldParamType } from './param_types/field';
import { OptionedParamType } from './param_types/optioned';
@ -7,6 +6,7 @@ import { RegexParamType } from './param_types/regex';
import { StringParamType } from './param_types/string';
import { JsonParamType } from './param_types/json';
import { BaseParamType } from './param_types/base';
import { createLegacyClass } from '../utils/legacy_class';
const paramTypeMap = {
field: FieldParamType,
@ -30,7 +30,7 @@ const paramTypeMap = {
* @extends IndexedArray
* @param {object[]} params - array of params that get new-ed up as AggParam objects as descibed above
*/
_.class(AggParams).inherits(IndexedArray);
createLegacyClass(AggParams).inherits(IndexedArray);
function AggParams(params) {
AggParams.Super.call(this, {
index: ['name'],

View file

@ -1,10 +1,11 @@
import _ from 'lodash';
import { AggTypesAggTypeProvider } from 'ui/agg_types/agg_type';
import { createLegacyClass } from '../../utils/legacy_class';
export function AggTypesBucketsBucketAggTypeProvider(Private) {
const AggType = Private(AggTypesAggTypeProvider);
_.class(BucketAggType).inherits(AggType);
createLegacyClass(BucketAggType).inherits(AggType);
function BucketAggType(config) {
BucketAggType.Super.call(this, config);

View file

@ -1,12 +1,13 @@
import _ from 'lodash';
import { AggTypesAggTypeProvider } from 'ui/agg_types/agg_type';
import { fieldFormats } from 'ui/registry/field_formats';
import { createLegacyClass } from '../../utils/legacy_class';
export function AggTypesMetricsMetricAggTypeProvider(Private) {
const AggType = Private(AggTypesAggTypeProvider);
_.class(MetricAggType).inherits(AggType);
createLegacyClass(MetricAggType).inherits(AggType);
function MetricAggType(config) {
MetricAggType.Super.call(this, config);

View file

@ -6,11 +6,11 @@ import 'ui/filters/field_type';
import { IndexedArray } from 'ui/indexed_array';
import { Notifier } from 'ui/notify';
import { propFilter } from 'ui/filters/_prop_filter';
import { createLegacyClass } from '../../utils/legacy_class';
const notifier = new Notifier();
_.class(FieldParamType).inherits(BaseParamType);
createLegacyClass(FieldParamType).inherits(BaseParamType);
function FieldParamType(config) {
FieldParamType.Super.call(this, config);
}

View file

@ -1,9 +1,10 @@
import _ from 'lodash';
import editorHtml from '../controls/raw_json.html';
import { BaseParamType } from './base';
import { createLegacyClass } from '../../utils/legacy_class';
_.class(JsonParamType).inherits(BaseParamType);
createLegacyClass(JsonParamType).inherits(BaseParamType);
function JsonParamType(config) {
// force name override
config = _.defaults(config, { name: 'json' });

View file

@ -1,8 +1,8 @@
import _ from 'lodash';
import { IndexedArray } from 'ui/indexed_array';
import { BaseParamType } from './base';
import { createLegacyClass } from '../../utils/legacy_class';
_.class(OptionedParamType).inherits(BaseParamType);
createLegacyClass(OptionedParamType).inherits(BaseParamType);
function OptionedParamType(config) {
OptionedParamType.Super.call(this, config);

View file

@ -1,8 +1,9 @@
import _ from 'lodash';
import editorHtml from '../controls/regular_expression.html';
import { BaseParamType } from './base';
import { createLegacyClass } from '../../utils/legacy_class';
_.class(RegexParamType).inherits(BaseParamType);
createLegacyClass(RegexParamType).inherits(BaseParamType);
function RegexParamType(config) {
_.defaults(config, { pattern: '' });
RegexParamType.Super.call(this, config);

View file

@ -1,8 +1,8 @@
import _ from 'lodash';
import editorHtml from '../controls/string.html';
import { BaseParamType } from './base';
import { createLegacyClass } from '../../utils/legacy_class';
_.class(StringParamType).inherits(BaseParamType);
createLegacyClass(StringParamType).inherits(BaseParamType);
function StringParamType(config) {
StringParamType.Super.call(this, config);
}

View file

@ -2,6 +2,7 @@ import _ from 'lodash';
import { Notifier } from 'ui/notify';
import { SearchRequestProvider } from './search_request';
import { SegmentedHandleProvider } from './segmented_handle';
import { pushAll } from '../../../utils/collection';
export function SegmentedRequestProvider(Private, timefilter, config) {
const SearchRequest = Private(SearchRequestProvider);
@ -226,7 +227,7 @@ export function SegmentedRequestProvider(Private, timefilter, config) {
const desiredSize = this._desiredSize;
const sortFn = this._sortFn;
_.pushAll(hits, mergedHits);
pushAll(hits, mergedHits);
if (sortFn) {
notify.event('resort rows', function () {

View file

@ -4,6 +4,8 @@ import AggConfigResult from 'ui/vis/agg_config_result';
import { FilterBarClickHandlerProvider } from 'ui/filter_bar/filter_bar_click_handler';
import { uiModules } from 'ui/modules';
import tableCellFilterHtml from './partials/table_cell_filter.html';
import { isNumeric } from '../utils/numeric';
const module = uiModules.get('kibana');
module.directive('kbnRows', function ($compile, $rootScope, getAppState, Private) {
@ -60,7 +62,7 @@ module.directive('kbnRows', function ($compile, $rootScope, getAppState, Private
// TODO: It would be better to actually check the type of the field, but we don't have
// access to it here. This may become a problem with the switch to BigNumber
if (_.isNumeric(contents)) {
if (isNumeric(contents)) {
$cell.addClass('numeric-value');
}
}

View file

@ -1,6 +1,6 @@
import _ from 'lodash';
import dragula from 'dragula';
import { uiModules } from 'ui/modules';
import { move } from '../utils/collection';
uiModules
.get('kibana')
@ -82,7 +82,7 @@ uiModules
const siblingIndex = getItemIndexFromElement(list, sibling);
const toIndex = getTargetIndex(list, fromIndex, siblingIndex);
_.move(list, item, toIndex);
move(list, item, toIndex);
}
function getTargetIndex(list, fromIndex, siblingIndex) {

View file

@ -1,5 +1,5 @@
import angular from 'angular';
import _ from 'lodash';
import { createLegacyClass } from './utils/legacy_class';
const canStack = (function () {
const err = new Error();
@ -30,7 +30,7 @@ export class KbnError {
// http://stackoverflow.com/questions/33870684/why-doesnt-instanceof-work-on-instances-of-error-subclasses-under-babel-node
// Hence we are inheriting from it this way, instead of using extends Error, and this will then preserve
// instanceof checks.
_.class(KbnError).inherits(Error);
createLegacyClass(KbnError).inherits(Error);
/**
* SearchTimeout error class

View file

@ -7,11 +7,12 @@
import _ from 'lodash';
import { fatalError } from 'ui/notify';
import { SimpleEmitter } from 'ui/utils/simple_emitter';
import { createLegacyClass } from './utils/legacy_class';
const location = 'EventEmitter';
export function EventsProvider(Private, Promise) {
_.class(Events).inherits(SimpleEmitter);
createLegacyClass(Events).inherits(SimpleEmitter);
function Events() {
Events.Super.call(this);
this._listeners = {};

View file

@ -5,6 +5,7 @@ import expect from 'expect.js';
import ngMock from 'ng_mock';
import 'ui/private';
import { EventsProvider } from 'ui/events';
import { createLegacyClass } from '../../utils/legacy_class';
describe('Events', function () {
require('test_utils/no_digest_promises').activateForSuite();
@ -30,7 +31,7 @@ describe('Events', function () {
});
it('should work with inherited objects', function () {
_.class(MyEventedObject).inherits(Events);
createLegacyClass(MyEventedObject).inherits(Events);
function MyEventedObject() {
MyEventedObject.Super.call(this);
}

View file

@ -1,11 +1,11 @@
import { IndexedArray } from 'ui/indexed_array';
import _ from 'lodash';
import { IndexPatternsFieldProvider } from 'ui/index_patterns/_field';
import { createLegacyClass } from '../utils/legacy_class';
export function IndexPatternsFieldListProvider(Private) {
const Field = Private(IndexPatternsFieldProvider);
_.class(FieldList).inherits(IndexedArray);
createLegacyClass(FieldList).inherits(IndexedArray);
function FieldList(indexPattern, specs) {
FieldList.Super.call(this, {
index: ['name'],

View file

@ -1,6 +1,7 @@
import _ from 'lodash';
import moment from 'moment';
import { IndexedArray } from 'ui/indexed_array';
import { isNumeric } from '../utils/numeric';
export function IndexPatternsIntervalsProvider(timefilter) {
@ -52,7 +53,7 @@ export function IndexPatternsIntervalsProvider(timefilter) {
val = bounds[bound];
}
if (_.isNumeric(val)) val = moment().add(val, interval.name);
if (isNumeric(val)) val = moment().add(val, interval.name);
else if (!moment.isMoment(val)) val = moment(val);
return val.clone().utc()[extend](interval.startOf);

View file

@ -1,5 +1,6 @@
import _ from 'lodash';
import { inflector } from './inflector';
import { organizeBy } from '../utils/collection';
const pathGetter = _(_.get).rearg(1, 0).ary(2);
const inflectIndex = inflector('by');
@ -31,7 +32,7 @@ export class IndexedArray {
Object.defineProperty(this, 'raw', { value: [] });
this._indexNames = _.union(
this._setupIndex(config.group, inflectIndex, _.organizeBy),
this._setupIndex(config.group, inflectIndex, organizeBy),
this._setupIndex(config.index, inflectIndex, _.indexBy),
this._setupIndex(config.order, inflectOrder, (raw, pluckValue) => {
return [...raw].sort((itemA, itemB) => {

View file

@ -3,6 +3,7 @@ import $ from 'jquery';
import { metadata } from 'ui/metadata';
import { formatMsg, formatStack } from './lib';
import fatalSplashScreen from './partials/fatal_splash_screen.html';
import { callEach } from '../utils/function';
const {
version,
@ -45,7 +46,7 @@ function formatInfo() {
export const fatalErrorInternals = {
show: (err, location) => {
if (firstFatal) {
_.callEach(fatalCallbacks);
callEach(fatalCallbacks);
firstFatal = false;
window.addEventListener('hashchange', function () {
window.location.reload();

View file

@ -8,10 +8,11 @@
* ability to destroy those mappings.
*/
import _ from 'lodash';
import { uiModules } from 'ui/modules';
import { StateProvider } from 'ui/state_management/state';
import 'ui/persisted_state';
import { createLegacyClass } from '../utils/legacy_class';
import { callEach } from '../utils/function';
const urlParam = '_a';
@ -21,7 +22,7 @@ export function AppStateProvider(Private, $rootScope, $location, $injector) {
let persistedStates;
let eventUnsubscribers;
_.class(AppState).inherits(State);
createLegacyClass(AppState).inherits(State);
function AppState(defaults) {
// Initialize persistedStates. This object maps "prop" names to
// PersistedState instances. These are used to make properties "stateful".
@ -42,7 +43,7 @@ export function AppStateProvider(Private, $rootScope, $location, $injector) {
AppState.prototype.destroy = function () {
AppState.Super.prototype.destroy.call(this);
AppState.getAppState._set(null);
_.callEach(eventUnsubscribers);
callEach(eventUnsubscribers);
};
/**

View file

@ -1,14 +1,14 @@
import _ from 'lodash';
import { QueryString } from 'ui/utils/query_string';
import { StateProvider } from 'ui/state_management/state';
import { uiModules } from 'ui/modules';
import { createLegacyClass } from '../utils/legacy_class';
const module = uiModules.get('kibana/global_state');
export function GlobalStateProvider(Private) {
const State = Private(StateProvider);
_.class(GlobalState).inherits(State);
createLegacyClass(GlobalState).inherits(State);
function GlobalState(defaults) {
GlobalState.Super.call(this, '_g', defaults);
}

View file

@ -13,6 +13,8 @@ import { applyDiff } from 'ui/utils/diff_object';
import { EventsProvider } from 'ui/events';
import { fatalError, Notifier } from 'ui/notify';
import 'ui/state_management/config_provider';
import { createLegacyClass } from '../utils/legacy_class';
import { callEach } from '../utils/function';
import {
createStateHash,
@ -23,7 +25,7 @@ import {
export function StateProvider(Private, $rootScope, $location, stateManagementConfig, config, kbnUrl) {
const Events = Private(EventsProvider);
_.class(State).inherits(Events);
createLegacyClass(State).inherits(Events);
function State(
urlParam,
defaults,
@ -38,7 +40,7 @@ export function StateProvider(Private, $rootScope, $location, stateManagementCon
this._hashedItemStore = hashedItemStore;
// When the URL updates we need to fetch the values from the URL
this._cleanUpListeners = _.partial(_.callEach, [
this._cleanUpListeners = _.partial(callEach, [
// partial route update, no app reload
$rootScope.$on('$routeUpdate', () => {
this.fetch();

View file

@ -8,6 +8,7 @@ import { TimefilterLibDiffTimeProvider } from 'ui/timefilter/lib/diff_time';
import { TimefilterLibDiffIntervalProvider } from 'ui/timefilter/lib/diff_interval';
import uiRoutes from 'ui/routes';
import { uiModules } from 'ui/modules';
import { createLegacyClass } from '../utils/legacy_class';
uiRoutes
.addSetupWork(function (timefilter) {
@ -24,7 +25,7 @@ uiModules
return obj.isValid() ? obj : stringTime;
}
_.class(Timefilter).inherits(Events);
createLegacyClass(Timefilter).inherits(Events);
function Timefilter() {
Timefilter.Super.call(this);

View file

@ -0,0 +1,225 @@
import expect from 'expect.js';
import { groupBy } from 'lodash';
import { move, pushAll, organizeBy } from '../collection';
describe('collection', () => {
describe('move', function () {
it('accepts previous from->to syntax', function () {
const list = [
1,
1,
1,
1,
1,
1,
1,
1,
8,
1,
1,
];
expect(list[3]).to.be(1);
expect(list[8]).to.be(8);
move(list, 8, 3);
expect(list[8]).to.be(1);
expect(list[3]).to.be(8);
});
it('moves an object up based on a function callback', function () {
const list = [
1,
1,
1,
1,
0,
1,
0,
1,
1,
1,
1,
];
expect(list[4]).to.be(0);
expect(list[5]).to.be(1);
expect(list[6]).to.be(0);
move(list, 5, false, function (v) {
return v === 0;
});
expect(list[4]).to.be(1);
expect(list[5]).to.be(0);
expect(list[6]).to.be(0);
});
it('moves an object down based on a function callback', function () {
const list = [
1,
1,
1,
1,
0,
1,
0,
1,
1,
1,
1,
];
expect(list[4]).to.be(0);
expect(list[5]).to.be(1);
expect(list[6]).to.be(0);
move(list, 5, true, function (v) {
return v === 0;
});
expect(list[4]).to.be(0);
expect(list[5]).to.be(0);
expect(list[6]).to.be(1);
});
it('moves an object up based on a where callback', function () {
const list = [
{ v: 1 },
{ v: 1 },
{ v: 1 },
{ v: 1 },
{ v: 0 },
{ v: 1 },
{ v: 0 },
{ v: 1 },
{ v: 1 },
{ v: 1 },
{ v: 1 },
];
expect(list[4]).to.have.property('v', 0);
expect(list[5]).to.have.property('v', 1);
expect(list[6]).to.have.property('v', 0);
move(list, 5, false, { v: 0 });
expect(list[4]).to.have.property('v', 1);
expect(list[5]).to.have.property('v', 0);
expect(list[6]).to.have.property('v', 0);
});
it('moves an object down based on a where callback', function () {
const list = [
{ v: 1 },
{ v: 1 },
{ v: 1 },
{ v: 1 },
{ v: 0 },
{ v: 1 },
{ v: 0 },
{ v: 1 },
{ v: 1 },
{ v: 1 },
{ v: 1 },
];
expect(list[4]).to.have.property('v', 0);
expect(list[5]).to.have.property('v', 1);
expect(list[6]).to.have.property('v', 0);
move(list, 5, true, { v: 0 });
expect(list[4]).to.have.property('v', 0);
expect(list[5]).to.have.property('v', 0);
expect(list[6]).to.have.property('v', 1);
});
it('moves an object down based on a pluck callback', function () {
const list = [
{ id: 0, normal: true },
{ id: 1, normal: true },
{ id: 2, normal: true },
{ id: 3, normal: true },
{ id: 4, normal: true },
{ id: 5, normal: false },
{ id: 6, normal: true },
{ id: 7, normal: true },
{ id: 8, normal: true },
{ id: 9, normal: true }
];
expect(list[4]).to.have.property('id', 4);
expect(list[5]).to.have.property('id', 5);
expect(list[6]).to.have.property('id', 6);
move(list, 5, true, 'normal');
expect(list[4]).to.have.property('id', 4);
expect(list[5]).to.have.property('id', 6);
expect(list[6]).to.have.property('id', 5);
});
});
describe('pushAll', function () {
it('pushes an entire array into another', function () {
const a = [1, 2, 3, 4];
const b = [5, 6, 7, 8];
const output = pushAll(b, a);
expect(output).to.be(a);
expect(a).to.eql([1, 2, 3, 4, 5, 6, 7, 8]);
expect(b).to.eql([5, 6, 7, 8]);
});
});
describe('organizeBy', function () {
it('it works', function () {
const col = [
{
name: 'one',
roles: ['user', 'admin', 'owner']
},
{
name: 'two',
roles: ['user']
},
{
name: 'three',
roles: ['user']
},
{
name: 'four',
roles: ['user', 'admin']
}
];
const resp = organizeBy(col, 'roles');
expect(resp).to.have.property('user');
expect(resp.user).to.have.length(4);
expect(resp).to.have.property('admin');
expect(resp.admin).to.have.length(2);
expect(resp).to.have.property('owner');
expect(resp.owner).to.have.length(1);
});
it('behaves just like groupBy in normal scenarios', function () {
const col = [
{ name: 'one' },
{ name: 'two' },
{ name: 'three' },
{ name: 'four' }
];
const orgs = organizeBy(col, 'name');
const groups = groupBy(col, 'name');
expect(orgs).to.eql(groups);
});
});
});

View file

@ -0,0 +1,104 @@
import _ from 'lodash';
/**
* move an obj either up or down in the collection by
* injecting it either before/after the prev/next obj that
* satisfied the qualifier
*
* or, just from one index to another...
*
* @param {array} objs - the list to move the object within
* @param {number|any} obj - the object that should be moved, or the index that the object is currently at
* @param {number|boolean} below - the index to move the object to, or whether it should be moved up or down
* @param {function} qualifier - a lodash-y callback, object = _.where, string = _.pluck
* @return {array} - the objs argument
*/
export function move(objs, obj, below, qualifier) {
const origI = _.isNumber(obj) ? obj : objs.indexOf(obj);
if (origI === -1) return objs;
if (_.isNumber(below)) {
// move to a specific index
objs.splice(below, 0, objs.splice(origI, 1)[0]);
return objs;
}
below = !!below;
qualifier = _.callback(qualifier);
const above = !below;
const finder = below ? _.findIndex : _.findLastIndex;
// find the index of the next/previous obj that meets the qualifications
const targetI = finder(objs, function (otherAgg, otherI) {
if (below && otherI <= origI) return;
if (above && otherI >= origI) return;
return !!qualifier(otherAgg, otherI);
});
if (targetI === -1) return objs;
// place the obj at it's new index
objs.splice(targetI, 0, objs.splice(origI, 1)[0]);
}
/**
* Like _.groupBy, but allows specifying multiple groups for a
* single object.
*
* organizeBy([{ a: [1, 2, 3] }, { b: true, a: [1, 4] }], 'a')
* // Object {1: Array[2], 2: Array[1], 3: Array[1], 4: Array[1]}
*
* _.groupBy([{ a: [1, 2, 3] }, { b: true, a: [1, 4] }], 'a')
* // Object {'1,2,3': Array[1], '1,4': Array[1]}
*
* @param {array} collection - the list of values to organize
* @param {Function} callback - either a property name, or a callback.
* @return {object}
*/
export function organizeBy(collection, callback) {
const buckets = {};
const prop = typeof callback === 'function' ? false : callback;
function add(key, obj) {
if (!buckets[key]) buckets[key] = [];
buckets[key].push(obj);
}
_.each(collection, function (obj) {
const keys = prop === false ? callback(obj) : obj[prop];
if (!Array.isArray(keys)) {
add(keys, obj);
return;
}
let length = keys.length;
while (length-- > 0) {
add(keys[length], obj);
}
});
return buckets;
}
/**
* Efficient and safe version of [].push(dest, source);
*
* @param {Array} source - the array to pull values from
* @param {Array} dest - the array to push values into
* @return {Array} dest
*/
export function pushAll(source, dest) {
const start = dest.length;
const adding = source.length;
// allocate - http://goo.gl/e2i0S0
dest.length = start + adding;
// fill sparse positions
let i = -1;
while (++i < adding) dest[start + i] = source[i];
return dest;
}

View file

@ -0,0 +1,13 @@
import _ from 'lodash';
/**
* Call all of the function in an array
*
* @param {array[functions]} arr
* @return {undefined}
*/
export function callEach(arr) {
return _.map(arr, function (fn) {
return _.isFunction(fn) ? fn() : undefined;
});
}

View file

@ -0,0 +1,38 @@
// create a property descriptor for properties
// that won't change
function describeConst(val) {
return {
writable: false,
enumerable: false,
configurable: false,
value: val
};
}
const props = {
inherits: describeConst(function (SuperClass) {
const prototype = Object.create(SuperClass.prototype, {
constructor: describeConst(this),
superConstructor: describeConst(SuperClass)
});
Object.defineProperties(this, {
prototype: describeConst(prototype),
Super: describeConst(SuperClass)
});
return this;
})
};
/**
* Add class-related behavior to a function, currently this
* only attaches an .inherits() method.
*
* @param {Constructor} ClassConstructor - The function that should be extended
* @return {Constructor} - the constructor passed in;
*/
export function createLegacyClass(ClassConstructor) {
return Object.defineProperties(ClassConstructor, props);
}

View file

@ -1,162 +0,0 @@
import _ from 'lodash';
import expect from 'expect.js';
describe('_.move', function () {
it('accepts previous from->to syntax', function () {
const list = [
1,
1,
1,
1,
1,
1,
1,
1,
8,
1,
1,
];
expect(list[3]).to.be(1);
expect(list[8]).to.be(8);
_.move(list, 8, 3);
expect(list[8]).to.be(1);
expect(list[3]).to.be(8);
});
it('moves an object up based on a function callback', function () {
const list = [
1,
1,
1,
1,
0,
1,
0,
1,
1,
1,
1,
];
expect(list[4]).to.be(0);
expect(list[5]).to.be(1);
expect(list[6]).to.be(0);
_.move(list, 5, false, function (v) {
return v === 0;
});
expect(list[4]).to.be(1);
expect(list[5]).to.be(0);
expect(list[6]).to.be(0);
});
it('moves an object down based on a function callback', function () {
const list = [
1,
1,
1,
1,
0,
1,
0,
1,
1,
1,
1,
];
expect(list[4]).to.be(0);
expect(list[5]).to.be(1);
expect(list[6]).to.be(0);
_.move(list, 5, true, function (v) {
return v === 0;
});
expect(list[4]).to.be(0);
expect(list[5]).to.be(0);
expect(list[6]).to.be(1);
});
it('moves an object up based on a where callback', function () {
const list = [
{ v: 1 },
{ v: 1 },
{ v: 1 },
{ v: 1 },
{ v: 0 },
{ v: 1 },
{ v: 0 },
{ v: 1 },
{ v: 1 },
{ v: 1 },
{ v: 1 },
];
expect(list[4]).to.have.property('v', 0);
expect(list[5]).to.have.property('v', 1);
expect(list[6]).to.have.property('v', 0);
_.move(list, 5, false, { v: 0 });
expect(list[4]).to.have.property('v', 1);
expect(list[5]).to.have.property('v', 0);
expect(list[6]).to.have.property('v', 0);
});
it('moves an object down based on a where callback', function () {
const list = [
{ v: 1 },
{ v: 1 },
{ v: 1 },
{ v: 1 },
{ v: 0 },
{ v: 1 },
{ v: 0 },
{ v: 1 },
{ v: 1 },
{ v: 1 },
{ v: 1 },
];
expect(list[4]).to.have.property('v', 0);
expect(list[5]).to.have.property('v', 1);
expect(list[6]).to.have.property('v', 0);
_.move(list, 5, true, { v: 0 });
expect(list[4]).to.have.property('v', 0);
expect(list[5]).to.have.property('v', 0);
expect(list[6]).to.have.property('v', 1);
});
it('moves an object down based on a pluck callback', function () {
const list = [
{ id: 0, normal: true },
{ id: 1, normal: true },
{ id: 2, normal: true },
{ id: 3, normal: true },
{ id: 4, normal: true },
{ id: 5, normal: false },
{ id: 6, normal: true },
{ id: 7, normal: true },
{ id: 8, normal: true },
{ id: 9, normal: true }
];
expect(list[4]).to.have.property('id', 4);
expect(list[5]).to.have.property('id', 5);
expect(list[6]).to.have.property('id', 6);
_.move(list, 5, true, 'normal');
expect(list[4]).to.have.property('id', 4);
expect(list[5]).to.have.property('id', 6);
expect(list[6]).to.have.property('id', 5);
});
});

View file

@ -1,48 +0,0 @@
import _ from 'lodash';
import expect from 'expect.js';
describe('_.organize', function () {
it('it works', function () {
const col = [
{
name: 'one',
roles: ['user', 'admin', 'owner']
},
{
name: 'two',
roles: ['user']
},
{
name: 'three',
roles: ['user']
},
{
name: 'four',
roles: ['user', 'admin']
}
];
const resp = _.organizeBy(col, 'roles');
expect(resp).to.have.property('user');
expect(resp.user).to.have.length(4);
expect(resp).to.have.property('admin');
expect(resp.admin).to.have.length(2);
expect(resp).to.have.property('owner');
expect(resp.owner).to.have.length(1);
});
it('behaves just like groupBy in normal scenarios', function () {
const col = [
{ name: 'one' },
{ name: 'two' },
{ name: 'three' },
{ name: 'four' }
];
const orgs = _.organizeBy(col, 'name');
const groups = _.groupBy(col, 'name');
expect(orgs).to.eql(groups);
});
});

View file

@ -1,14 +0,0 @@
import _ from 'lodash';
import expect from 'expect.js';
describe('_.pushAll', function () {
it('pushes an entire array into another', function () {
const a = [1, 2, 3, 4];
const b = [5, 6, 7, 8];
const output = _.pushAll(b, a);
expect(output).to.be(a);
expect(a).to.eql([1, 2, 3, 4, 5, 6, 7, 8]);
expect(b).to.eql([5, 6, 7, 8]);
});
});

View file

@ -1,6 +0,0 @@
import './_move';
import './_organize_by';
import './_push_all';
describe('lodash mixins', function () {
});

View file

@ -1,126 +0,0 @@
export function lodashCollectionMixin(_) {
_.mixin(_, {
/**
* move an obj either up or down in the collection by
* injecting it either before/after the prev/next obj that
* satisfied the qualifier
*
* or, just from one index to another...
*
* @param {array} objs - the list to move the object within
* @param {number|any} obj - the object that should be moved, or the index that the object is currently at
* @param {number|boolean} below - the index to move the object to, or whether it should be moved up or down
* @param {function} qualifier - a lodash-y callback, object = _.where, string = _.pluck
* @return {array} - the objs argument
*/
move: function (objs, obj, below, qualifier) {
const origI = _.isNumber(obj) ? obj : objs.indexOf(obj);
if (origI === -1) return objs;
if (_.isNumber(below)) {
// move to a specific index
objs.splice(below, 0, objs.splice(origI, 1)[0]);
return objs;
}
below = !!below;
qualifier = _.callback(qualifier);
const above = !below;
const finder = below ? _.findIndex : _.findLastIndex;
// find the index of the next/previous obj that meets the qualifications
const targetI = finder(objs, function (otherAgg, otherI) {
if (below && otherI <= origI) return;
if (above && otherI >= origI) return;
return !!qualifier(otherAgg, otherI);
});
if (targetI === -1) return objs;
// place the obj at it's new index
objs.splice(targetI, 0, objs.splice(origI, 1)[0]);
},
/**
* Like _.groupBy, but allows specifying multiple groups for a
* single object.
*
* _.organizeBy([{ a: [1, 2, 3] }, { b: true, a: [1, 4] }], 'a')
* // Object {1: Array[2], 2: Array[1], 3: Array[1], 4: Array[1]}
*
* _.groupBy([{ a: [1, 2, 3] }, { b: true, a: [1, 4] }], 'a')
* // Object {'1,2,3': Array[1], '1,4': Array[1]}
*
* @param {array} collection - the list of values to organize
* @param {Function} callback - either a property name, or a callback.
* @return {object}
*/
organizeBy: function (collection, callback) {
const buckets = {};
const prop = typeof callback === 'function' ? false : callback;
function add(key, obj) {
if (!buckets[key]) buckets[key] = [];
buckets[key].push(obj);
}
_.each(collection, function (obj) {
const keys = prop === false ? callback(obj) : obj[prop];
if (!Array.isArray(keys)) {
add(keys, obj);
return;
}
let length = keys.length;
while (length-- > 0) {
add(keys[length], obj);
}
});
return buckets;
},
/**
* Remove or add a value to an array based on it's presense in the
* array initially.
*
* @param {array} arr
* @param {any} value - the value to toggle
* @return {array} arr
*/
toggleInOut: function (arr, value) {
if (_.contains(arr, value)) {
arr.splice(arr.indexOf(value), 1);
} else {
arr.push(value);
}
return arr;
},
/**
* Efficient and safe version of [].push(dest, source);
*
* @param {Array} source - the array to pull values from
* @param {Array} dest - the array to push values into
* @return {Array} dest
*/
pushAll: function (source, dest) {
const start = dest.length;
const adding = source.length;
// allocate - http://goo.gl/e2i0S0
dest.length = start + adding;
// fill sparse positions
let i = -1;
while (++i < adding) dest[start + i] = source[i];
return dest;
},
});
}

View file

@ -1,65 +0,0 @@
export function lodashFunctionMixin(_) {
_.mixin({
/**
* Create a method that wraps another method which expects a callback as it's last
* argument. The wrapper method will call the wrapped function only once (the first
* time it is called), but will always call the callbacks passed to it. This has a
* similar effect to calling a promise-returning function that is wrapped with _.once
* but can be used outside of angular.
*
* @param {Function} fn - the function that should only be executed once and accepts
* a callback as it's last arg
* @return {Function} - the wrapper method
*/
onceWithCb: function (fn) {
const callbacks = [];
// on initial flush, call the init function, but ensure
// that it only happens once
let flush = _.once(function (cntx, args) {
args.push(function finishedOnce() {
// override flush to simply schedule an asynchronous clear
flush = function () {
setTimeout(function () {
_.callEach(callbacks.splice(0));
}, 0);
};
flush();
});
fn.apply(cntx, args);
});
return function runOnceWithCb() {
let args = [].slice.call(arguments, 0);
const cb = args[args.length - 1];
if (typeof cb === 'function') {
callbacks.push(cb);
// trim the arg list so the other callback can
// be pushed if needed
args = args.slice(0, -1);
}
// always call flush, it might not do anything
flush(this, args);
};
},
/**
* Call all of the function in an array
*
* @param {array[functions]} arr
* @return {undefined}
*/
callEach: function (arr) {
return _.map(arr, function (fn) {
return _.isFunction(fn) ? fn() : undefined;
});
}
});
}

View file

@ -1,19 +0,0 @@
export function lodashLangMixin(_) {
_.mixin(_, {
/**
* Checks to see if an input value is number-like, this
* includes strings that parse into valid numbers and objects
* that don't have a type of number but still parse properly
* via-some sort of valueOf magic
*
* @param {any} v - the value to check
* @return {Boolean}
*/
isNumeric: function (v) {
return !_.isNaN(v) && (typeof v === 'number' || (!Array.isArray(v) && !_.isNaN(parseFloat(v))));
},
});
}

View file

@ -1,38 +0,0 @@
export function lodashObjectMixin(_) {
return _.mixin(_, {
/**
* Flatten an object into a single-level object.
* NOTE: The flatten behavior here works if you don't need to keep a reference to the original value
*
* set flattenArrays to traverse into arrays and create properties like:
* {
* 'users.0.name': 'username1',
* 'users.1.name': 'username2',
* 'users.2.name': 'username3',
* }
*
* @param {string} dot - the seperator for keys, '.' is generally preferred
* @param {object} nestedObj - the object to flatten
* @param {Boolean} flattenArrays - should arrays be travered or left alone?
* @return {object}
*/
flattenWith: function (dot, nestedObj, flattenArrays) {
const stack = []; // track key stack
const flatObj = {};
(function flattenObj(obj) {
_.keys(obj).forEach(function (key) {
stack.push(key);
if (!flattenArrays && Array.isArray(obj[key])) flatObj[stack.join(dot)] = obj[key];
else if (_.isObject(obj[key])) flattenObj(obj[key]);
else flatObj[stack.join(dot)] = obj[key];
stack.pop();
});
}(nestedObj));
return flatObj;
}
});
}

View file

@ -1,44 +0,0 @@
export function lodashOopMixin(_) {
// create a property descriptor for properties
// that won't change
function describeConst(val) {
return {
writable: false,
enumerable: false,
configurable: false,
value: val
};
}
const props = {
inherits: describeConst(function (SuperClass) {
const prototype = Object.create(SuperClass.prototype, {
constructor: describeConst(this),
superConstructor: describeConst(SuperClass)
});
Object.defineProperties(this, {
prototype: describeConst(prototype),
Super: describeConst(SuperClass)
});
return this;
})
};
_.mixin(_, {
/**
* Add class-related behavior to a function, currently this
* only attaches an .inherits() method.
*
* @param {Constructor} ClassConstructor - The function that should be extended
* @return {Constructor} - the constructor passed in;
*/
class: function (ClassConstructor) {
return Object.defineProperties(ClassConstructor, props);
}
});
}

View file

@ -0,0 +1,5 @@
import _ from 'lodash';
export function isNumeric(v) {
return !_.isNaN(v) && (typeof v === 'number' || (!Array.isArray(v) && !_.isNaN(parseFloat(v))));
}

View file

@ -1,5 +1,6 @@
import _ from 'lodash';
import { BaseObject } from 'ui/utils/base_object';
import { createLegacyClass } from './legacy_class';
/**
* Simple event emitter class used in the vislib. Calls
@ -7,7 +8,7 @@ import { BaseObject } from 'ui/utils/base_object';
*
* @class
*/
_.class(SimpleEmitter).inherits(BaseObject);
createLegacyClass(SimpleEmitter).inherits(BaseObject);
export function SimpleEmitter() {
this._listeners = {};
}

View file

@ -11,11 +11,12 @@ import _ from 'lodash';
import { IndexedArray } from 'ui/indexed_array';
import { AggConfig } from 'ui/vis/agg_config';
import { AggTypesIndexProvider } from 'ui/agg_types/index';
import { createLegacyClass } from '../utils/legacy_class';
export function VisAggConfigsProvider(Private) {
AggConfig.aggTypes = Private(AggTypesIndexProvider);
_.class(AggConfigs).inherits(IndexedArray);
createLegacyClass(AggConfigs).inherits(IndexedArray);
function AggConfigs(vis, configStates) {
const self = this;
self.vis = vis;

View file

@ -4,6 +4,8 @@ import { Direction } from './keyboard_move';
import _ from 'lodash';
import { uiModules } from 'ui/modules';
import aggTemplate from './agg.html';
import { move } from '../../../utils/collection';
uiModules
.get('app/visualize')
.directive('visEditorAgg', function ($compile, $parse, $filter, Private, Notifier) {
@ -60,7 +62,7 @@ uiModules
const currentPosition = $scope.group.indexOf($scope.agg);
const newPosition = Math.max(0, Math.min(currentPosition + positionOffset, $scope.group.length - 1));
_.move($scope.group, currentPosition, newPosition);
move($scope.group, currentPosition, newPosition);
$scope.$emit('agg-reorder');
};

View file

@ -5,6 +5,7 @@ import './nesting_indicator';
import { uiModules } from 'ui/modules';
import aggGroupTemplate from './agg_group.html';
import { move } from '../../../utils/collection';
uiModules
.get('app/visualize')
@ -48,7 +49,7 @@ uiModules
//to apply that ordering to [vis.aggs]
const indexOffset = $scope.vis.aggs.indexOf($scope.group[0]);
_.forEach($scope.group, (agg, index) => {
_.move($scope.vis.aggs, agg, indexOffset + index);
move($scope.vis.aggs, agg, indexOffset + index);
});
}

View file

@ -1,5 +1,6 @@
import _ from 'lodash';
import { uiModules } from 'ui/modules';
import { callEach } from '../utils/function';
uiModules.get('kibana')
.config(function ($provide) {
@ -80,7 +81,7 @@ uiModules.get('kibana')
});
}));
return _.partial(_.callEach, unwatchers);
return _.partial(callEach, unwatchers);
};
function normalizeExpression($scope, expr) {

View file

@ -1,21 +0,0 @@
/**
* THESE ARE AUTOMATICALLY INCLUDED IN LODASH
*
* use:
* var _ = require('lodash');
*/
var _ = require('../node_modules/lodash/index.js').runInContext();
var lodashLangMixin = require('ui/utils/lodash-mixins/lang').lodashLangMixin;
var lodashObjectMixin = require('ui/utils/lodash-mixins/object').lodashObjectMixin;
var lodashCollectionMixin = require('ui/utils/lodash-mixins/collection').lodashCollectionMixin;
var lodashFunctionMixin = require('ui/utils/lodash-mixins/function').lodashFunctionMixin;
var lodashOopMixin = require('ui/utils/lodash-mixins/oop').lodashOopMixin;
lodashLangMixin(_);
lodashObjectMixin(_);
lodashCollectionMixin(_);
lodashFunctionMixin(_);
lodashOopMixin(_);
module.exports = _;