unit tests for provider checks, provider listings, utils and provider meta
This commit is contained in:
parent
391432c1ba
commit
bcf312d1b3
|
@ -1,7 +0,0 @@
|
|||
import { describe, it, expect } from "vitest";
|
||||
|
||||
describe('oof.ts', () => {
|
||||
it('should contain hello', () => {
|
||||
expect('hello').toContain('hello');
|
||||
});
|
||||
});
|
|
@ -0,0 +1,122 @@
|
|||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
import { vi } from 'vitest';
|
||||
|
||||
import { gatherAllEmbeds, gatherAllSources } from '@/providers/all';
|
||||
import { Embed, Sourcerer } from '@/providers/base';
|
||||
|
||||
export function makeProviderMocks() {
|
||||
const embedsMock = vi.fn<Parameters<typeof gatherAllEmbeds>, ReturnType<typeof gatherAllEmbeds>>();
|
||||
const sourcesMock = vi.fn<Parameters<typeof gatherAllSources>, ReturnType<typeof gatherAllSources>>();
|
||||
return {
|
||||
gatherAllEmbeds: embedsMock,
|
||||
gatherAllSources: sourcesMock,
|
||||
};
|
||||
}
|
||||
|
||||
const sourceA = {
|
||||
id: 'a',
|
||||
rank: 1,
|
||||
disabled: false,
|
||||
} as Sourcerer;
|
||||
const sourceB = {
|
||||
id: 'b',
|
||||
rank: 2,
|
||||
disabled: false,
|
||||
} as Sourcerer;
|
||||
const sourceCDisabled = {
|
||||
id: 'c',
|
||||
rank: 3,
|
||||
disabled: true,
|
||||
} as Sourcerer;
|
||||
const sourceAHigherRank = {
|
||||
id: 'a',
|
||||
rank: 100,
|
||||
disabled: false,
|
||||
} as Sourcerer;
|
||||
const sourceGSameRankAsA = {
|
||||
id: 'g',
|
||||
rank: 1,
|
||||
disabled: false,
|
||||
} as Sourcerer;
|
||||
const fullSourceYMovie = {
|
||||
id: 'y',
|
||||
name: 'Y',
|
||||
rank: 105,
|
||||
scrapeMovie: vi.fn(),
|
||||
} as Sourcerer;
|
||||
const fullSourceYShow = {
|
||||
id: 'y',
|
||||
name: 'Y',
|
||||
rank: 105,
|
||||
scrapeShow: vi.fn(),
|
||||
} as Sourcerer;
|
||||
const fullSourceZBoth = {
|
||||
id: 'z',
|
||||
name: 'Z',
|
||||
rank: 106,
|
||||
scrapeMovie: vi.fn(),
|
||||
scrapeShow: vi.fn(),
|
||||
} as Sourcerer;
|
||||
|
||||
const embedD = {
|
||||
id: 'd',
|
||||
rank: 4,
|
||||
disabled: false,
|
||||
} as Embed;
|
||||
const embedA = {
|
||||
id: 'a',
|
||||
rank: 5,
|
||||
disabled: false,
|
||||
} as Embed;
|
||||
const embedEDisabled = {
|
||||
id: 'e',
|
||||
rank: 6,
|
||||
disabled: true,
|
||||
} as Embed;
|
||||
const embedDHigherRank = {
|
||||
id: 'd',
|
||||
rank: 4000,
|
||||
disabled: false,
|
||||
} as Embed;
|
||||
const embedFSameRankAsA = {
|
||||
id: 'f',
|
||||
rank: 5,
|
||||
disabled: false,
|
||||
} as Embed;
|
||||
const embedHSameRankAsSourceA = {
|
||||
id: 'h',
|
||||
rank: 1,
|
||||
disabled: false,
|
||||
} as Embed;
|
||||
const fullEmbedX = {
|
||||
id: 'x',
|
||||
name: 'X',
|
||||
rank: 104,
|
||||
} as Embed;
|
||||
const fullEmbedZ = {
|
||||
id: 'z',
|
||||
name: 'Z',
|
||||
rank: 109,
|
||||
} as Embed;
|
||||
|
||||
export const mockSources = {
|
||||
sourceA,
|
||||
sourceB,
|
||||
sourceCDisabled,
|
||||
sourceAHigherRank,
|
||||
sourceGSameRankAsA,
|
||||
fullSourceYMovie,
|
||||
fullSourceYShow,
|
||||
fullSourceZBoth,
|
||||
};
|
||||
|
||||
export const mockEmbeds = {
|
||||
embedA,
|
||||
embedD,
|
||||
embedDHigherRank,
|
||||
embedEDisabled,
|
||||
embedFSameRankAsA,
|
||||
embedHSameRankAsSourceA,
|
||||
fullEmbedX,
|
||||
fullEmbedZ,
|
||||
};
|
|
@ -0,0 +1,63 @@
|
|||
import { mockEmbeds, mockSources } from '@/__test__/providerTests';
|
||||
import { getProviders } from '@/providers/get';
|
||||
import { vi, describe, it, expect, afterEach } from 'vitest';
|
||||
|
||||
const mocks = await vi.hoisted(async () => (await import('@/__test__/providerTests')).makeProviderMocks());
|
||||
vi.mock('@/providers/all', () => mocks);
|
||||
|
||||
describe('getProviders()', () => {
|
||||
afterEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should return providers', () => {
|
||||
mocks.gatherAllEmbeds.mockReturnValue([mockEmbeds.embedD]);
|
||||
mocks.gatherAllSources.mockReturnValue([mockSources.sourceA, mockSources.sourceB]);
|
||||
expect(getProviders()).toEqual({
|
||||
sources: [mockSources.sourceA, mockSources.sourceB],
|
||||
embeds: [mockEmbeds.embedD],
|
||||
});
|
||||
});
|
||||
|
||||
it('should filter out disabled providers', () => {
|
||||
mocks.gatherAllEmbeds.mockReturnValue([mockEmbeds.embedD, mockEmbeds.embedEDisabled]);
|
||||
mocks.gatherAllSources.mockReturnValue([mockSources.sourceA, mockSources.sourceCDisabled, mockSources.sourceB]);
|
||||
expect(getProviders()).toEqual({
|
||||
sources: [mockSources.sourceA, mockSources.sourceB],
|
||||
embeds: [mockEmbeds.embedD],
|
||||
});
|
||||
});
|
||||
|
||||
it('should throw on duplicate ids in sources', () => {
|
||||
mocks.gatherAllEmbeds.mockReturnValue([]);
|
||||
mocks.gatherAllSources.mockReturnValue([mockSources.sourceAHigherRank, mockSources.sourceA, mockSources.sourceB]);
|
||||
expect(() => getProviders()).toThrowError();
|
||||
});
|
||||
|
||||
it('should throw on duplicate ids in embeds', () => {
|
||||
mocks.gatherAllEmbeds.mockReturnValue([mockEmbeds.embedD, mockEmbeds.embedDHigherRank, mockEmbeds.embedA]);
|
||||
mocks.gatherAllSources.mockReturnValue([]);
|
||||
expect(() => getProviders()).toThrowError();
|
||||
});
|
||||
|
||||
it('should throw on duplicate ids between sources and embeds', () => {
|
||||
mocks.gatherAllEmbeds.mockReturnValue([mockEmbeds.embedD, mockEmbeds.embedA]);
|
||||
mocks.gatherAllSources.mockReturnValue([mockSources.sourceA, mockSources.sourceB]);
|
||||
expect(() => getProviders()).toThrowError();
|
||||
});
|
||||
|
||||
it('should throw on duplicate rank between sources and embeds', () => {
|
||||
mocks.gatherAllEmbeds.mockReturnValue([mockEmbeds.embedD, mockEmbeds.embedA]);
|
||||
mocks.gatherAllSources.mockReturnValue([mockSources.sourceA, mockSources.sourceB]);
|
||||
expect(() => getProviders()).toThrowError();
|
||||
});
|
||||
|
||||
it('should not throw with same rank between sources and embeds', () => {
|
||||
mocks.gatherAllEmbeds.mockReturnValue([mockEmbeds.embedD, mockEmbeds.embedHSameRankAsSourceA]);
|
||||
mocks.gatherAllSources.mockReturnValue([mockSources.sourceA, mockSources.sourceB]);
|
||||
expect(getProviders()).toEqual({
|
||||
sources: [mockSources.sourceA, mockSources.sourceB],
|
||||
embeds: [mockEmbeds.embedD, mockEmbeds.embedHSameRankAsSourceA],
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,121 @@
|
|||
import { mockEmbeds, mockSources } from '@/__test__/providerTests';
|
||||
import { makeProviders } from '@/main/builder';
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
const mocks = await vi.hoisted(async () => (await import('@/__test__/providerTests')).makeProviderMocks());
|
||||
vi.mock('@/providers/all', () => mocks);
|
||||
|
||||
describe('ProviderControls.listSources()', () => {
|
||||
afterEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should return the source with movie type', () => {
|
||||
mocks.gatherAllSources.mockReturnValue([mockSources.fullSourceYMovie]);
|
||||
mocks.gatherAllEmbeds.mockReturnValue([]);
|
||||
const p = makeProviders({
|
||||
fetcher: null as any,
|
||||
});
|
||||
expect(p.listSources()).toEqual([
|
||||
{
|
||||
type: 'source',
|
||||
id: 'y',
|
||||
rank: mockSources.fullSourceYMovie.rank,
|
||||
name: 'Y',
|
||||
mediaTypes: ['movie'],
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('should return the source with show type', () => {
|
||||
mocks.gatherAllSources.mockReturnValue([mockSources.fullSourceYShow]);
|
||||
mocks.gatherAllEmbeds.mockReturnValue([]);
|
||||
const p = makeProviders({
|
||||
fetcher: null as any,
|
||||
});
|
||||
expect(p.listSources()).toEqual([
|
||||
{
|
||||
type: 'source',
|
||||
id: 'y',
|
||||
rank: mockSources.fullSourceYShow.rank,
|
||||
name: 'Y',
|
||||
mediaTypes: ['show'],
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('should return the source with both types', () => {
|
||||
mocks.gatherAllSources.mockReturnValue([mockSources.fullSourceZBoth]);
|
||||
mocks.gatherAllEmbeds.mockReturnValue([]);
|
||||
const p = makeProviders({
|
||||
fetcher: null as any,
|
||||
});
|
||||
expect(p.listSources()).toEqual([
|
||||
{
|
||||
type: 'source',
|
||||
id: 'z',
|
||||
rank: mockSources.fullSourceZBoth.rank,
|
||||
name: 'Z',
|
||||
mediaTypes: ['movie', 'show'],
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('should return the sources in correct order', () => {
|
||||
mocks.gatherAllSources.mockReturnValue([mockSources.fullSourceYMovie, mockSources.fullSourceZBoth]);
|
||||
mocks.gatherAllEmbeds.mockReturnValue([]);
|
||||
const p1 = makeProviders({
|
||||
fetcher: null as any,
|
||||
});
|
||||
const l1 = p1.listSources();
|
||||
expect(l1.map((v) => v.id).join(',')).toEqual('z,y');
|
||||
|
||||
mocks.gatherAllSources.mockReturnValue([mockSources.fullSourceZBoth, mockSources.fullSourceYMovie]);
|
||||
mocks.gatherAllEmbeds.mockReturnValue([]);
|
||||
const p2 = makeProviders({
|
||||
fetcher: null as any,
|
||||
});
|
||||
const l2 = p2.listSources();
|
||||
expect(l2.map((v) => v.id).join(',')).toEqual('z,y');
|
||||
});
|
||||
});
|
||||
|
||||
describe('ProviderControls.getAllEmbedMetaSorted()', () => {
|
||||
afterEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should return the correct embed format', () => {
|
||||
mocks.gatherAllSources.mockReturnValue([]);
|
||||
mocks.gatherAllEmbeds.mockReturnValue([mockEmbeds.fullEmbedX]);
|
||||
const p = makeProviders({
|
||||
fetcher: null as any,
|
||||
});
|
||||
expect(p.listEmbeds()).toEqual([
|
||||
{
|
||||
type: 'embed',
|
||||
id: 'x',
|
||||
rank: mockEmbeds.fullEmbedX.rank,
|
||||
name: 'X',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('should return the embeds in correct order', () => {
|
||||
mocks.gatherAllSources.mockReturnValue([]);
|
||||
mocks.gatherAllEmbeds.mockReturnValue([mockEmbeds.fullEmbedX, mockEmbeds.fullEmbedZ]);
|
||||
const p1 = makeProviders({
|
||||
fetcher: null as any,
|
||||
});
|
||||
const l1 = p1.listEmbeds();
|
||||
expect(l1.map((v) => v.id).join(',')).toEqual('z,x');
|
||||
|
||||
mocks.gatherAllSources.mockReturnValue([]);
|
||||
mocks.gatherAllEmbeds.mockReturnValue([mockEmbeds.fullEmbedZ, mockEmbeds.fullEmbedX]);
|
||||
const p2 = makeProviders({
|
||||
fetcher: null as any,
|
||||
});
|
||||
const l2 = p2.listEmbeds();
|
||||
expect(l2.map((v) => v.id).join(',')).toEqual('z,x');
|
||||
});
|
||||
});
|
|
@ -0,0 +1,50 @@
|
|||
import { mockEmbeds, mockSources } from '@/__test__/providerTests';
|
||||
import { makeProviders } from '@/main/builder';
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
const mocks = await vi.hoisted(async () => (await import('@/__test__/providerTests')).makeProviderMocks());
|
||||
vi.mock('@/providers/all', () => mocks);
|
||||
|
||||
describe('ProviderControls.getMetadata()', () => {
|
||||
afterEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should return null if not found', () => {
|
||||
mocks.gatherAllSources.mockReturnValue([]);
|
||||
mocks.gatherAllEmbeds.mockReturnValue([]);
|
||||
const p = makeProviders({
|
||||
fetcher: null as any,
|
||||
});
|
||||
expect(p.getMetadata(':)')).toEqual(null);
|
||||
});
|
||||
|
||||
it('should return correct source meta', () => {
|
||||
mocks.gatherAllSources.mockReturnValue([mockSources.fullSourceZBoth]);
|
||||
mocks.gatherAllEmbeds.mockReturnValue([]);
|
||||
const p = makeProviders({
|
||||
fetcher: null as any,
|
||||
});
|
||||
expect(p.getMetadata(mockSources.fullSourceZBoth.id)).toEqual({
|
||||
type: 'source',
|
||||
id: 'z',
|
||||
name: 'Z',
|
||||
rank: mockSources.fullSourceZBoth.rank,
|
||||
mediaTypes: ['movie', 'show'],
|
||||
});
|
||||
});
|
||||
|
||||
it('should return correct embed meta', () => {
|
||||
mocks.gatherAllSources.mockReturnValue([]);
|
||||
mocks.gatherAllEmbeds.mockReturnValue([mockEmbeds.fullEmbedX]);
|
||||
const p = makeProviders({
|
||||
fetcher: null as any,
|
||||
});
|
||||
expect(p.getMetadata(mockEmbeds.fullEmbedX.id)).toEqual({
|
||||
type: 'embed',
|
||||
id: 'x',
|
||||
name: 'X',
|
||||
rank: mockEmbeds.fullEmbedX.rank,
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,54 @@
|
|||
import { reorderOnIdList } from "@/utils/list";
|
||||
import { describe, it, expect } from "vitest";
|
||||
|
||||
function list(def: string) {
|
||||
return def.split(",").map(v=>({
|
||||
rank: parseInt(v),
|
||||
id: v,
|
||||
}))
|
||||
}
|
||||
|
||||
function expectListToEqual(l1: ReturnType<typeof list>, l2: ReturnType<typeof list>) {
|
||||
function flatten(l: ReturnType<typeof list>) {
|
||||
return l.map(v=>v.id).join(",");
|
||||
}
|
||||
expect(flatten(l1)).toEqual(flatten(l2));
|
||||
}
|
||||
|
||||
describe('reorderOnIdList()', () => {
|
||||
it('should reorder based on rank', () => {
|
||||
const l = list('2,1,4,3');
|
||||
const sortedList = list('4,3,2,1')
|
||||
expectListToEqual(reorderOnIdList([], l), sortedList);
|
||||
});
|
||||
|
||||
it('should work with empty input', () => {
|
||||
expectListToEqual(reorderOnIdList([], []), []);
|
||||
});
|
||||
|
||||
it('should reorder based on id list', () => {
|
||||
const l = list('4,2,1,3');
|
||||
const sortedList = list('4,3,2,1')
|
||||
expectListToEqual(reorderOnIdList(["4","3","2","1"], l), sortedList);
|
||||
});
|
||||
|
||||
it('should reorder based on id list and rank second', () => {
|
||||
const l = list('4,2,1,3');
|
||||
const sortedList = list('4,3,2,1')
|
||||
expectListToEqual(reorderOnIdList(["4","3"], l), sortedList);
|
||||
});
|
||||
|
||||
it('should work with only one item', () => {
|
||||
const l = list('1');
|
||||
const sortedList = list('1')
|
||||
expectListToEqual(reorderOnIdList(["1"], l), sortedList);
|
||||
expectListToEqual(reorderOnIdList([], l), sortedList);
|
||||
});
|
||||
|
||||
it('should not affect original list', () => {
|
||||
const l = list('4,3,2,1');
|
||||
const unsortedList = list('4,3,2,1')
|
||||
reorderOnIdList([], l);
|
||||
expectListToEqual(l, unsortedList);
|
||||
});
|
||||
});
|
|
@ -4,7 +4,7 @@ import { FullScraperEvents } from '@/main/events';
|
|||
import { ScrapeMedia } from '@/main/media';
|
||||
import { MetaOutput, getAllEmbedMetaSorted, getAllSourceMetaSorted, getSpecificId } from '@/main/meta';
|
||||
import { RunOutput, runAllProviders } from '@/main/runner';
|
||||
import { getProviders } from '@/providers/all';
|
||||
import { getProviders } from '@/providers/get';
|
||||
|
||||
export interface ProviderBuilderOptions {
|
||||
// fetcher, every web request gets called through here
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { MediaTypes } from '@/main/media';
|
||||
import { ProviderList } from '@/providers/all';
|
||||
import { Embed, Sourcerer } from '@/providers/base';
|
||||
import { ProviderList } from '@/providers/get';
|
||||
|
||||
export type MetaOutput = {
|
||||
type: 'embed' | 'source';
|
||||
|
@ -9,36 +10,45 @@ export type MetaOutput = {
|
|||
mediaTypes?: Array<MediaTypes>;
|
||||
};
|
||||
|
||||
export function getAllSourceMetaSorted(list: ProviderList): MetaOutput[] {
|
||||
return list.sources
|
||||
.sort((a, b) => b.rank - a.rank)
|
||||
.map((v) => {
|
||||
const types: Array<MediaTypes> = [];
|
||||
if (v.scrapeMovie) types.push('movie');
|
||||
if (v.scrapeShow) types.push('show');
|
||||
return {
|
||||
type: 'source',
|
||||
id: v.id,
|
||||
rank: v.rank,
|
||||
name: v.name,
|
||||
mediaTypes: types,
|
||||
};
|
||||
});
|
||||
function formatSourceMeta(v: Sourcerer): MetaOutput {
|
||||
const types: Array<MediaTypes> = [];
|
||||
if (v.scrapeMovie) types.push('movie');
|
||||
if (v.scrapeShow) types.push('show');
|
||||
return {
|
||||
type: 'source',
|
||||
id: v.id,
|
||||
rank: v.rank,
|
||||
name: v.name,
|
||||
mediaTypes: types,
|
||||
};
|
||||
}
|
||||
|
||||
export function getAllEmbedMetaSorted(_list: ProviderList): MetaOutput[] {
|
||||
return [];
|
||||
function formatEmbedMeta(v: Embed): MetaOutput {
|
||||
return {
|
||||
type: 'embed',
|
||||
id: v.id,
|
||||
rank: v.rank,
|
||||
name: v.name,
|
||||
};
|
||||
}
|
||||
|
||||
export function getAllSourceMetaSorted(list: ProviderList): MetaOutput[] {
|
||||
return list.sources.sort((a, b) => b.rank - a.rank).map(formatSourceMeta);
|
||||
}
|
||||
|
||||
export function getAllEmbedMetaSorted(list: ProviderList): MetaOutput[] {
|
||||
return list.embeds.sort((a, b) => b.rank - a.rank).map(formatEmbedMeta);
|
||||
}
|
||||
|
||||
export function getSpecificId(list: ProviderList, id: string): MetaOutput | null {
|
||||
const foundSource = list.sources.find((v) => v.id === id);
|
||||
if (foundSource) {
|
||||
return {
|
||||
type: 'source',
|
||||
id: foundSource.id,
|
||||
name: foundSource.name,
|
||||
rank: foundSource.rank,
|
||||
};
|
||||
return formatSourceMeta(foundSource);
|
||||
}
|
||||
|
||||
const foundEmbed = list.embeds.find((v) => v.id === id);
|
||||
if (foundEmbed) {
|
||||
return formatEmbedMeta(foundEmbed);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
|
|
@ -1,38 +1,13 @@
|
|||
import { Embed, Sourcerer } from '@/providers/base';
|
||||
import { upcloudScraper } from '@/providers/embeds/upcloud';
|
||||
import { flixhqScraper } from '@/providers/sources/flixhq/index';
|
||||
import { hasDuplicates } from '@/utils/predicates';
|
||||
|
||||
function gatherAllSources(): Array<Sourcerer> {
|
||||
export function gatherAllSources(): Array<Sourcerer> {
|
||||
// all sources are gathered here
|
||||
return [flixhqScraper];
|
||||
}
|
||||
|
||||
function gatherAllEmbeds(): Array<Embed> {
|
||||
export function gatherAllEmbeds(): Array<Embed> {
|
||||
// all embeds are gathered here
|
||||
return [upcloudScraper];
|
||||
}
|
||||
|
||||
export interface ProviderList {
|
||||
sources: Sourcerer[];
|
||||
embeds: Embed[];
|
||||
}
|
||||
|
||||
export function getProviders(): ProviderList {
|
||||
const sources = gatherAllSources().filter((v) => !v?.disabled);
|
||||
const embeds = gatherAllEmbeds().filter((v) => !v?.disabled);
|
||||
const combined = [...sources, ...embeds];
|
||||
|
||||
const anyDuplicateId = hasDuplicates(combined.map((v) => v.id));
|
||||
const anyDuplicateSourceRank = hasDuplicates(sources.map((v) => v.rank));
|
||||
const anyDuplicateEmbedRank = hasDuplicates(embeds.map((v) => v.rank));
|
||||
|
||||
if (anyDuplicateId) throw new Error('Duplicate id found in sources/embeds');
|
||||
if (anyDuplicateSourceRank) throw new Error('Duplicate rank found in sources');
|
||||
if (anyDuplicateEmbedRank) throw new Error('Duplicate rank found in embeds');
|
||||
|
||||
return {
|
||||
sources,
|
||||
embeds,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
import { gatherAllEmbeds, gatherAllSources } from '@/providers/all';
|
||||
import { Embed, Sourcerer } from '@/providers/base';
|
||||
import { hasDuplicates } from '@/utils/predicates';
|
||||
|
||||
export interface ProviderList {
|
||||
sources: Sourcerer[];
|
||||
embeds: Embed[];
|
||||
}
|
||||
|
||||
export function getProviders(): ProviderList {
|
||||
const sources = gatherAllSources().filter((v) => !v?.disabled);
|
||||
const embeds = gatherAllEmbeds().filter((v) => !v?.disabled);
|
||||
const combined = [...sources, ...embeds];
|
||||
|
||||
const anyDuplicateId = hasDuplicates(combined.map((v) => v.id));
|
||||
const anyDuplicateSourceRank = hasDuplicates(sources.map((v) => v.rank));
|
||||
const anyDuplicateEmbedRank = hasDuplicates(embeds.map((v) => v.rank));
|
||||
|
||||
if (anyDuplicateId) throw new Error('Duplicate id found in sources/embeds');
|
||||
if (anyDuplicateSourceRank) throw new Error('Duplicate rank found in sources');
|
||||
if (anyDuplicateEmbedRank) throw new Error('Duplicate rank found in embeds');
|
||||
|
||||
return {
|
||||
sources,
|
||||
embeds,
|
||||
};
|
||||
}
|
|
@ -10,8 +10,8 @@ export function reorderOnIdList<T extends { rank: number; id: string }[]>(order:
|
|||
// only one in order list
|
||||
// negative means order [a,b]
|
||||
// positive means order [b,a]
|
||||
if (aIndex < 0) return 1; // A isnt in list, so A goes later on the list
|
||||
if (bIndex < 0) return -1; // B isnt in list, so B goes later on the list
|
||||
if (bIndex >= 0) return 1; // A isnt in list but B is, so A goes later on the list
|
||||
if (aIndex >= 0) return -1; // B isnt in list but A is, so B goes later on the list
|
||||
|
||||
// both not in list, sort on rank
|
||||
return b.rank - a.rank;
|
||||
|
|
Loading…
Reference in New Issue