REFACTOR: Remove _.merge

This commit is contained in:
Robin Ward 2020-09-02 11:52:54 -04:00
parent 720cd57fb5
commit c4079780be
16 changed files with 70 additions and 18 deletions

View File

@ -0,0 +1,37 @@
// a fairly simple deep merge based on: https://gist.github.com/ahtcx/0cd94e62691f539160b32ecda18af3d6
export function merge(...objects) {
const isObject = obj => obj && typeof obj === "object";
function deepMergeInner(target, source) {
Object.keys(source).forEach(key => {
const targetValue = target[key];
const sourceValue = source[key];
if (Array.isArray(targetValue) && Array.isArray(sourceValue)) {
target[key] = targetValue.concat(sourceValue);
} else if (isObject(targetValue) && isObject(sourceValue)) {
target[key] = deepMergeInner(
Object.assign({}, targetValue),
sourceValue
);
} else {
target[key] = sourceValue;
}
});
return target;
}
if (objects.some(object => object && !isObject(object))) {
throw new Error('deepMerge: all values should be of type "object"');
}
const target = objects.shift();
let source;
while ((source = objects.shift())) {
deepMergeInner(target, source || {});
}
return target;
}

View File

@ -26,6 +26,7 @@ import { escapeExpression } from "discourse/lib/utilities";
import { AUTO_DELETE_PREFERENCES } from "discourse/models/bookmark"; import { AUTO_DELETE_PREFERENCES } from "discourse/models/bookmark";
import { inject as service } from "@ember/service"; import { inject as service } from "@ember/service";
import bootbox from "bootbox"; import bootbox from "bootbox";
import { merge } from "discourse-common/lib/object";
let customPostMessageCallbacks = {}; let customPostMessageCallbacks = {};
@ -249,7 +250,7 @@ export default Controller.extend(bufferedProperty("model"), {
this.set("loadingPostIds", true); this.set("loadingPostIds", true);
return ajax(url, { return ajax(url, {
data: _.merge( data: merge(
{ post_number: post.get("post_number") }, { post_number: post.get("post_number") },
postStream.get("streamFilters") postStream.get("streamFilters")
) )

View File

@ -13,6 +13,7 @@ import User from "discourse/models/user";
import Post from "discourse/models/post"; import Post from "discourse/models/post";
import Topic from "discourse/models/topic"; import Topic from "discourse/models/topic";
import { escapeExpression } from "discourse/lib/utilities"; import { escapeExpression } from "discourse/lib/utilities";
import { merge } from "discourse-common/lib/object";
export function translateResults(results, opts) { export function translateResults(results, opts) {
opts = opts || {}; opts = opts || {};
@ -206,7 +207,7 @@ export function applySearchAutocomplete(
}; };
$input.autocomplete( $input.autocomplete(
_.merge( merge(
{ {
template: findRawTemplate("category-tag-autocomplete"), template: findRawTemplate("category-tag-autocomplete"),
key: "#", key: "#",
@ -226,7 +227,7 @@ export function applySearchAutocomplete(
if (siteSettings.enable_mentions) { if (siteSettings.enable_mentions) {
$input.autocomplete( $input.autocomplete(
_.merge( merge(
{ {
template: findRawTemplate("user-selector-autocomplete"), template: findRawTemplate("user-selector-autocomplete"),
key: "@", key: "@",

View File

@ -4,6 +4,7 @@ import toMarkdown from "discourse/lib/to-markdown";
import Handlebars from "handlebars"; import Handlebars from "handlebars";
import { default as getURL, getURLWithCDN } from "discourse-common/lib/get-url"; import { default as getURL, getURLWithCDN } from "discourse-common/lib/get-url";
import { helperContext } from "discourse-common/lib/helpers"; import { helperContext } from "discourse-common/lib/helpers";
import { merge } from "discourse-common/lib/object";
let _defaultHomepage; let _defaultHomepage;
@ -85,7 +86,7 @@ export function avatarImg(options, customGetURL) {
export function tinyAvatar(avatarTemplate, options) { export function tinyAvatar(avatarTemplate, options) {
return avatarImg( return avatarImg(
_.merge({ avatarTemplate: avatarTemplate, size: "tiny" }, options) merge({ avatarTemplate: avatarTemplate, size: "tiny" }, options)
); );
} }

View File

@ -8,6 +8,7 @@ import getUrl from "discourse-common/lib/get-url";
import { on } from "@ember/object/evented"; import { on } from "@ember/object/evented";
import Mixin from "@ember/object/mixin"; import Mixin from "@ember/object/mixin";
import bootbox from "bootbox"; import bootbox from "bootbox";
import { merge } from "discourse-common/lib/object";
export default Mixin.create({ export default Mixin.create({
uploading: false, uploading: false,
@ -56,7 +57,7 @@ export default Mixin.create({
}); });
$upload.fileupload( $upload.fileupload(
_.merge( merge(
{ {
url: this.calculateUploadUrl(), url: this.calculateUploadUrl(),
dataType: "json", dataType: "json",
@ -82,7 +83,7 @@ export default Mixin.create({
}); });
$upload.on("fileuploadsubmit", (e, data) => { $upload.on("fileuploadsubmit", (e, data) => {
const opts = _.merge( const opts = merge(
{ {
bypassNewUserRestriction: true, bypassNewUserRestriction: true,
user: this.currentUser, user: this.currentUser,

View File

@ -9,6 +9,7 @@ import deprecated from "discourse-common/lib/deprecated";
import Site from "discourse/models/site"; import Site from "discourse/models/site";
import User from "discourse/models/user"; import User from "discourse/models/user";
import { getOwner } from "discourse-common/lib/get-owner"; import { getOwner } from "discourse-common/lib/get-owner";
import { merge } from "discourse-common/lib/object";
const NavItem = EmberObject.extend({ const NavItem = EmberObject.extend({
@discourseComputed("name") @discourseComputed("name")
@ -180,7 +181,7 @@ NavItem.reopenClass({
args.noSubcategories = true; args.noSubcategories = true;
} }
NavItem.extraArgsCallbacks.forEach(cb => NavItem.extraArgsCallbacks.forEach(cb =>
_.merge(args, cb.call(this, filterType, opts)) merge(args, cb.call(this, filterType, opts))
); );
let store = getOwner(this).lookup("service:store"); let store = getOwner(this).lookup("service:store");
@ -222,7 +223,7 @@ NavItem.reopenClass({
}; };
const extraItems = NavItem.extraNavItemDescriptors const extraItems = NavItem.extraNavItemDescriptors
.map(descriptor => ExtraNavItem.create(_.merge({}, context, descriptor))) .map(descriptor => ExtraNavItem.create(merge({}, context, descriptor)))
.filter(item => { .filter(item => {
if (!item.customFilter) return true; if (!item.customFilter) return true;
return item.customFilter(category, args); return item.customFilter(category, args);

View File

@ -10,6 +10,7 @@ import discourseComputed from "discourse-common/utils/decorators";
import { loadTopicView } from "discourse/models/topic"; import { loadTopicView } from "discourse/models/topic";
import { Promise } from "rsvp"; import { Promise } from "rsvp";
import User from "discourse/models/user"; import User from "discourse/models/user";
import { merge } from "discourse-common/lib/object";
export default RestModel.extend({ export default RestModel.extend({
_identityMap: null, _identityMap: null,
@ -274,7 +275,7 @@ export default RestModel.extend({
this.set("loadingFilter", true); this.set("loadingFilter", true);
this.set("loadingNearPost", opts.nearPost); this.set("loadingNearPost", opts.nearPost);
opts = _.merge(opts, this.streamFilters); opts = merge(opts, this.streamFilters);
// Request a topicView // Request a topicView
return loadTopicView(topic, opts) return loadTopicView(topic, opts)
@ -943,7 +944,7 @@ export default RestModel.extend({
include_suggested: includeSuggested include_suggested: includeSuggested
}; };
data = _.merge(data, this.streamFilters); data = merge(data, this.streamFilters);
const store = this.store; const store = this.store;
return ajax(url, { data }).then(result => { return ajax(url, { data }).then(result => {

View File

@ -23,9 +23,10 @@ import { Promise } from "rsvp";
import Site from "discourse/models/site"; import Site from "discourse/models/site";
import User from "discourse/models/user"; import User from "discourse/models/user";
import bootbox from "bootbox"; import bootbox from "bootbox";
import { merge } from "discourse-common/lib/object";
export function loadTopicView(topic, args) { export function loadTopicView(topic, args) {
const data = _.merge({}, args); const data = merge({}, args);
const url = `${getURL("/t/")}${topic.id}`; const url = `${getURL("/t/")}${topic.id}`;
const jsonUrl = (data.nearPost ? `${url}/${data.nearPost}` : url) + ".json"; const jsonUrl = (data.nearPost ? `${url}/${data.nearPost}` : url) + ".json";

View File

@ -1,6 +1,7 @@
import I18n from "I18n"; import I18n from "I18n";
import DiscourseRoute from "discourse/routes/discourse"; import DiscourseRoute from "discourse/routes/discourse";
import PreloadStore from "discourse/lib/preload-store"; import PreloadStore from "discourse/lib/preload-store";
import { merge } from "discourse-common/lib/object";
export default DiscourseRoute.extend({ export default DiscourseRoute.extend({
titleToken() { titleToken() {
@ -10,7 +11,7 @@ export default DiscourseRoute.extend({
model(params) { model(params) {
if (PreloadStore.get("invite_info")) { if (PreloadStore.get("invite_info")) {
return PreloadStore.getAndRemove("invite_info").then(json => return PreloadStore.getAndRemove("invite_info").then(json =>
_.merge(params, json) merge(params, json)
); );
} else { } else {
return {}; return {};

View File

@ -3,6 +3,7 @@ import DiscourseRoute from "discourse/routes/discourse";
import PreloadStore from "discourse/lib/preload-store"; import PreloadStore from "discourse/lib/preload-store";
import { ajax } from "discourse/lib/ajax"; import { ajax } from "discourse/lib/ajax";
import { userPath } from "discourse/lib/url"; import { userPath } from "discourse/lib/url";
import { merge } from "discourse-common/lib/object";
export default DiscourseRoute.extend({ export default DiscourseRoute.extend({
titleToken() { titleToken() {
@ -12,7 +13,7 @@ export default DiscourseRoute.extend({
model(params) { model(params) {
if (PreloadStore.get("password_reset")) { if (PreloadStore.get("password_reset")) {
return PreloadStore.getAndRemove("password_reset").then(json => return PreloadStore.getAndRemove("password_reset").then(json =>
_.merge(params, json) merge(params, json)
); );
} }
}, },

View File

@ -8,6 +8,7 @@ import { iconNode } from "discourse-common/lib/icon-library";
import RawHtml from "discourse/widgets/raw-html"; import RawHtml from "discourse/widgets/raw-html";
import renderTags from "discourse/lib/render-tags"; import renderTags from "discourse/lib/render-tags";
import renderTopicFeaturedLink from "discourse/lib/render-topic-featured-link"; import renderTopicFeaturedLink from "discourse/lib/render-topic-featured-link";
import { merge } from "discourse-common/lib/object";
const SCROLLER_HEIGHT = 50; const SCROLLER_HEIGHT = 50;
const LAST_READ_HEIGHT = 20; const LAST_READ_HEIGHT = 20;
@ -240,7 +241,7 @@ createWidget("timeline-scrollarea", {
this.attach("timeline-padding", { height: before }), this.attach("timeline-padding", { height: before }),
this.attach( this.attach(
"timeline-scroller", "timeline-scroller",
_.merge(position, { merge(position, {
showDockedButton: !attrs.mobileView && hasBackPosition && !showButton, showDockedButton: !attrs.mobileView && hasBackPosition && !showButton,
fullScreen: attrs.fullScreen fullScreen: attrs.fullScreen
}) })

View File

@ -22,6 +22,7 @@ import DecoratorHelper from "discourse/widgets/decorator-helper";
import { Promise } from "rsvp"; import { Promise } from "rsvp";
import { isProduction } from "discourse-common/config/environment"; import { isProduction } from "discourse-common/config/environment";
import { get } from "@ember/object"; import { get } from "@ember/object";
import { merge } from "discourse-common/lib/object";
const _registry = {}; const _registry = {};
@ -185,7 +186,7 @@ export default class Widget {
// Sometimes we pass state down from the parent // Sometimes we pass state down from the parent
if (this.mergeState) { if (this.mergeState) {
this.state = _.merge(this.state, this.mergeState); this.state = merge(this.state, this.mergeState);
} }
if (prev) { if (prev) {

View File

@ -2,6 +2,7 @@ import {
cook as cookIt, cook as cookIt,
setup as setupIt setup as setupIt
} from "pretty-text/engines/discourse-markdown-it"; } from "pretty-text/engines/discourse-markdown-it";
import { merge } from "discourse-common/lib/object";
export function registerOption() { export function registerOption() {
// TODO next major version deprecate this // TODO next major version deprecate this
@ -48,7 +49,7 @@ export function buildOptions(state) {
}; };
if (state.features) { if (state.features) {
features = _.merge(features, state.features); features = merge(features, state.features);
} }
const options = { const options = {

View File

@ -87,6 +87,7 @@ module PrettyText
root_path = "#{Rails.root}/app/assets/javascripts/" root_path = "#{Rails.root}/app/assets/javascripts/"
apply_es6_file(ctx, root_path, "discourse-common/addon/lib/get-url") apply_es6_file(ctx, root_path, "discourse-common/addon/lib/get-url")
apply_es6_file(ctx, root_path, "discourse-common/addon/lib/object")
apply_es6_file(ctx, root_path, "discourse/app/lib/to-markdown") apply_es6_file(ctx, root_path, "discourse/app/lib/to-markdown")
apply_es6_file(ctx, root_path, "discourse/app/lib/utilities") apply_es6_file(ctx, root_path, "discourse/app/lib/utilities")

View File

@ -8,6 +8,7 @@ import {
} from "pretty-text/inline-oneboxer"; } from "pretty-text/inline-oneboxer";
import { extractDataAttribute } from "pretty-text/engines/discourse-markdown-it"; import { extractDataAttribute } from "pretty-text/engines/discourse-markdown-it";
import { registerEmoji } from "pretty-text/emoji"; import { registerEmoji } from "pretty-text/emoji";
import { merge } from "discourse-common/lib/object";
QUnit.module("lib:pretty-text"); QUnit.module("lib:pretty-text");
@ -38,7 +39,7 @@ QUnit.assert.cooked = function(input, expected, message) {
}; };
QUnit.assert.cookedOptions = function(input, opts, expected, message) { QUnit.assert.cookedOptions = function(input, opts, expected, message) {
const merged = _.merge({}, rawOpts, opts); const merged = merge({}, rawOpts, opts);
const actual = new PrettyText(buildOptions(merged)).cook(input); const actual = new PrettyText(buildOptions(merged)).cook(input);
this.pushResult({ this.pushResult({
result: actual === expected, result: actual === expected,

View File

@ -1,11 +1,12 @@
import Post from "discourse/models/post"; import Post from "discourse/models/post";
import User from "discourse/models/user"; import User from "discourse/models/user";
import { merge } from "discourse-common/lib/object";
QUnit.module("model: Post"); QUnit.module("model: Post");
var buildPost = function(args) { var buildPost = function(args) {
return Post.create( return Post.create(
_.merge( merge(
{ {
id: 1, id: 1,
can_delete: true, can_delete: true,