Skip to content

Commit

Permalink
fix(helpers): update merge.ts
Browse files Browse the repository at this point in the history
  • Loading branch information
kitce committed Mar 20, 2022
1 parent 8caf62f commit 4cee1da
Show file tree
Hide file tree
Showing 7 changed files with 95 additions and 15 deletions.
5 changes: 4 additions & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node'
testEnvironment: 'jsdom',
moduleNameMapper: {
'\\.module\\.s?css$': 'identity-obj-proxy'
}
};
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
"css-loader": "^5.2.0",
"cssnano": "^5.1.4",
"dotenv": "^10.0.0",
"identity-obj-proxy": "^3.0.0",
"jest": "^27.5.1",
"postcss": "^8.2.9",
"postcss-loader": "^5.2.0",
Expand Down
13 changes: 13 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

35 changes: 30 additions & 5 deletions src/helpers/label.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { shortenedHost } from '../constants/lihkg';
import { IDataSet } from '../models/DataSet';
import { IGroupedLabel } from '../types/label';
import { IPost } from '../types/lihkg';
import { ILabel, ISource } from './../models/Label';
import { TTracablePost } from './../types/lihkg';
import type { IDataSet } from '../models/DataSet';
import type { IGroupedLabel } from '../types/label';
import type { IPost } from '../types/lihkg';
import type { ILabel, ISource } from './../models/Label';
import type { TTracablePost } from './../types/lihkg';
import { counter } from './counter';
import { getShareID } from './lihkg';

Expand Down Expand Up @@ -63,3 +63,28 @@ export const groupByText = (user: string, dataSets: IDataSet[]) => {
return groupedLabels;
}, []);
};

/**
* compare two label objects to check equality
* @param {ILabel} labelA the target A to be compare
* @param {ILabel} labelB the target B to be compare
* @param {boolean} [strict=true] enable strict equality checking
*/
export const isEqual = (labelA: ILabel, labelB: ILabel, strict = false) => {
if (labelA.id && labelB.id) {
// `id` determines everything
return labelA.id === labelB.id;
}
/**
* either one of them is stale
* attempt to compare something else
*/
return (
labelA.text === labelB.text
&& (
strict ? (
labelA.reason === labelB.reason
) : true
)
);
};
31 changes: 31 additions & 0 deletions src/helpers/merge.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,37 @@ describe('mergeDataSet', () => {
expect(merged.data['2']![0]).toBe(dataSetB.data['2']![0]);
expect(merged.data['2']![1]).toBe(dataSetB.data['2']![1]);
});

it('should have 1 user, 3 labels', () => {
const dataSetA: IDataSet = {
data: {
'1': [
{ text: 'Label 1A', reason: 'Reason A' },
{ text: 'Label 1A', reason: 'Reason B' },
{ text: 'Label 1B' }
]
}
};
const dataSetB: IDataSet = {
data: {
'1': [
{ id: '1', text: 'Label 1A', reason: 'Reason A' },
{ id: '2', text: 'Label 1A', reason: 'Reason B' },
{ id: '3', text: 'Label 1B' }
]
}
};
const merged = mergeDataSet(dataSetA, dataSetB, true);
expect(Object.keys(merged.data).length).toBe(1);
const mergedLabels = merged.data['1']!;
expect(mergedLabels.length).toBe(3);
for (let i = 0; i < mergedLabels.length; i++) {
const mergedLabel = mergedLabels[i];
expect(mergedLabel.id).toEqual(dataSetA.data['1']![i].id);
expect(mergedLabel.text).toEqual(dataSetB.data['1']![i].text);
expect(mergedLabel.reason).toEqual(dataSetB.data['1']![i].reason);
}
});
});

describe('mergeSubscriptions', () => {
Expand Down
20 changes: 11 additions & 9 deletions src/helpers/merge.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { produce } from 'immer';
import { IDataSet } from '../models/DataSet';
import { ISerializedSubscription } from './../models/Subscription';
import type { IDataSet } from '../models/DataSet';
import type { ISerializedSubscription } from './../models/Subscription';
import { isEqual as isLabelEqual } from './label';
import { isEqual as isSubscriptionEqual } from './subscription';

export enum MergeDirection {
IncomingToLocal,
Expand All @@ -26,16 +28,16 @@ export const mergeDataSet = <T extends IDataSet> (dataSetA: T, dataSetB: T, prun
/** existing user in B */
if (labelsB) {
if (prune) {
/** prune the missing A */
/** prune the missing B in A */
dataA[userA] = dataA[userA]?.filter((labelA) => {
const labelB = labelsB.find((labelB) => labelB.id === labelA.id || labelB.text === labelA.text);
const labelB = labelsB.find((labelB) => isLabelEqual(labelA, labelB));
return !!labelB;
});
}
/** merge B into A */
const labelsA = dataA[userA]!;
for (const labelB of labelsB) {
const labelA = labelsA.find((labelA) => labelA.id === labelB.id || labelA.text === labelB.text);
const labelA = labelsA.find((labelA) => isLabelEqual(labelA, labelB, true));
if (labelA) {
/** existing label */
labelA.text = labelB.text;
Expand Down Expand Up @@ -73,23 +75,23 @@ export const mergeDataSet = <T extends IDataSet> (dataSetA: T, dataSetB: T, prun
* @returns {ISerializedSubscription[]}
*/
export const mergeSubscriptions = (subscriptionsA: ISerializedSubscription[], subscriptionsB: ISerializedSubscription[], prune: boolean): ISerializedSubscription[] => {
/** prune the missing A */
/** prune the missing B in A */
const _subscriptionsA = !prune ? subscriptionsA : subscriptionsA.filter((subscriptionA) => {
const subscriptionB = subscriptionsB.find(({ url }) => url === subscriptionA.url);
const subscriptionB = subscriptionsB.find((subscriptionB) => isSubscriptionEqual(subscriptionA, subscriptionB));
return !!subscriptionB;
});
return produce(_subscriptionsA, (subscriptionsA) => {
/** existing subscriptions */
for (const subscriptionA of subscriptionsA) {
const subscriptionB = subscriptionsB.find((subscriptionB) => subscriptionB.url === subscriptionA.url);
const subscriptionB = subscriptionsB.find((subscriptionB) => isSubscriptionEqual(subscriptionA, subscriptionB));
if (subscriptionB) {
subscriptionA.name = subscriptionB.name;
subscriptionA.enabled = subscriptionB.enabled;
}
}
/** new subscriptions */
for (const subscriptionB of subscriptionsB) {
const subscriptionA = subscriptionsA.find((subscriptionA) => subscriptionA.url === subscriptionB.url);
const subscriptionA = subscriptionsA.find((subscriptionA) => isSubscriptionEqual(subscriptionA, subscriptionB));
if (!subscriptionA) {
subscriptionsA.push(subscriptionB);
}
Expand Down
5 changes: 5 additions & 0 deletions src/helpers/subscription.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import { SUBSCRIPTION_MESSAGE_QUESTION_ADD } from '../constants/texts';
import type { ISerializedSubscription } from '../models/Subscription';

export const prompt = () => {
const url = window.prompt(SUBSCRIPTION_MESSAGE_QUESTION_ADD);
return url;
};

export const isEqual = (subscriptionA: ISerializedSubscription, subscriptionB: ISerializedSubscription) => {
return subscriptionA.url === subscriptionB.url;
};

0 comments on commit 4cee1da

Please sign in to comment.