Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,6 @@ jobs:
- name: Lint
run: npm run check:lint

# noUncheckedIndexedAccess is a compiler flag with no warning level, so it
# is held at a per-file count until it reaches zero and can be enabled
# (#345). Like the lint warnings, a count can only go down.
- name: Unchecked indexed access has not increased
run: npm run check:indexed

# eslint sees unused symbols within a file; knip sees whole files and
# exports nothing imports, which was the bigger pile. Also baselined,
# because some findings need someone who knows the data model to judge --
Expand Down
4 changes: 3 additions & 1 deletion e2e/reacfoam.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,9 @@ async function centreOf(page: Page, label: string) {
function darkInTitleStrip(page: Page) {
return page.evaluate(() => {
const canvases = [...document.querySelectorAll<HTMLCanvasElement>('cr-reacfoam canvas')];
const { width, height } = canvases[0];
const [first] = canvases;
if (!first) throw new Error('no reacfoam canvas');
const { width, height } = first;
const top = Math.floor(height * 0.85);
const all = document.createElement('canvas');
all.width = width;
Expand Down
15 changes: 0 additions & 15 deletions indexed-access-baseline.json

This file was deleted.

1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"check:lint": "node scripts/check-lint.mjs",
"check:indexed": "node scripts/check-indexed-access.mjs",
"check:dead": "node scripts/check-dead-code.mjs",
"check:lockfile": "node scripts/check-lockfile.mjs",
"dead": "knip",
Expand Down
5 changes: 1 addition & 4 deletions projects/reactome-diagram-element/tsconfig.app.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "../../out-tsc/reactome-diagram-element",
"types": [],
// Every index read checked (#345). Not yet in tsconfig.json: the workspace
// libraries have findings left, held at a count by scripts/check-indexed-access.mjs.
"noUncheckedIndexedAccess": true
"types": []
},
"files": ["src/main.ts"],
"include": ["../pathway-browser/src/**/*.d.ts", "../../src/**/*.d.ts"]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,10 +141,9 @@ export class LocalDataComponent {
}
const lines = text.trim().split('\n');

for (let i = 1; i < lines.length; i++) {
const columns = lines[i].split('\t');
for (let j = 1; j < columns.length; j++) {
const value = columns[j].trim();
for (const line of lines.slice(1)) {
for (const column of line.split('\t').slice(1)) {
const value = column.trim();
if (!Number.isInteger(Number(value))) {
return resolve(false);
}
Expand All @@ -166,10 +165,10 @@ export class LocalDataComponent {
this.readFile(fileRibo),
]);

const file1FirstLine = file1Content.split('\n')[0].trim();
const file2FirstLine = file2Content.split('\n')[0].trim();
const [file1FirstLine = ''] = file1Content.split('\n');
const [file2FirstLine = ''] = file2Content.split('\n');

return file1FirstLine === file2FirstLine;
return file1FirstLine.trim() === file2FirstLine.trim();
} catch (error) {
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export class StatisticalDesignComponent implements OnInit {
this.store.dispatch(datasetActions.setCovariatesValue({ id: this.datasetId(), value: value }));
}

comparisonGroup2Values(groups: string[], group1: string) {
comparisonGroup2Values(groups: string[] | undefined, group1: string) {
if (!groups) return [];
return groups.filter((group) => group !== group1);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,24 @@ import { extractErrorMessage } from '../utilities/utils';
import { MatSnackBar } from '@angular/material/snack-bar';
import { ConfigProvider, REACTOME_GSA_CONFIG } from '../config/gsa-config';

export const typeToParse: { [p: string]: (value: string) => any } = {
/** Reads a parameter's text as its type: a boolean, a number, or the text itself. */
type Parser = (value: string) => any;

const typeToParse: { [p: string]: Parser } = {
bool: (value) => value.toLowerCase() === 'true',
float: parseFloat,
int: parseInt,
email: (value) => value,
string: (value) => value,
};

/**
* How to read a parameter of this type. A type this form does not know -- one
* the service added since -- is read as text, rather than taking the whole form
* down with it.
*/
export const parserFor = (type: string): Parser => typeToParse[type] ?? ((text: string) => text);

@Injectable({
providedIn: 'root',
})
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { describe, expect, it } from 'vitest';
import { parserFor } from './analysis-methods.service';

// A method's parameters come from the GSA service, typed by name. A type this
// form does not know -- one added since -- is read as text rather than taking
// the form down.
describe('parserFor', () => {
it('reads each known type', () => {
expect(parserFor('bool')('True')).toBe(true);
expect(parserFor('float')('0.05')).toBe(0.05);
expect(parserFor('int')('7')).toBe(7);
expect(parserFor('string')('x')).toBe('x');
});

it('reads a type it does not know as text', () => {
expect(parserFor('ratio')('1:2')).toBe('1:2');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Injectable, inject } from '@angular/core';
import { catchError, exhaustMap, map, mergeMap, of, take } from 'rxjs';
import { FetchDatasetService } from '../../services/fetch-dataset.service';
import { datasetSourceActions } from './dataset-source.action';
import { typeToParse } from '../../services/analysis-methods.service';
import { parserFor } from '../../services/analysis-methods.service';

@Injectable()
export class DatasetSourceEffects {
Expand Down Expand Up @@ -50,8 +50,8 @@ export class DatasetSourceEffects {
externals.forEach((external) =>
external.parameters.forEach((param) => {
// param.id = `${external.id} - ${param.name}`;
param.value = typeToParse[param.type](param.default);
param.default = typeToParse[param.type](param.default);
param.value = parserFor(param.type)(param.default);
param.default = parserFor(param.type)(param.default);
})
);
return externals;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,8 @@ export class DatasetEffects {
['', ...summary.sample_metadata.map((col) => col.name)],
...summary.sample_ids.map((sampleId, i) => [
sampleId,
...summary.sample_metadata!.map((column) => column.values[i]),
// A missing value stays missing (sent as null), as it always was.
...summary.sample_metadata!.map((column) => column.values[i] as string),
]),
];
return datasetActions.setAnnotations({ annotations: table, id });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,13 +134,14 @@ export const datasetReducer: ActionReducer<DatasetState> = createReducer(
const annotations = dataset.annotations!;

const annotationsWithSimpleIds = cp(annotations);
annotationsWithSimpleIds[0][0] = 'sample_ids';
const [header] = annotationsWithSimpleIds;
if (header) header[0] = 'sample_ids';

return {
id: dataset.id,
changes: {
annotationColumns: new Map<string, string[]>(
transpose(annotationsWithSimpleIds).map((col) => [col[0], col.slice(1)])
transpose(annotationsWithSimpleIds).map((col) => [col[0] ?? '', col.slice(1)])
),
},
};
Expand Down Expand Up @@ -213,7 +214,7 @@ export const datasetReducer: ActionReducer<DatasetState> = createReducer(
...dataset.statisticalDesign!,
covariances:
dataset.annotations?.[0]
.slice(1) //slice the first element, which is the empty string
?.slice(1) //slice the first element, which is the empty string
.filter((name) => name !== dataset.statisticalDesign!.analysisGroup)
.map((name) => ({
name,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ export const datasetFeature = createFeature({
.slice(1) // Remove row ids column
.map((column) => ({
// Create groups with distinct values
name: column[0],
name: column[0] ?? '',
values: new Set(column.slice(1).filter((s) => s)),
}))
.filter((group) => group.values.size >= 2) // Filter groups suitable for analysis
Expand Down Expand Up @@ -115,19 +115,20 @@ export const datasetFeature = createFeature({
.slice(1) // Remove row ids column
.map((column) => ({
// Create groups with distinct values
name: column[0],
name: column[0] ?? '',
values: column.slice(1),
}))
.filter((column) => dataset!.statisticalDesign!.analysisGroup !== column.name) // Remove analysis group
.filter((column) => {
const group1Values = new Set<string>();
const group2Values = new Set<string>();
// A missing value counts as one, as it always has.
const group1Values = new Set<string | undefined>();
const group2Values = new Set<string | undefined>();
for (let i = 0; i < analysisColumn.length; i++) {
const analysedValue = analysisColumn[i];
for (const [comparisonGroup, values] of [
[dataset!.statisticalDesign!.comparisonGroup1, group1Values],
[dataset!.statisticalDesign!.comparisonGroup2, group2Values],
] as [string, Set<string>][]) {
] as [string, Set<string | undefined>][]) {
if (analysedValue === comparisonGroup) {
const value = column.values[i];
if (values.has(value)) return false; // remove columns where a "pair" is associated more than once to the same condition
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Actions, createEffect, ofType } from '@ngrx/effects';
import { Injectable, inject } from '@angular/core';
import { AnalysisMethodsService, typeToParse } from '../../services/analysis-methods.service';
import { AnalysisMethodsService, parserFor } from '../../services/analysis-methods.service';
import { methodActions } from './method.action';
import { catchError, exhaustMap, map, of } from 'rxjs';
import { ParameterType } from '../../model/methods.model';
Expand All @@ -21,8 +21,8 @@ export class MethodEffects {
methods.forEach((method) => {
method.parameters.forEach((param) => {
param.type = param.name === 'email' ? ParameterType.email : param.type;
param.value = typeToParse[param.type](param.default);
param.default = typeToParse[param.type](param.default);
param.value = parserFor(param.type)(param.default);
param.default = parserFor(param.type)(param.default);
});
const server = method.parameters.find((param) => param.name === 'reactome_server');
if (server) server.value = this.config().server;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ export const methodReducer: ActionReducer<MethodState> = createReducer(
})),
{
...state,
commonParameters: methods[0].parameters.filter((param) => param.scope === 'common'), // They are transferred to global status
// They are transferred to global status; no methods have none.
commonParameters: methods[0]?.parameters.filter((param) => param.scope === 'common') ?? [],
}
)
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Pipe, PipeTransform } from '@angular/core';
export class SpeciesPipe implements PipeTransform {
transform(value: string): unknown {
const words = value.split(' ');
return words[0].charAt(0).toUpperCase() + '. ' + words.slice(1).join(' ');
const [genus = ''] = words;
return genus.charAt(0).toUpperCase() + '. ' + words.slice(1).join(' ');
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@
@if (settings.addRow) {
<tr>
<th class="rows">...</th>
<td class="no-padding add-row-button-container" [colSpan]="data[0].length">
<td class="no-padding add-row-button-container" [colSpan]="data[0]?.length ?? 1">
<button
(click)="addRow()"
(keydown.shift.tab)="focusLastCell($event)"
Expand Down
Loading
Loading