@genspectrum/dashboard-components 0.6.18 → 0.6.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -12
- package/custom-elements.json +4 -4
- package/dist/assets/mutationOverTimeWorker-BdzqDqvO.js.map +1 -0
- package/dist/dashboard-components.js +216 -214
- package/dist/dashboard-components.js.map +1 -1
- package/dist/genspectrum-components.d.ts +40 -40
- package/dist/style.css +3 -2
- package/package.json +13 -2
- package/src/operator/FetchInsertionsOperator.ts +2 -2
- package/src/operator/FetchSubstitutionsOrDeletionsOperator.ts +3 -3
- package/src/preact/mutationComparison/fetchMutationData.spec.ts +3 -3
- package/src/preact/mutationComparison/getMutationComparisonTableData.spec.ts +11 -11
- package/src/preact/mutationComparison/getMutationComparisonTableData.ts +4 -4
- package/src/preact/mutationComparison/mutation-comparison-table.tsx +2 -2
- package/src/preact/mutationFilter/mutation-filter.tsx +27 -18
- package/src/preact/mutationFilter/parseAndValidateMutation.ts +4 -4
- package/src/preact/mutationFilter/parseMutation.spec.ts +17 -17
- package/src/preact/mutations/getInsertionsTableData.spec.ts +3 -3
- package/src/preact/mutations/getMutationsGridData.spec.ts +9 -9
- package/src/preact/mutations/getMutationsTableData.spec.ts +7 -7
- package/src/preact/mutations/mutations-insertions-table.tsx +3 -3
- package/src/preact/mutations/mutations-table.tsx +3 -3
- package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutationsByDay.ts +45686 -0
- package/src/preact/mutationsOverTime/__mockData__/byWeek.ts +58989 -0
- package/src/preact/mutationsOverTime/__mockData__/defaultMockData.ts +103991 -0
- package/src/preact/mutationsOverTime/__mockData__/mockConversion.ts +54 -0
- package/src/preact/mutationsOverTime/__mockData__/showsMessageWhenTooManyMutations.ts +63690 -0
- package/src/preact/mutationsOverTime/getFilteredMutationsOverTime.spec.ts +176 -159
- package/src/preact/mutationsOverTime/getFilteredMutationsOverTimeData.ts +17 -59
- package/src/preact/mutationsOverTime/mutationOverTimeWorker.mock.ts +27 -0
- package/src/preact/mutationsOverTime/mutationOverTimeWorker.ts +29 -0
- package/src/preact/mutationsOverTime/mutations-over-time-grid.tsx +13 -14
- package/src/preact/mutationsOverTime/mutations-over-time.stories.tsx +9 -334
- package/src/preact/mutationsOverTime/mutations-over-time.tsx +68 -52
- package/src/preact/numberSequencesOverTime/getNumberOfSequencesOverTimeTableData.ts +3 -3
- package/src/preact/prevalenceOverTime/getPrevalenceOverTimeTableData.spec.ts +5 -5
- package/src/preact/prevalenceOverTime/prevalence-over-time-bubble-chart.tsx +1 -1
- package/src/preact/relativeGrowthAdvantage/relative-growth-advantage-chart.tsx +2 -2
- package/src/preact/shared/sort/sortInsertions.spec.ts +11 -11
- package/src/preact/shared/sort/sortInsertions.ts +2 -2
- package/src/preact/shared/sort/sortSubstitutionsAndDeletions.spec.ts +13 -13
- package/src/preact/shared/sort/sortSubstitutionsAndDeletions.ts +7 -4
- package/src/preact/webWorkers/useWebWorker.ts +51 -0
- package/src/preact/webWorkers/workerFunction.ts +14 -0
- package/src/query/queryAggregatedDataOverTime.ts +3 -3
- package/src/query/queryMutationsOverTime.spec.ts +272 -51
- package/src/query/queryMutationsOverTime.ts +114 -45
- package/src/query/queryPrevalenceOverTime.ts +2 -2
- package/src/query/queryRelativeGrowthAdvantage.ts +3 -3
- package/src/types.ts +25 -5
- package/src/utils/map2d.spec.ts +29 -1
- package/src/utils/map2d.ts +22 -1
- package/src/utils/mutations.spec.ts +20 -20
- package/src/utils/mutations.ts +80 -17
- package/src/utils/sort.ts +5 -2
- package/src/utils/temporal.spec.ts +27 -24
- package/src/utils/{temporal.ts → temporalClass.ts} +170 -72
- package/src/utils/temporalTestHelpers.ts +3 -3
- package/src/web-components/introduction.mdx +46 -0
- package/src/web-components/visualization/gs-mutations-over-time.stories.ts +6 -699
- package/src/web-components/visualization/gs-mutations-over-time.tsx +2 -2
- package/standalone-bundle/dashboard-components.js +13763 -13754
- package/standalone-bundle/dashboard-components.js.map +1 -1
- package/src/preact/mutationsOverTime/__mockData__/aggregated_2024_01.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_2024_02.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_2024_03.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_2024_04.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_2024_05.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_2024_06.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_2024_07.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_20_01_2024.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_21_01_2024.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_22_01_2024.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_23_01_2024.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_24_01_2024.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_25_01_2024.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_26_01_2024.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_byDay.json +0 -38
- package/src/preact/mutationsOverTime/__mockData__/aggregated_byWeek.json +0 -122
- package/src/preact/mutationsOverTime/__mockData__/aggregated_date.json +0 -642
- package/src/preact/mutationsOverTime/__mockData__/aggregated_tooManyMutations.json +0 -1470
- package/src/preact/mutationsOverTime/__mockData__/aggregated_tooManyMutations_total.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_week3_2024.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_week4_2024.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_week5_2024.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_week6_2024.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutations_20_01_2024.json +0 -6778
- package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutations_21_01_2024.json +0 -7129
- package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutations_22_01_2024.json +0 -4681
- package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutations_23_01_2024.json +0 -10738
- package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutations_24_01_2024.json +0 -11710
- package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutations_25_01_2024.json +0 -11557
- package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutations_26_01_2024.json +0 -8596
- package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutations_byDayOverall.json +0 -4726
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_2024_01.json +0 -1747
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_2024_02.json +0 -1774
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_2024_03.json +0 -1819
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_2024_04.json +0 -1864
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_2024_05.json +0 -1927
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_2024_06.json +0 -1864
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_2024_07.json +0 -9
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_byMonthOverall.json +0 -11143
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_byWeekOverall.json +0 -9154
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_tooManyMutations.json +0 -16453
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_week3_2024.json +0 -8812
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_week4_2024.json +0 -9730
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_week5_2024.json +0 -9865
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_week6_2024.json +0 -11314
|
@@ -2,7 +2,7 @@ import { FetchAggregatedOperator } from '../operator/FetchAggregatedOperator';
|
|
|
2
2
|
import { MapOperator } from '../operator/MapOperator';
|
|
3
3
|
import { RenameFieldOperator } from '../operator/RenameFieldOperator';
|
|
4
4
|
import { type LapisFilter } from '../types';
|
|
5
|
-
import { getMinMaxTemporal, TemporalCache, type
|
|
5
|
+
import { getMinMaxTemporal, TemporalCache, type YearMonthDayClass } from '../utils/temporalClass';
|
|
6
6
|
|
|
7
7
|
export type RelativeGrowthAdvantageData = Awaited<ReturnType<typeof queryRelativeGrowthAdvantage>>;
|
|
8
8
|
|
|
@@ -33,13 +33,13 @@ export async function queryRelativeGrowthAdvantage<LapisDateField extends string
|
|
|
33
33
|
return null;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
const numeratorCounts = new Map<
|
|
36
|
+
const numeratorCounts = new Map<YearMonthDayClass, number>();
|
|
37
37
|
numeratorData.content.forEach((d) => {
|
|
38
38
|
if (d.date) {
|
|
39
39
|
numeratorCounts.set(d.date, d.count);
|
|
40
40
|
}
|
|
41
41
|
});
|
|
42
|
-
const denominatorCounts = new Map<
|
|
42
|
+
const denominatorCounts = new Map<YearMonthDayClass, number>();
|
|
43
43
|
const requestData = {
|
|
44
44
|
t: [] as number[],
|
|
45
45
|
n: [] as number[],
|
package/src/types.ts
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
type Deletion,
|
|
3
|
+
type DeletionClass,
|
|
4
|
+
type Insertion,
|
|
5
|
+
type InsertionClass,
|
|
6
|
+
type Substitution,
|
|
7
|
+
type SubstitutionClass,
|
|
8
|
+
} from './utils/mutations';
|
|
2
9
|
|
|
3
10
|
export type LapisFilter = Record<string, string | number | null | boolean>;
|
|
4
11
|
|
|
@@ -15,12 +22,25 @@ export type SubstitutionOrDeletion = 'substitution' | 'deletion';
|
|
|
15
22
|
|
|
16
23
|
export type MutationType = SubstitutionOrDeletion | 'insertion';
|
|
17
24
|
|
|
18
|
-
export type SubstitutionEntry
|
|
25
|
+
export type SubstitutionEntry<T extends Substitution = SubstitutionClass> = {
|
|
26
|
+
type: 'substitution';
|
|
27
|
+
mutation: T;
|
|
28
|
+
count: number;
|
|
29
|
+
proportion: number;
|
|
30
|
+
};
|
|
19
31
|
|
|
20
|
-
export type DeletionEntry
|
|
32
|
+
export type DeletionEntry<T extends Deletion = DeletionClass> = {
|
|
33
|
+
type: 'deletion';
|
|
34
|
+
mutation: T;
|
|
35
|
+
count: number;
|
|
36
|
+
proportion: number;
|
|
37
|
+
};
|
|
21
38
|
|
|
22
|
-
export type InsertionEntry = { type: 'insertion'; mutation:
|
|
39
|
+
export type InsertionEntry<T extends Insertion = InsertionClass> = { type: 'insertion'; mutation: T; count: number };
|
|
23
40
|
|
|
24
|
-
export type SubstitutionOrDeletionEntry
|
|
41
|
+
export type SubstitutionOrDeletionEntry<
|
|
42
|
+
S extends Substitution = SubstitutionClass,
|
|
43
|
+
D extends Deletion = DeletionClass,
|
|
44
|
+
> = SubstitutionEntry<S> | DeletionEntry<D>;
|
|
25
45
|
|
|
26
46
|
export type MutationEntry = SubstitutionEntry | DeletionEntry | InsertionEntry;
|
package/src/utils/map2d.spec.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { describe, expect, it } from 'vitest';
|
|
|
2
2
|
|
|
3
3
|
import { Map2dBase, Map2dView } from './map2d';
|
|
4
4
|
|
|
5
|
-
describe('
|
|
5
|
+
describe('Map2dBase', () => {
|
|
6
6
|
it('should add a value and return it', () => {
|
|
7
7
|
const map2d = new Map2dBase<string, string, number>();
|
|
8
8
|
map2d.set('a', 'b', 2);
|
|
@@ -86,6 +86,34 @@ describe('Map2dContainer', () => {
|
|
|
86
86
|
|
|
87
87
|
expect(map2d.getRow('c', 0)).toEqual([]);
|
|
88
88
|
});
|
|
89
|
+
|
|
90
|
+
it('should return content as object', () => {
|
|
91
|
+
const map2d = new Map2dBase<string, string, number>();
|
|
92
|
+
map2d.set('a', 'b', 2);
|
|
93
|
+
map2d.set('c', 'd', 4);
|
|
94
|
+
|
|
95
|
+
const content = map2d.getContents();
|
|
96
|
+
expect(Array.from(content.keysFirstAxis.values())).to.deep.equal(['a', 'c']);
|
|
97
|
+
expect(Array.from(content.keysSecondAxis.values())).to.deep.equal(['b', 'd']);
|
|
98
|
+
expect(content.data.get('a')?.get('b')).toBe(2);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('should use initial data', () => {
|
|
102
|
+
const map2d = new Map2dBase<string, string, number>();
|
|
103
|
+
map2d.set('a', 'b', 2);
|
|
104
|
+
map2d.set('c', 'd', 4);
|
|
105
|
+
|
|
106
|
+
const content = map2d.getContents();
|
|
107
|
+
|
|
108
|
+
const mapWithInitialData = new Map2dBase<string, string, number>(
|
|
109
|
+
(value) => value,
|
|
110
|
+
(value) => value,
|
|
111
|
+
content,
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
expect(mapWithInitialData.get('a', 'b')).toBe(2);
|
|
115
|
+
expect(mapWithInitialData.get('c', 'd')).toBe(4);
|
|
116
|
+
});
|
|
89
117
|
});
|
|
90
118
|
|
|
91
119
|
describe('Map2dView', () => {
|
package/src/utils/map2d.ts
CHANGED
|
@@ -22,6 +22,12 @@ export interface Map2d<Key1, Key2, Value> {
|
|
|
22
22
|
readonly keysSecondAxis: Map<string, Key2>;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
export type Map2DContents<Key1, Key2, Value> = {
|
|
26
|
+
keysFirstAxis: Map<string, Key1>;
|
|
27
|
+
keysSecondAxis: Map<string, Key2>;
|
|
28
|
+
data: Map<string, Map<string, Value>>;
|
|
29
|
+
};
|
|
30
|
+
|
|
25
31
|
export class Map2dBase<Key1 extends object | string, Key2 extends object | string, Value>
|
|
26
32
|
implements Map2d<Key1, Key2, Value>
|
|
27
33
|
{
|
|
@@ -32,7 +38,14 @@ export class Map2dBase<Key1 extends object | string, Key2 extends object | strin
|
|
|
32
38
|
constructor(
|
|
33
39
|
readonly serializeFirstAxis: (key: Key1) => string = (key) => (typeof key === 'string' ? key : hash(key)),
|
|
34
40
|
readonly serializeSecondAxis: (key: Key2) => string = (key) => (typeof key === 'string' ? key : hash(key)),
|
|
35
|
-
|
|
41
|
+
initialContent?: Map2DContents<Key1, Key2, Value>,
|
|
42
|
+
) {
|
|
43
|
+
if (initialContent) {
|
|
44
|
+
this.keysFirstAxis = new Map(initialContent.keysFirstAxis);
|
|
45
|
+
this.keysSecondAxis = new Map(initialContent.keysSecondAxis);
|
|
46
|
+
this.data = new Map(initialContent.data);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
36
49
|
|
|
37
50
|
get(keyFirstAxis: Key1, keySecondAxis: Key2) {
|
|
38
51
|
const serializedKeyFirstAxis = this.serializeFirstAxis(keyFirstAxis);
|
|
@@ -84,6 +97,14 @@ export class Map2dBase<Key1 extends object | string, Key2 extends object | strin
|
|
|
84
97
|
});
|
|
85
98
|
});
|
|
86
99
|
}
|
|
100
|
+
|
|
101
|
+
getContents(): Map2DContents<Key1, Key2, Value> {
|
|
102
|
+
return {
|
|
103
|
+
keysFirstAxis: this.keysFirstAxis,
|
|
104
|
+
keysSecondAxis: this.keysSecondAxis,
|
|
105
|
+
data: this.data,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
87
108
|
}
|
|
88
109
|
|
|
89
110
|
export class Map2dView<Key1 extends object | string, Key2 extends object | string, Value>
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { DeletionClass, InsertionClass, SubstitutionClass } from './mutations';
|
|
4
4
|
|
|
5
|
-
describe('
|
|
5
|
+
describe('SubstitutionClass', () => {
|
|
6
6
|
it('should be parsed from string', () => {
|
|
7
|
-
expect(
|
|
8
|
-
expect(
|
|
7
|
+
expect(SubstitutionClass.parse('A1T')).deep.equal(new SubstitutionClass(undefined, 'A', 'T', 1));
|
|
8
|
+
expect(SubstitutionClass.parse('seg1:A1T')).deep.equal(new SubstitutionClass('seg1', 'A', 'T', 1));
|
|
9
9
|
});
|
|
10
10
|
|
|
11
11
|
it('should render to string correctly', () => {
|
|
12
12
|
const substitutions = [
|
|
13
13
|
{
|
|
14
|
-
substitution: new
|
|
14
|
+
substitution: new SubstitutionClass(undefined, 'A', 'T', 1),
|
|
15
15
|
expected: 'A1T',
|
|
16
16
|
},
|
|
17
|
-
{ substitution: new
|
|
18
|
-
{ substitution: new
|
|
17
|
+
{ substitution: new SubstitutionClass('segment', 'A', 'T', 1), expected: 'segment:A1T' },
|
|
18
|
+
{ substitution: new SubstitutionClass(undefined, undefined, undefined, 1), expected: '1' },
|
|
19
19
|
];
|
|
20
20
|
|
|
21
21
|
for (const { substitution, expected } of substitutions) {
|
|
@@ -24,20 +24,20 @@ describe('Substitution', () => {
|
|
|
24
24
|
});
|
|
25
25
|
});
|
|
26
26
|
|
|
27
|
-
describe('
|
|
27
|
+
describe('DeletionClass', () => {
|
|
28
28
|
it('should be parsed from string', () => {
|
|
29
|
-
expect(
|
|
30
|
-
expect(
|
|
29
|
+
expect(DeletionClass.parse('A1-')).deep.equal(new DeletionClass(undefined, 'A', 1));
|
|
30
|
+
expect(DeletionClass.parse('seg1:A1-')).deep.equal(new DeletionClass('seg1', 'A', 1));
|
|
31
31
|
});
|
|
32
32
|
|
|
33
33
|
it('should render to string correctly', () => {
|
|
34
34
|
const substitutions = [
|
|
35
35
|
{
|
|
36
|
-
deletion: new
|
|
36
|
+
deletion: new DeletionClass(undefined, 'A', 1),
|
|
37
37
|
expected: 'A1-',
|
|
38
38
|
},
|
|
39
|
-
{ deletion: new
|
|
40
|
-
{ deletion: new
|
|
39
|
+
{ deletion: new DeletionClass('segment', 'A', 1), expected: 'segment:A1-' },
|
|
40
|
+
{ deletion: new DeletionClass(undefined, undefined, 1), expected: '1-' },
|
|
41
41
|
];
|
|
42
42
|
|
|
43
43
|
for (const { deletion, expected } of substitutions) {
|
|
@@ -46,19 +46,19 @@ describe('Deletion', () => {
|
|
|
46
46
|
});
|
|
47
47
|
});
|
|
48
48
|
|
|
49
|
-
describe('
|
|
49
|
+
describe('InsertionClass', () => {
|
|
50
50
|
it('should be parsed from string', () => {
|
|
51
|
-
expect(
|
|
52
|
-
expect(
|
|
51
|
+
expect(InsertionClass.parse('ins_1:A')).deep.equal(new InsertionClass(undefined, 1, 'A'));
|
|
52
|
+
expect(InsertionClass.parse('ins_seg1:1:A')).deep.equal(new InsertionClass('seg1', 1, 'A'));
|
|
53
53
|
});
|
|
54
54
|
|
|
55
55
|
it('should be parsed with case insensitive ins prefix', () => {
|
|
56
|
-
expect(
|
|
57
|
-
expect(
|
|
56
|
+
expect(InsertionClass.parse('INS_1:A')).deep.equal(new InsertionClass(undefined, 1, 'A'));
|
|
57
|
+
expect(InsertionClass.parse('iNs_1:A')).deep.equal(new InsertionClass(undefined, 1, 'A'));
|
|
58
58
|
});
|
|
59
59
|
|
|
60
60
|
it('should be parsed with the other parts not case insensitive', () => {
|
|
61
|
-
expect(
|
|
62
|
-
expect(
|
|
61
|
+
expect(InsertionClass.parse('ins_geNe1:1:A')).deep.equal(new InsertionClass('geNe1', 1, 'A'));
|
|
62
|
+
expect(InsertionClass.parse('ins_1:aA')).deep.equal(new InsertionClass(undefined, 1, 'aA'));
|
|
63
63
|
});
|
|
64
64
|
});
|
package/src/utils/mutations.ts
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { type MutationType, type SequenceType } from '../types';
|
|
2
2
|
|
|
3
3
|
export interface Mutation {
|
|
4
|
-
readonly segment: string | undefined;
|
|
5
4
|
readonly position: number;
|
|
6
5
|
readonly code: string;
|
|
7
6
|
readonly type: MutationType;
|
|
7
|
+
readonly segment?: string;
|
|
8
|
+
}
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
export interface MutationClass extends Mutation {
|
|
11
|
+
equals(other: MutationClass): boolean;
|
|
10
12
|
|
|
11
13
|
toString(): string;
|
|
12
14
|
}
|
|
@@ -14,7 +16,13 @@ export interface Mutation {
|
|
|
14
16
|
export const substitutionRegex =
|
|
15
17
|
/^((?<segment>[A-Za-z0-9_-]+)(?=:):)?(?<valueAtReference>[A-Za-z])?(?<position>\d+)(?<substitutionValue>[A-Za-z.])?$/;
|
|
16
18
|
|
|
17
|
-
export
|
|
19
|
+
export interface Substitution extends Mutation {
|
|
20
|
+
type: 'substitution';
|
|
21
|
+
valueAtReference: string | undefined;
|
|
22
|
+
substitutionValue: string | undefined;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export class SubstitutionClass implements MutationClass, Substitution {
|
|
18
26
|
readonly code;
|
|
19
27
|
readonly type = 'substitution';
|
|
20
28
|
|
|
@@ -30,8 +38,8 @@ export class Substitution implements Mutation {
|
|
|
30
38
|
this.code = `${segmentString}${valueAtReferenceString}${this.position}${substitutionValueString}`;
|
|
31
39
|
}
|
|
32
40
|
|
|
33
|
-
equals(other:
|
|
34
|
-
if (!(other instanceof
|
|
41
|
+
equals(other: MutationClass): boolean {
|
|
42
|
+
if (!(other instanceof SubstitutionClass)) {
|
|
35
43
|
return false;
|
|
36
44
|
}
|
|
37
45
|
return (
|
|
@@ -46,12 +54,12 @@ export class Substitution implements Mutation {
|
|
|
46
54
|
return this.code;
|
|
47
55
|
}
|
|
48
56
|
|
|
49
|
-
static parse(mutationStr: string):
|
|
57
|
+
static parse(mutationStr: string): SubstitutionClass | null {
|
|
50
58
|
const match = mutationStr.match(substitutionRegex);
|
|
51
59
|
if (match === null || match.groups === undefined) {
|
|
52
60
|
return null;
|
|
53
61
|
}
|
|
54
|
-
return new
|
|
62
|
+
return new SubstitutionClass(
|
|
55
63
|
match.groups.segment,
|
|
56
64
|
match.groups.valueAtReference,
|
|
57
65
|
match.groups.substitutionValue,
|
|
@@ -62,7 +70,12 @@ export class Substitution implements Mutation {
|
|
|
62
70
|
|
|
63
71
|
export const deletionRegex = /^((?<segment>[A-Za-z0-9_-]+)(?=:):)?(?<valueAtReference>[A-Za-z])?(?<position>\d+)(-)$/;
|
|
64
72
|
|
|
65
|
-
export
|
|
73
|
+
export interface Deletion extends Mutation {
|
|
74
|
+
type: 'deletion';
|
|
75
|
+
valueAtReference: string | undefined;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export class DeletionClass implements MutationClass, Deletion {
|
|
66
79
|
readonly code;
|
|
67
80
|
readonly type = 'deletion';
|
|
68
81
|
|
|
@@ -76,8 +89,8 @@ export class Deletion implements Mutation {
|
|
|
76
89
|
this.code = `${segmentString}${valueAtReferenceString}${this.position}-`;
|
|
77
90
|
}
|
|
78
91
|
|
|
79
|
-
equals(other:
|
|
80
|
-
if (!(other instanceof
|
|
92
|
+
equals(other: MutationClass): boolean {
|
|
93
|
+
if (!(other instanceof DeletionClass)) {
|
|
81
94
|
return false;
|
|
82
95
|
}
|
|
83
96
|
return (
|
|
@@ -91,20 +104,29 @@ export class Deletion implements Mutation {
|
|
|
91
104
|
return this.code;
|
|
92
105
|
}
|
|
93
106
|
|
|
94
|
-
static parse(mutationStr: string):
|
|
107
|
+
static parse(mutationStr: string): DeletionClass | null {
|
|
95
108
|
const match = mutationStr.match(deletionRegex);
|
|
96
109
|
if (match === null || match.groups === undefined) {
|
|
97
110
|
return null;
|
|
98
111
|
}
|
|
99
112
|
|
|
100
|
-
return new
|
|
113
|
+
return new DeletionClass(
|
|
114
|
+
match.groups.segment,
|
|
115
|
+
match.groups.valueAtReference,
|
|
116
|
+
parseInt(match.groups.position, 10),
|
|
117
|
+
);
|
|
101
118
|
}
|
|
102
119
|
}
|
|
103
120
|
|
|
104
121
|
export const insertionRegexp =
|
|
105
122
|
/^ins_((?<segment>[A-Za-z0-9_-]+)(?=:):)?(?<position>\d+):(?<insertedSymbols>(([A-Za-z?]|(\.\*))+))$/i;
|
|
106
123
|
|
|
107
|
-
export
|
|
124
|
+
export interface Insertion extends Mutation {
|
|
125
|
+
type: 'insertion';
|
|
126
|
+
insertedSymbols: string;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export class InsertionClass implements MutationClass {
|
|
108
130
|
readonly code;
|
|
109
131
|
readonly type = 'insertion';
|
|
110
132
|
|
|
@@ -116,8 +138,8 @@ export class Insertion implements Mutation {
|
|
|
116
138
|
this.code = `ins_${this.segment ? `${this.segment}:` : ''}${this.position}:${this.insertedSymbols}`;
|
|
117
139
|
}
|
|
118
140
|
|
|
119
|
-
equals(other:
|
|
120
|
-
if (!(other instanceof
|
|
141
|
+
equals(other: MutationClass): boolean {
|
|
142
|
+
if (!(other instanceof InsertionClass)) {
|
|
121
143
|
return false;
|
|
122
144
|
}
|
|
123
145
|
return (
|
|
@@ -131,13 +153,54 @@ export class Insertion implements Mutation {
|
|
|
131
153
|
return this.code;
|
|
132
154
|
}
|
|
133
155
|
|
|
134
|
-
static parse(mutationStr: string):
|
|
156
|
+
static parse(mutationStr: string): InsertionClass | null {
|
|
135
157
|
const match = mutationStr.match(insertionRegexp);
|
|
136
158
|
if (match === null || match.groups === undefined) {
|
|
137
159
|
return null;
|
|
138
160
|
}
|
|
139
161
|
|
|
140
|
-
return new
|
|
162
|
+
return new InsertionClass(
|
|
163
|
+
match.groups.segment,
|
|
164
|
+
parseInt(match.groups.position, 10),
|
|
165
|
+
match.groups.insertedSymbols,
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export function toMutation(
|
|
171
|
+
mutationClass: SubstitutionClass | DeletionClass | InsertionClass,
|
|
172
|
+
): Substitution | Deletion | Insertion {
|
|
173
|
+
if (mutationClass.type === 'insertion') {
|
|
174
|
+
return {
|
|
175
|
+
type: 'insertion' as const,
|
|
176
|
+
code: mutationClass.code,
|
|
177
|
+
segment: mutationClass.segment,
|
|
178
|
+
position: mutationClass.position,
|
|
179
|
+
insertedSymbols: mutationClass.insertedSymbols,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
return toSubstitutionOrDeletion(mutationClass);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export function toSubstitutionOrDeletion(mutation: SubstitutionClass | DeletionClass): Substitution | Deletion {
|
|
186
|
+
switch (mutation.type) {
|
|
187
|
+
case 'substitution':
|
|
188
|
+
return {
|
|
189
|
+
type: 'substitution' as const,
|
|
190
|
+
code: mutation.code,
|
|
191
|
+
segment: mutation.segment,
|
|
192
|
+
position: mutation.position,
|
|
193
|
+
valueAtReference: mutation.valueAtReference,
|
|
194
|
+
substitutionValue: mutation.substitutionValue,
|
|
195
|
+
};
|
|
196
|
+
case 'deletion':
|
|
197
|
+
return {
|
|
198
|
+
type: 'deletion' as const,
|
|
199
|
+
code: mutation.code,
|
|
200
|
+
segment: mutation.segment,
|
|
201
|
+
position: mutation.position,
|
|
202
|
+
valueAtReference: mutation.valueAtReference,
|
|
203
|
+
};
|
|
141
204
|
}
|
|
142
205
|
}
|
|
143
206
|
|
package/src/utils/sort.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { TemporalClass } from './temporalClass';
|
|
2
2
|
|
|
3
|
-
export function sortNullToBeginningThenByDate(
|
|
3
|
+
export function sortNullToBeginningThenByDate(
|
|
4
|
+
a: { dateRange: TemporalClass | null },
|
|
5
|
+
b: { dateRange: TemporalClass | null },
|
|
6
|
+
) {
|
|
4
7
|
return a.dateRange === null
|
|
5
8
|
? -1
|
|
6
9
|
: b.dateRange === null
|
|
@@ -5,23 +5,26 @@ import {
|
|
|
5
5
|
generateAllMonthsInRange,
|
|
6
6
|
generateAllYearsInRange,
|
|
7
7
|
TemporalCache,
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
} from './
|
|
8
|
+
YearClass,
|
|
9
|
+
YearMonthClass,
|
|
10
|
+
YearMonthDayClass,
|
|
11
|
+
YearWeekClass,
|
|
12
|
+
} from './temporalClass';
|
|
13
13
|
|
|
14
14
|
const cache = TemporalCache.getInstance();
|
|
15
15
|
|
|
16
16
|
describe('generateAllDaysInRange', () => {
|
|
17
17
|
it('should return all days in range', () => {
|
|
18
18
|
expect(
|
|
19
|
-
generateAllDaysInRange(
|
|
19
|
+
generateAllDaysInRange(
|
|
20
|
+
YearMonthDayClass.parse('2020-01-01', cache),
|
|
21
|
+
YearMonthDayClass.parse('2020-01-04', cache),
|
|
22
|
+
),
|
|
20
23
|
).deep.equal([
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
YearMonthDayClass.parse('2020-01-01', cache),
|
|
25
|
+
YearMonthDayClass.parse('2020-01-02', cache),
|
|
26
|
+
YearMonthDayClass.parse('2020-01-03', cache),
|
|
27
|
+
YearMonthDayClass.parse('2020-01-04', cache),
|
|
25
28
|
]);
|
|
26
29
|
});
|
|
27
30
|
});
|
|
@@ -29,30 +32,30 @@ describe('generateAllDaysInRange', () => {
|
|
|
29
32
|
describe('generateAllMonthsInRange', () => {
|
|
30
33
|
it('should return all months in range', () => {
|
|
31
34
|
expect(
|
|
32
|
-
generateAllMonthsInRange(
|
|
35
|
+
generateAllMonthsInRange(YearMonthClass.parse('2020-01', cache), YearMonthClass.parse('2020-04', cache)),
|
|
33
36
|
).deep.equal([
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
37
|
+
YearMonthClass.parse('2020-01', cache),
|
|
38
|
+
YearMonthClass.parse('2020-02', cache),
|
|
39
|
+
YearMonthClass.parse('2020-03', cache),
|
|
40
|
+
YearMonthClass.parse('2020-04', cache),
|
|
38
41
|
]);
|
|
39
42
|
});
|
|
40
43
|
});
|
|
41
44
|
|
|
42
45
|
describe('generateAllYearsInRange', () => {
|
|
43
46
|
it('should return all years in range', () => {
|
|
44
|
-
expect(generateAllYearsInRange(
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
expect(generateAllYearsInRange(YearClass.parse('2020-01', cache), YearClass.parse('2023', cache))).deep.equal([
|
|
48
|
+
YearClass.parse('2020', cache),
|
|
49
|
+
YearClass.parse('2021', cache),
|
|
50
|
+
YearClass.parse('2022', cache),
|
|
51
|
+
YearClass.parse('2023', cache),
|
|
49
52
|
]);
|
|
50
53
|
});
|
|
51
54
|
});
|
|
52
55
|
|
|
53
56
|
describe('YearMonthDay', () => {
|
|
54
57
|
it('should parse from string', () => {
|
|
55
|
-
const underTest =
|
|
58
|
+
const underTest = YearMonthDayClass.parse('2020-01-01', cache);
|
|
56
59
|
|
|
57
60
|
expect(underTest.yearNumber).equal(2020);
|
|
58
61
|
expect(underTest.monthNumber).equal(1);
|
|
@@ -66,7 +69,7 @@ describe('YearMonthDay', () => {
|
|
|
66
69
|
|
|
67
70
|
describe('YearWeek', () => {
|
|
68
71
|
it('should parse from string', () => {
|
|
69
|
-
const underTest =
|
|
72
|
+
const underTest = YearWeekClass.parse('2020-W02', cache);
|
|
70
73
|
|
|
71
74
|
expect(underTest.isoYearNumber).equal(2020);
|
|
72
75
|
expect(underTest.isoWeekNumber).equal(2);
|
|
@@ -78,7 +81,7 @@ describe('YearWeek', () => {
|
|
|
78
81
|
|
|
79
82
|
describe('YearMonth', () => {
|
|
80
83
|
it('should parse from string', () => {
|
|
81
|
-
const underTest =
|
|
84
|
+
const underTest = YearMonthClass.parse('2020-01', cache);
|
|
82
85
|
|
|
83
86
|
expect(underTest.yearNumber).equal(2020);
|
|
84
87
|
expect(underTest.monthNumber).equal(1);
|
|
@@ -90,7 +93,7 @@ describe('YearMonth', () => {
|
|
|
90
93
|
|
|
91
94
|
describe('Year', () => {
|
|
92
95
|
it('should parse from string', () => {
|
|
93
|
-
const underTest =
|
|
96
|
+
const underTest = YearClass.parse('2020', cache);
|
|
94
97
|
|
|
95
98
|
expect(underTest.year).equal(2020);
|
|
96
99
|
expect(underTest.text).equal('2020');
|