Merge branch 'main' into colinmegill/#632

This commit is contained in:
Colin Megill
2021-08-16 12:14:34 -07:00
25 changed files with 448 additions and 332 deletions
@@ -9,6 +9,7 @@ on:
env: env:
JEST_ENV: prod JEST_ENV: prod
CXG_AUTH_TYPE: none
jobs: jobs:
docker-build: docker-build:
+5 -3
View File
@@ -1,11 +1,13 @@
include ../common.mk include ../common.mk
ANNOTATIONS := $(if $(ANNOTATIONS),$(ANNOTATIONS),../backend/test/fixtures/pbmc3k-annotations.csv) ANNOTATIONS := $(if $(ANNOTATIONS),$(ANNOTATIONS),../backend/test/fixtures/pbmc3k-annotations.csv)
GENE_SETS := $(if $(GENE_SETS),$(GENE_SETS),../backend/test/fixtures/pbmc3k-genesets.csv) GENE_SETS := $(if $(GENE_SETS),$(GENE_SETS),../backend/test/fixtures/pbmc3k-genesets.csv)
ANNOTATIONS_FILENAME := $(shell basename $(ANNOTATIONS)) ANNOTATIONS_FILENAME := $(shell basename $(ANNOTATIONS))
GENE_SETS_FILENAME := $(shell basename $(GENE_SETS)) GENE_SETS_FILENAME := $(shell basename $(GENE_SETS))
CXG_CONFIG := $(if $(CXG_CONFIG), $(CXG_CONFIG), ./__tests__/e2e/test_config.yaml) CXG_CONFIG := $(if $(CXG_CONFIG),$(CXG_CONFIG),./__tests__/e2e/test_config.yaml)
CXG_AUTH_TYPE := $(if $(CXG_AUTH_TYPE),$(CXG_AUTH_TYPE),"test")
# Packaging # Packaging
@@ -38,7 +40,7 @@ smoke-test:
start_server_and_test \ start_server_and_test \
'CXG_OPTIONS="--config-file $(CXG_CONFIG)" $(MAKE) start-server' \ 'CXG_OPTIONS="--config-file $(CXG_CONFIG)" $(MAKE) start-server' \
$(CXG_SERVER_PORT) \ $(CXG_SERVER_PORT) \
'CXG_URL_BASE="http://localhost:$(CXG_SERVER_PORT)" CXG_AUTH_TYPE="test" npm run e2e -- --verbose false' 'CXG_URL_BASE="http://localhost:$(CXG_SERVER_PORT)" CXG_AUTH_TYPE=$(CXG_AUTH_TYPE) npm run e2e -- --verbose false'
# start an instance of cellxgene and run the end-to-end annotations tests # start an instance of cellxgene and run the end-to-end annotations tests
.PHONY: smoke-test-annotations .PHONY: smoke-test-annotations
+8 -9
View File
@@ -1,10 +1,12 @@
import { Reducer } from "redux";
import undoable from "../../src/reducers/undoable"; import undoable from "../../src/reducers/undoable";
describe("create", () => { describe("create", () => {
test("no keys", () => { test("no keys", () => {
// @ts-expect-error ts-migrate(2554) FIXME: Expected 2-3 arguments, but got 1. expect(() =>
expect(() => undoable(() => {})).toThrow(); undoable(() => {}, undefined as unknown as string[])
expect(() => undoable(() => {}, null)).toThrow(); ).toThrow();
expect(() => undoable(() => {}, null as unknown as string[])).toThrow();
expect(() => undoable(() => {}, [])).toThrow(); expect(() => undoable(() => {}, [])).toThrow();
expect(() => undoable(() => {}, [], {})).toThrow(); expect(() => undoable(() => {}, [], {})).toThrow();
}); });
@@ -24,8 +26,7 @@ describe("create", () => {
describe("undo", () => { describe("undo", () => {
test("expected state modifications", () => { test("expected state modifications", () => {
const initialState = { a: 0, b: 1000 }; const initialState = { a: 0, b: 1000 };
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. const reducer: Reducer = (state) => ({ a: state.a + 1, b: state.b + 1 });
const reducer = (state: any) => ({ a: state.a + 1, b: state.b + 1 });
const undoableReducer = undoable(reducer, ["a"]); const undoableReducer = undoable(reducer, ["a"]);
const s1 = undoableReducer(initialState, { type: "test" }); const s1 = undoableReducer(initialState, { type: "test" });
@@ -43,10 +44,8 @@ describe("undo", () => {
describe("redo", () => { describe("redo", () => {
const initialState = { a: 0, b: 1000 }; const initialState = { a: 0, b: 1000 };
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. const reducer: Reducer = (state) => ({ a: state.a + 1, b: state.b + 1 });
const reducer = (state: any) => ({ a: state.a + 1, b: state.b + 1 }); let UR: Reducer;
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
let UR: any;
beforeEach(() => { beforeEach(() => {
UR = undoable(reducer, ["a"]); UR = undoable(reducer, ["a"]);
@@ -34,7 +34,7 @@ function makeMockColumn(s: any, length: any) {
return new Array(length).fill(s.categories[0]); return new Array(length).fill(s.categories[0]);
default: default:
throw new Error("unkonwn type"); throw new Error("unknown type");
} }
} }
@@ -1,4 +1,4 @@
import { RawSchema } from "../../../../src/common/types/entities"; import { RawSchema } from "../../../../src/common/types/schema";
export const schema: { schema: RawSchema } = { export const schema: { schema: RawSchema } = {
schema: { schema: {
@@ -5,7 +5,7 @@ import zip from "lodash.zip";
import _ from "lodash"; import _ from "lodash";
import { flatbuffers } from "flatbuffers"; import { flatbuffers } from "flatbuffers";
import { NetEncoding } from "../../../src/util/stateManager/matrix_generated"; import { NetEncoding } from "../../../src/util/stateManager/matrix_generated";
import { RawSchema } from "../../../src/common/types/entities"; import { RawSchema } from "../../../src/common/types/schema";
/* /*
test data mocking REST 0.2 API responses. Used in several tests. test data mocking REST 0.2 API responses. Used in several tests.
+4 -1
View File
@@ -37,7 +37,10 @@ module.exports = {
jsx: true, jsx: true,
generators: true, generators: true,
}, },
project: "./tsconfig.json", // (thuang): Pairing with `tsconfigRootDir`, which points to the directory
// of eslint.js
project: "../../tsconfig.json",
tsconfigRootDir: __dirname,
}, },
rules: { rules: {
"react/jsx-no-target-blank": "off", "react/jsx-no-target-blank": "off",
+2 -2
View File
@@ -8,7 +8,7 @@ import {
removeObsAnnoCategory, removeObsAnnoCategory,
addObsLayout, addObsLayout,
} from "../util/stateManager/schemaHelpers"; } from "../util/stateManager/schemaHelpers";
import { isArrayOrTypedArray } from "../util/typeHelpers"; import { isAnyArray } from "../common/types/arraytypes";
import { _whereCacheCreate } from "./whereCache"; import { _whereCacheCreate } from "./whereCache";
import AnnoMatrix from "./annoMatrix"; import AnnoMatrix from "./annoMatrix";
import PromiseLimit from "../util/promiseLimit"; import PromiseLimit from "../util/promiseLimit";
@@ -134,7 +134,7 @@ export default class AnnoMatrixLoader extends AnnoMatrix {
const newAnnoMatrix = this._clone(); const newAnnoMatrix = this._clone();
let data; let data;
if (isArrayOrTypedArray(value)) { if (isAnyArray(value)) {
if (value.constructor !== Ctor) if (value.constructor !== Ctor)
throw new Error("Mismatched value array type"); throw new Error("Mismatched value array type");
if (value.length !== this.nObs) if (value.length !== this.nObs)
+85
View File
@@ -0,0 +1,85 @@
/**
* Utility type and interface definitions.
*/
/**
* TypedArrays that can be assigned to a number.
*/
export type TypedArray =
| Int8Array
| Uint8Array
| Int16Array
| Uint16Array
| Int32Array
| Uint32Array
| Float32Array
| Float64Array;
export type UnsignedTypedArray = Uint8Array | Uint16Array | Uint32Array;
export type FloatTypedArray = Float32Array | Float64Array;
export type TypedArrayConstructor =
| Int8ArrayConstructor
| Uint8ArrayConstructor
| Int16ArrayConstructor
| Uint16ArrayConstructor
| Int32ArrayConstructor
| Uint32ArrayConstructor
| Float32ArrayConstructor
| Float64ArrayConstructor;
export type AnyArray = Array<unknown> | TypedArray;
export type NumberArray = Array<number> | TypedArray;
export type Int8 = Int8Array[0];
export type Uint8 = Uint8Array[0];
export type Int16 = Int16Array[0];
export type Uint16 = Uint16Array[0];
export type Int32 = Int32Array[0];
export type Uint32 = Uint32Array[0];
export type Float32 = Float32Array[0];
export type Float64 = Float64Array[0];
/**
* Test if the parameter is a TypedArray.
* @param tbd - value to be tested
* @returns true if `tbd` is a TypedArray, false if not.
*/
export function isTypedArray(tbd: unknown): tbd is TypedArray {
return (
ArrayBuffer.isView(tbd) &&
Object.prototype.toString.call(tbd) !== "[object DataView]"
);
}
/**
* Test if the paramter is a float TypedArray
* @param tbd - value to be tested
* @returns - true if `tbd` is a float typed array.
*/
export function isFloatTypedArray(tbd: unknown): tbd is FloatTypedArray {
return tbd instanceof Float32Array || tbd instanceof Float64Array;
}
/**
* Test if the paramter is a float TypedArray
* @param tbd - value to be tested
* @returns - true if `tbd` is a float typed array.
*/
export function isUnsignedTypedArray(tbd: unknown): tbd is UnsignedTypedArray {
return (
tbd instanceof Uint8Array ||
tbd instanceof Uint16Array ||
tbd instanceof Uint32Array
);
}
/**
* Test if the parameter is a TypedArray or Array
* @param tbd - value to be tested
* @returns - true if `tbd` is a TypedArray or Array
*/
export function isAnyArray(tbd: unknown): tbd is AnyArray {
return Array.isArray(tbd) || isTypedArray(tbd);
}
+1 -58
View File
@@ -1,60 +1,3 @@
// If a globally shared type or interface doesn't have a clear owner, put it here // If a globally shared type or interface doesn't have a clear owner, put it here
export type Category = number | string | boolean; export {};
export interface AnnotationColumn {
categories?: Category[];
name: string;
type: "string" | "float32" | "int32" | "categorical" | "boolean";
writable: boolean;
}
interface DataFrame {
nObs: number;
nVar: number;
// TODO(thuang): Not sure what other types are available
type: "float32";
}
export interface LayoutColumn {
dims: string[];
name: string;
// TODO(thuang): Not sure what other types are available
type: "float32";
}
interface RawLayout {
obs: LayoutColumn[];
var?: LayoutColumn[];
}
interface RawAnnotations {
obs: {
columns: AnnotationColumn[];
index: string;
};
var: {
columns: AnnotationColumn[];
index: string;
};
}
export interface RawSchema {
annotations: RawAnnotations;
dataframe: DataFrame;
layout: RawLayout;
}
interface Annotations extends RawAnnotations {
obsByName: { [name: string]: AnnotationColumn };
varByName: { [name: string]: AnnotationColumn };
}
interface Layout extends RawLayout {
obsByName: { [name: string]: LayoutColumn };
varByName: { [name: string]: LayoutColumn };
}
export interface Schema extends RawSchema {
annotations: Annotations;
layout: Layout;
}
+58
View File
@@ -0,0 +1,58 @@
type Category = number | string | boolean;
export interface AnnotationColumnSchema {
categories?: Category[];
name: string;
type: "string" | "float32" | "int32" | "categorical" | "boolean";
writable: boolean;
}
interface XMatrixSchema {
nObs: number;
nVar: number;
// TODO(thuang): Not sure what other types are available
type: "float32";
}
export interface EmbeddingSchema {
dims: string[];
name: string;
// TODO(thuang): Not sure what other types are available
type: "float32";
}
interface RawLayoutSchema {
obs: EmbeddingSchema[];
var?: EmbeddingSchema[];
}
interface RawAnnotationsSchema {
obs: {
columns: AnnotationColumnSchema[];
index: string;
};
var: {
columns: AnnotationColumnSchema[];
index: string;
};
}
export interface RawSchema {
annotations: RawAnnotationsSchema;
dataframe: XMatrixSchema;
layout: RawLayoutSchema;
}
interface AnnotationsSchema extends RawAnnotationsSchema {
obsByName: { [name: string]: AnnotationColumnSchema };
varByName: { [name: string]: AnnotationColumnSchema };
}
interface LayoutSchema extends RawLayoutSchema {
obsByName: { [name: string]: EmbeddingSchema };
varByName: { [name: string]: EmbeddingSchema };
}
export interface Schema extends RawSchema {
annotations: AnnotationsSchema;
layout: LayoutSchema;
}
+79 -40
View File
@@ -51,27 +51,55 @@ history state processing. The undoable action object contents, by key:
filter state are entirely at the discretion of the action filter. filter state are entirely at the discretion of the action filter.
*/ */
import { Reducer, AnyAction } from "redux";
import fromEntries from "../util/fromEntries"; import fromEntries from "../util/fromEntries";
const historyKeyPrefix = "@@undoable/"; export const pastKey = "@@undoable/past";
const pastKey = `${historyKeyPrefix}past`; export const futureKey = "@@undoable/future";
const futureKey = `${historyKeyPrefix}future`; export const filterStateKey = "@@undoable/filterState";
const filterStateKey = `${historyKeyPrefix}filterState`; export const filterActionKey = "@@undoable/filterAction";
const filterActionKey = `${historyKeyPrefix}filterAction`; export const pendingKey = "@@undoable/pending";
const pendingKey = `${historyKeyPrefix}pending`;
const defaultHistoryLimit = -100; const defaultHistoryLimit = -100;
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS. export interface UndoableFilterState {
const Undoable = (reducer: any, undoableKeys: any, options = {}) => { [name: string]: unknown;
// @ts-expect-error ts-migrate(2339) FIXME: Property 'debug' does not exist on type '{}'. }
const { debug } = options;
// @ts-expect-error ts-migrate(2339) FIXME: Property 'historyLimit' does not exist on type '{}... Remove this comment to see the full error message export interface UndoableConfig<FilterStateType extends UndoableFilterState> {
debug?: boolean | number;
historyLimit?: number;
actionFilter?: ActionFilterFn<FilterStateType>;
}
export interface UndoableAction<FilterStateType extends UndoableFilterState> {
[filterActionKey]: string;
[filterStateKey]?: FilterStateType;
}
export type ActionFilterFn<FilterStateType extends UndoableFilterState> = (
undoableState: UndoableState<FilterStateType>,
action: AnyAction,
filterState?: FilterStateType
) => UndoableAction<FilterStateType>;
export interface UndoableState<FilterStateType extends UndoableFilterState> {
[pastKey]: [string, unknown][][];
[futureKey]: [string, unknown][][];
[pendingKey]: [string, unknown][] | null;
[filterStateKey]: FilterStateType | undefined;
}
const Undoable = <FilterStateType extends UndoableFilterState>(
reducer: Reducer,
undoableKeys: string[],
options: UndoableConfig<FilterStateType> = {}
): Reducer => {
const debug = options?.debug ?? false;
let { historyLimit } = options; let { historyLimit } = options;
if (!historyLimit) historyLimit = defaultHistoryLimit; if (!historyLimit) historyLimit = defaultHistoryLimit;
if (historyLimit > 0) historyLimit = -historyLimit; if (historyLimit > 0) historyLimit = -historyLimit;
const actionFilter = const actionFilter: ActionFilterFn<FilterStateType> =
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. options?.actionFilter ?? (() => ({ [filterActionKey]: "save" }));
(options as any).actionFilter || (() => ({ [filterActionKey]: "save" }));
if (!Array.isArray(undoableKeys) || undoableKeys.length === 0) if (!Array.isArray(undoableKeys) || undoableKeys.length === 0)
throw new Error("undoable keys array must be specified"); throw new Error("undoable keys array must be specified");
@@ -80,8 +108,9 @@ const Undoable = (reducer: any, undoableKeys: any, options = {}) => {
/* /*
Undo the current to previous history Undo the current to previous history
*/ */
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. function undo(
function undo(currentState: any) { currentState: UndoableState<FilterStateType>
): UndoableState<FilterStateType> {
const past = currentState[pastKey]; const past = currentState[pastKey];
const future = currentState[futureKey]; const future = currentState[futureKey];
if (past.length === 0) return currentState; if (past.length === 0) return currentState;
@@ -89,7 +118,7 @@ const Undoable = (reducer: any, undoableKeys: any, options = {}) => {
undoableKeysSet.has(kv[0]) undoableKeysSet.has(kv[0])
); );
const newPast = [...past]; const newPast = [...past];
const newState = newPast.pop(); const newState = newPast.pop() || [];
const newFuture = push(future, currentUndoableState); const newFuture = push(future, currentUndoableState);
const nextState = { const nextState = {
...currentState, ...currentState,
@@ -104,8 +133,9 @@ const Undoable = (reducer: any, undoableKeys: any, options = {}) => {
/* /*
Replay future, previously undone. Replay future, previously undone.
*/ */
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. function redo(
function redo(currentState: any) { currentState: UndoableState<FilterStateType>
): UndoableState<FilterStateType> {
const past = currentState[pastKey] || []; const past = currentState[pastKey] || [];
const future = currentState[futureKey] || []; const future = currentState[futureKey] || [];
if (future.length === 0) return currentState; if (future.length === 0) return currentState;
@@ -113,7 +143,7 @@ const Undoable = (reducer: any, undoableKeys: any, options = {}) => {
undoableKeysSet.has(kv[0]) undoableKeysSet.has(kv[0])
); );
const newFuture = [...future]; const newFuture = [...future];
const newState = newFuture.pop(); const newState = newFuture.pop() || [];
const newPast = push(past, currentUndoableState); const newPast = push(past, currentUndoableState);
const nextState = { const nextState = {
...currentState, ...currentState,
@@ -128,13 +158,14 @@ const Undoable = (reducer: any, undoableKeys: any, options = {}) => {
/* /*
Clear the history state. No side-effects on current state. Clear the history state. No side-effects on current state.
*/ */
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. function clear(
function clear(currentState: any) { currentState: UndoableState<FilterStateType>
): UndoableState<FilterStateType> {
return { return {
...currentState, ...currentState,
[pastKey]: [], [pastKey]: [],
[futureKey]: [], [futureKey]: [],
[filterStateKey]: {}, [filterStateKey]: undefined,
[pendingKey]: null, [pendingKey]: null,
}; };
} }
@@ -142,8 +173,11 @@ const Undoable = (reducer: any, undoableKeys: any, options = {}) => {
/* /*
Reduce current action, with no history side-effects Reduce current action, with no history side-effects
*/ */
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. function skip(
function skip(currentState: any, action: any, filterState: any) { currentState: UndoableState<FilterStateType>,
action: AnyAction,
filterState: UndoableFilterState
): UndoableState<FilterStateType> {
const past = currentState[pastKey] || []; const past = currentState[pastKey] || [];
const future = currentState[futureKey] || []; const future = currentState[futureKey] || [];
const pending = currentState[pendingKey]; const pending = currentState[pendingKey];
@@ -160,8 +194,11 @@ const Undoable = (reducer: any, undoableKeys: any, options = {}) => {
/* /*
Save current state in the history, then reduce action. Save current state in the history, then reduce action.
*/ */
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. function save(
function save(currentState: any, action: any, filterState: any) { currentState: UndoableState<FilterStateType>,
action: AnyAction,
filterState: UndoableFilterState
): UndoableState<FilterStateType> {
const past = currentState[pastKey] || []; const past = currentState[pastKey] || [];
const currentUndoableState = Object.entries(currentState).filter((kv) => const currentUndoableState = Object.entries(currentState).filter((kv) =>
undoableKeysSet.has(kv[0]) undoableKeysSet.has(kv[0])
@@ -181,8 +218,9 @@ const Undoable = (reducer: any, undoableKeys: any, options = {}) => {
/* /*
Save current state as pending history change. No other side effects. Save current state as pending history change. No other side effects.
*/ */
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. function stashPending(
function stashPending(currentState: any) { currentState: UndoableState<FilterStateType>
): UndoableState<FilterStateType> {
const currentUndoableState = Object.entries(currentState).filter((kv) => const currentUndoableState = Object.entries(currentState).filter((kv) =>
undoableKeysSet.has(kv[0]) undoableKeysSet.has(kv[0])
); );
@@ -195,8 +233,9 @@ const Undoable = (reducer: any, undoableKeys: any, options = {}) => {
/* /*
Cancel pending history state change. No other side effects. Cancel pending history state change. No other side effects.
*/ */
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. function cancelPending(
function cancelPending(currentState: any) { currentState: UndoableState<FilterStateType>
): UndoableState<FilterStateType> {
return { return {
...currentState, ...currentState,
[pendingKey]: null, [pendingKey]: null,
@@ -206,10 +245,12 @@ const Undoable = (reducer: any, undoableKeys: any, options = {}) => {
/* /*
Push pending state onto the history stack Push pending state onto the history stack
*/ */
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. function applyPending(
function applyPending(currentState: any) { currentState: UndoableState<FilterStateType>
const past = currentState[pastKey] || []; ): UndoableState<FilterStateType> {
const past = currentState[pastKey];
const pendingState = currentState[pendingKey]; const pendingState = currentState[pendingKey];
if (pendingState === null) return currentState;
const newPast = push(past, pendingState, historyLimit); const newPast = push(past, pendingState, historyLimit);
const nextState = { const nextState = {
...currentState, ...currentState,
@@ -221,14 +262,13 @@ const Undoable = (reducer: any, undoableKeys: any, options = {}) => {
} }
return ( return (
currentState = { currentState: UndoableState<FilterStateType> = {
[pastKey]: [], [pastKey]: [],
[futureKey]: [], [futureKey]: [],
[filterStateKey]: {}, [filterStateKey]: undefined,
[pendingKey]: null, [pendingKey]: null,
}, },
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. action: AnyAction
action: any
) => { ) => {
if (debug > 1) console.log("---- ACTION", action.type); if (debug > 1) console.log("---- ACTION", action.type);
const aType = action.type; const aType = action.type;
@@ -288,8 +328,7 @@ const Undoable = (reducer: any, undoableKeys: any, options = {}) => {
}; };
}; };
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. function push<T = unknown>(arr: T[], val: T, limit?: number) {
function push(arr: any, val: any, limit = undefined) {
/* /*
functional array push, with a max length limit to the new array. functional array push, with a max length limit to the new array.
Like Array.push, except it returns new array and discards as needed Like Array.push, except it returns new array and discards as needed
+99 -79
View File
@@ -1,13 +1,19 @@
import StateMachine from "../util/statemachine"; import { AnyAction } from "redux";
import { StateMachine, FsmActionFn, FsmErrorFn } from "../util/statemachine";
import {
UndoableConfig,
UndoableState,
UndoableFilterState,
UndoableAction,
filterActionKey,
filterStateKey,
} from "./undoable";
import createFsmTransitions from "./undoableFsm"; import createFsmTransitions from "./undoableFsm";
const actionKey = "@@undoable/filterAction";
const stateKey = "@@undoable/filterState";
/* /*
these actions will not affect history these actions will not affect history
*/ */
const skipOnActions = new Set([ const skipOnActions = new Set<string>([
"annoMatrix: init complete", "annoMatrix: init complete",
"url changed", "url changed",
"initial data load start", "initial data load start",
@@ -58,12 +64,12 @@ const skipOnActions = new Set([
identical, repeated occurances of these action types will be debounced. identical, repeated occurances of these action types will be debounced.
Entire action must be identical (all keys). Entire action must be identical (all keys).
*/ */
const debounceOnActions = new Set([]); const debounceOnActions = new Set<string>([]);
/* /*
history will be cleared when these actions occur history will be cleared when these actions occur
*/ */
const clearOnActions = new Set([ const clearOnActions = new Set<string>([
"initial data load complete", "initial data load complete",
"initial data load error", "initial data load error",
]); ]);
@@ -71,7 +77,7 @@ const clearOnActions = new Set([
/* /*
An immediate history save will be done for these An immediate history save will be done for these
*/ */
const saveOnActions = new Set([ const saveOnActions = new Set<string>([
"categorical metadata filter select", "categorical metadata filter select",
"categorical metadata filter deselect", "categorical metadata filter deselect",
"categorical metadata filter all of these", "categorical metadata filter all of these",
@@ -123,35 +129,43 @@ StateMachine - processing complex action handling - see FSM graph for
actual structure, in undoableFsm.js actual structure, in undoableFsm.js
**/ **/
interface MyFilterState extends UndoableFilterState {
prevAction?: AnyAction;
fsm: StateMachine<MyUndoableAction> | null;
}
type MyUndoableAction = UndoableAction<MyFilterState>;
/* /*
Default FSM actions. Used to side-effect transitions in the graph. Default FSM actions. Used to side-effect transitions in the graph.
See graph definition for the transitions that use each. See graph definition for the transitions that use each.
Signature: (fsm, transition, reducerState, reducerAction) => undoableAction Signature: (fsm, transition, reducerState, reducerAction) => undoableAction
*/ */
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. const stashPending: FsmActionFn<MyUndoableAction> = (
const stashPending = (fsm: any) => ({ fsm: StateMachine<MyUndoableAction>
[actionKey]: "stashPending", ) => ({
[stateKey]: { fsm }, [filterActionKey]: "stashPending",
[filterStateKey]: { fsm },
}); });
const cancelPending = () => ({ const cancelPending: FsmActionFn<MyUndoableAction> = () => ({
[actionKey]: "cancelPending", [filterActionKey]: "cancelPending",
[stateKey]: { fsm: null }, [filterStateKey]: { fsm: null },
}); });
const applyPending = () => ({ const applyPending: FsmActionFn<MyUndoableAction> = () => ({
[actionKey]: "applyPending", [filterActionKey]: "applyPending",
[stateKey]: { fsm: null }, [filterStateKey]: { fsm: null },
}); });
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'fsm' implicitly has an 'any' type. const skip: FsmActionFn<MyUndoableAction> = (fsm, transition) => ({
const skip = (fsm, transition) => ({ [filterActionKey]: "skip",
[actionKey]: "skip", [filterStateKey]: { fsm: transition.to !== "done" ? fsm : null },
[stateKey]: { fsm: transition.to !== "done" ? fsm : null },
}); });
const clear = () => ({ [actionKey]: "clear", [stateKey]: { fsm: null } }); const clear: FsmActionFn<MyUndoableAction> = () => ({
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'fsm' implicitly has an 'any' type. [filterActionKey]: "clear",
const save = (fsm, transition) => ({ [filterStateKey]: { fsm: null },
[actionKey]: "save", });
[stateKey]: { fsm: transition.to !== "done" ? fsm : null }, const save: FsmActionFn<MyUndoableAction> = (fsm, transition) => ({
[filterActionKey]: "save",
[filterStateKey]: { fsm: transition.to !== "done" ? fsm : null },
}); });
/* /*
@@ -160,11 +174,13 @@ StateMachine when it doesn't know what to do.
Signature: (fsm, event, from) => undoableAction Signature: (fsm, event, from) => undoableAction
*/ */
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. const onFsmError: FsmErrorFn<MyUndoableAction> = (fsm, event, from) => {
const onFsmError = (fsm: any, event: any, from: any) => {
console.error(`FSM error [event: "${event}", state: "${from}"]`, fsm); console.error(`FSM error [event: "${event}", state: "${from}"]`, fsm);
// In production, try to recover gracefully if we have unexpected state // In production, try to recover gracefully if we have unexpected state
return clear(); return {
[filterActionKey]: "clear",
[filterStateKey]: { fsm: null },
};
}; };
/* /*
@@ -179,7 +195,11 @@ const fsmTransitions = createFsmTransitions(
save save
); );
/* State machine we clone whenever we need to run it */ /* State machine we clone whenever we need to run it */
const seedFsm = new StateMachine("init", fsmTransitions, onFsmError); const seedFsm = new StateMachine<MyUndoableAction>(
"init",
fsmTransitions,
onFsmError
);
/* /*
See undoable.js for description action filter interface description. See undoable.js for description action filter interface description.
@@ -189,53 +209,52 @@ Basic approach:
* only implement complex state machines where absolutely required (eg, * only implement complex state machines where absolutely required (eg,
multi-event selection and the like) multi-event selection and the like)
*/ */
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. const actionFilter =
const actionFilter = (debug: any) => ( (debug: boolean) =>
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. (
state: any, state: UndoableState<MyFilterState>,
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. action: AnyAction,
action: any, prevFilterState: MyFilterState | undefined
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. ): UndoableAction<MyFilterState> => {
prevFilterState: any const actionType = action.type;
) => { prevFilterState = prevFilterState || { fsm: null };
const actionType = action.type; const filterState: MyFilterState = {
const filterState = { ...prevFilterState,
...prevFilterState, prevAction: action,
prevAction: action, };
}; if (skipOnActions.has(actionType)) {
if (skipOnActions.has(actionType)) { return { [filterActionKey]: "skip", [filterStateKey]: filterState };
return { [actionKey]: "skip", [stateKey]: filterState }; }
} if (
if ( debounceOnActions.has(actionType) &&
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'any' is not assignable to parame... Remove this comment to see the full error message prevFilterState.prevAction &&
debounceOnActions.has(actionType) && shallowObjectEq(action, prevFilterState.prevAction)
shallowObjectEq(action, prevFilterState.prevAction) ) {
) { return { [filterActionKey]: "skip", [filterStateKey]: filterState };
return { [actionKey]: "skip", [stateKey]: filterState }; }
} if (clearOnActions.has(actionType)) {
if (clearOnActions.has(actionType)) { return { [filterActionKey]: "clear", [filterStateKey]: filterState };
return { [actionKey]: "clear", [stateKey]: filterState }; }
} if (saveOnActions.has(actionType)) {
if (saveOnActions.has(actionType)) { return { [filterActionKey]: "save", [filterStateKey]: filterState };
return { [actionKey]: "save", [stateKey]: filterState }; }
}
/* /*
Else, something more complex OR unknown to us.... Else, something more complex OR unknown to us....
*/ */
if (seedFsm.events.has(actionType)) { if (seedFsm.events.has(actionType)) {
let { fsm } = filterState; let { fsm } = filterState;
if (!fsm) { if (!fsm) {
/* no active FSM, so create one in init state */ /* no active FSM, so create one in init state */
fsm = seedFsm.clone("init"); fsm = seedFsm.clone("init");
}
return fsm.next(action.type, { state, action });
} }
return fsm.next(action.type, { state, action });
}
/* else, we have no idea what this is - skip it */ /* else, we have no idea what this is - skip it */
if (debug) console.log("**** ACTION FILTER EVENT HANDLER MISS", actionType); if (debug) console.log("**** ACTION FILTER EVENT HANDLER MISS", actionType);
return { [actionKey]: "skip", [stateKey]: filterState }; return { [filterActionKey]: "skip", [filterStateKey]: filterState };
}; };
/* /*
return true if objA and objB are ===, OR if: return true if objA and objB are ===, OR if:
@@ -243,8 +262,10 @@ return true if objA and objB are ===, OR if:
- have same own properties - have same own properties
- all values are strict equal (===) - all values are strict equal (===)
*/ */
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. function shallowObjectEq(
function shallowObjectEq(objA: any, objB: any) { objA: Record<string | number | symbol, unknown>,
objB: Record<string | number | symbol, unknown>
) {
if (objA === objB) return true; if (objA === objB) return true;
if (!objA || !objB) return false; if (!objA || !objB) return false;
if (!shallowArrayEq(Object.keys(objA), Object.keys(objB))) return false; if (!shallowArrayEq(Object.keys(objA), Object.keys(objB))) return false;
@@ -256,8 +277,7 @@ function shallowObjectEq(objA: any, objB: any) {
return true if arrA and arrB contain the same strict-equal values, return true if arrA and arrB contain the same strict-equal values,
in the same order. in the same order.
*/ */
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. function shallowArrayEq(arrA: unknown[], arrB: unknown[]) {
function shallowArrayEq(arrA: any, arrB: any) {
if (arrA.length !== arrB.length) return false; if (arrA.length !== arrB.length) return false;
for (let i = 0, l = arrA.length; i < l; i += 1) { for (let i = 0, l = arrA.length; i < l; i += 1) {
if (arrA[i] !== arrB[i]) return false; if (arrA[i] !== arrB[i]) return false;
@@ -272,7 +292,7 @@ Set to true or 1 for base logging, high number for more verbosity (currently onl
or 2). or 2).
*/ */
const debug = false; const debug = false;
const undoableConfig = { const undoableConfig: UndoableConfig<MyFilterState> = {
debug, debug,
historyLimit: 50, // maximum history size historyLimit: 50, // maximum history size
actionFilter: actionFilter(debug), actionFilter: actionFilter(debug),
@@ -311,7 +331,7 @@ if (debug) {
); );
if (trivialOverlapWithFsm.size > 0) { if (trivialOverlapWithFsm.size > 0) {
console.error( console.error(
"Undoable misconfiguration - trivival action filter blocking FSM filter", "Undoable misconfiguration - trivial action filter blocking FSM filter",
[...trivialOverlapWithFsm] [...trivialOverlapWithFsm]
); );
} }
+24 -26
View File
@@ -18,22 +18,16 @@ b) compound actions that should be collapsed into a single history change.
*/ */
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS. import { StateMachine, FsmTransition, FsmActionFn } from "../util/statemachine";
const createFsmTransitions = (
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS. const createFsmTransitions = <ActionReturnType>(
stashPending: any, stashPending: FsmActionFn<ActionReturnType>,
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS. cancelPending: FsmActionFn<ActionReturnType>,
cancelPending: any, applyPending: FsmActionFn<ActionReturnType>,
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS. skip: FsmActionFn<ActionReturnType>,
applyPending: any, _clear: FsmActionFn<ActionReturnType>,
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS. save: FsmActionFn<ActionReturnType>
skip: any, ): FsmTransition<ActionReturnType>[] => [
// @ts-expect-error ts-migrate(6133) FIXME: 'clear' is declared but its value is never read.
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
clear: any,
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
save: any
) => [
/* graph selection brushing */ /* graph selection brushing */
{ {
event: "graph brush start", event: "graph brush start",
@@ -52,12 +46,14 @@ const createFsmTransitions = (
from: "graph brush in progress", from: "graph brush in progress",
to: "done", to: "done",
/* if current selection is all, cancelPending. Else, applyPending */ /* if current selection is all, cancelPending. Else, applyPending */
// @ts-expect-error ts-migrate(6133) FIXME: 'fsm' is declared but its value is never read. action: (
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. fsm: StateMachine<ActionReturnType>,
action: (fsm: any, transition: any, data: any) => transition: FsmTransition<ActionReturnType>,
data: any // eslint-disable-line @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS. Requires state typing.
) =>
data.state.graphSelection.selection.mode === "all" data.state.graphSelection.selection.mode === "all"
? cancelPending() ? cancelPending(fsm, transition, data)
: applyPending(), : applyPending(fsm, transition, data),
}, },
{ {
event: "graph brush end", event: "graph brush end",
@@ -84,12 +80,14 @@ const createFsmTransitions = (
from: "graph lasso in progress", from: "graph lasso in progress",
to: "done", to: "done",
/* if current selection is all, cancelPending. Else, applyPending */ /* if current selection is all, cancelPending. Else, applyPending */
// @ts-expect-error ts-migrate(6133) FIXME: 'fsm' is declared but its value is never read. action: (
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. fsm: StateMachine<ActionReturnType>,
action: (fsm: any, transition: any, data: any) => transition: FsmTransition<ActionReturnType>,
data: any // eslint-disable-line @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS. Requires state typing.
) =>
data.state.graphSelection.selection.mode === "all" data.state.graphSelection.selection.mode === "all"
? cancelPending() ? cancelPending(fsm, transition, data)
: applyPending(), : applyPending(fsm, transition, data),
}, },
{ {
event: "graph lasso end", event: "graph lasso end",
+3 -8
View File
@@ -1,12 +1,7 @@
import { IdentityInt32Index, isLabelIndex } from "./labelIndex"; import { IdentityInt32Index, isLabelIndex } from "./labelIndex";
// weird cross-dependency that we should clean up someday... // weird cross-dependency that we should clean up someday...
import { import { callOnceLazy, memoize, __getMemoId } from "./util";
isTypedArray, import { isTypedArray, isAnyArray } from "../../common/types/arraytypes";
isArrayOrTypedArray,
callOnceLazy,
memoize,
__getMemoId,
} from "./util";
import { import {
summarizeContinuous, summarizeContinuous,
summarizeCategorical as _summarizeCategorical, summarizeCategorical as _summarizeCategorical,
@@ -163,7 +158,7 @@ class Dataframe {
if (!Array.isArray(columnarData)) { if (!Array.isArray(columnarData)) {
throw new TypeError("Dataframe constructor requires array of columns"); throw new TypeError("Dataframe constructor requires array of columns");
} }
if (!columnarData.every((c) => isArrayOrTypedArray(c))) { if (!columnarData.every((c) => isAnyArray(c))) {
throw new TypeError("Dataframe columns must all be Array or TypedArray"); throw new TypeError("Dataframe columns must all be Array or TypedArray");
} }
if (!isLabelIndex(rowIndex)) { if (!isLabelIndex(rowIndex)) {
+1 -1
View File
@@ -1,7 +1,7 @@
/* /*
Dataframe histogram Dataframe histogram
*/ */
import { isTypedArray } from "./util"; import { isTypedArray } from "../../common/types/arraytypes";
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
function _histogramContinuous(column: any, bins: any, min: any, max: any) { function _histogramContinuous(column: any, bins: any, min: any, max: any) {
-2
View File
@@ -2,8 +2,6 @@
Private utility code for dataframe Private utility code for dataframe
*/ */
export { isTypedArray, isArrayOrTypedArray } from "../typeHelpers";
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS. // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
export function callOnceLazy(f: any) { export function callOnceLazy(f: any) {
/* /*
@@ -3,7 +3,7 @@ Helper functions for user-editable annotations state management.
See also reducers/annotations.js See also reducers/annotations.js
*/ */
import { Schema } from "../../common/types/entities"; import { Schema } from "../../common/types/schema";
/* /*
There are a number of state constraints assumed throughout the There are a number of state constraints assumed throughout the
+3 -3
View File
@@ -1,6 +1,6 @@
import { flatbuffers } from "flatbuffers"; import { flatbuffers } from "flatbuffers";
import { NetEncoding } from "./matrix_generated"; import { NetEncoding } from "./matrix_generated";
import { isTypedArray, isFpTypedArray } from "../typeHelpers"; import { isTypedArray, isFloatTypedArray } from "../../common/types/arraytypes";
import { import {
Dataframe, Dataframe,
IdentityInt32Index, IdentityInt32Index,
@@ -188,7 +188,7 @@ function promoteTypedArray(o: any) {
TODO - future optimization: not all int32/uint32 data series require TODO - future optimization: not all int32/uint32 data series require
promotion to float64. We COULD simply look at the data to decide. promotion to float64. We COULD simply look at the data to decide.
*/ */
if (isFpTypedArray(o) || Array.isArray(o)) return o; if (isFloatTypedArray(o) || Array.isArray(o)) return o;
let TypedArrayCtor; let TypedArrayCtor;
switch (o.constructor) { switch (o.constructor) {
@@ -246,7 +246,7 @@ export function matrixFBSToDataframe(arrayBuffers: any) {
.map((fb: any) => .map((fb: any) =>
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
fb.columns.map((c: any) => { fb.columns.map((c: any) => {
if (isFpTypedArray(c) || Array.isArray(c)) return c; if (isFloatTypedArray(c) || Array.isArray(c)) return c;
return promoteTypedArray(c); return promoteTypedArray(c);
}) })
) )
@@ -11,9 +11,9 @@ import catLabelSort from "../catLabelSort";
import { import {
RawSchema, RawSchema,
Schema, Schema,
LayoutColumn, EmbeddingSchema,
AnnotationColumn, AnnotationColumnSchema,
} from "../../common/types/entities"; } from "../../common/types/schema";
/* /*
System wide schema assumptions: System wide schema assumptions:
@@ -86,7 +86,7 @@ export function removeObsAnnoColumn(schema: Schema, name: string): Schema {
export function addObsAnnoColumn( export function addObsAnnoColumn(
schema: Schema, schema: Schema,
_: string, _: string,
defn: AnnotationColumn defn: AnnotationColumnSchema
): Schema { ): Schema {
const newSchema = _copyObsAnno(schema); const newSchema = _copyObsAnno(schema);
@@ -142,7 +142,7 @@ export function addObsAnnoCategory(schema: any, name: any, category: any) {
return newSchema; return newSchema;
} }
export function addObsLayout(schema: Schema, layout: LayoutColumn): Schema { export function addObsLayout(schema: Schema, layout: EmbeddingSchema): Schema {
/* add or replace a layout */ /* add or replace a layout */
const newSchema = _copyObsLayout(schema); const newSchema = _copyObsLayout(schema);
newSchema.layout.obs.push(layout); newSchema.layout.obs.push(layout);
+56 -41
View File
@@ -13,18 +13,17 @@ Where:
to: state_name_transitioning_to, to: state_name_transitioning_to,
from: state_name_transitioning_from, from: state_name_transitioning_from,
event: value_that_will_cause_transition, event: value_that_will_cause_transition,
action: optional_callback_upon_transition action: callback_upon_transition
} }
The transition will be provided to the action callback, so other data The transition will be provided to the action callback, so other data
may be stored in the transition object for use by the action callback. may be stored in the transition object for use by the action callback.
* onErrorCallback - a callback function called if the FSM receives an event * onErrorCallback - a callback function called if the FSM receives an event
for which it has no defined transition. for which it has no defined transition.
Interface: Interface:
* states - property containing the state names. A Set(), contianing the * states - property containing the state names. A Set(), containing the
union of to: and from: values. union of to: and from: values.
* events - property containing all of the accepted event values. Set(). * events - property containing all of the accepted event values. Set().
* graph - a Map of Maps, organized as graph[eventValue][fromStateValue] * graph - a Map of Maps, organized as graph[eventValue][fromStateValue]
* clone() - clone the entire statemachine. * clone() - clone the entire statemachine.
* next(eventValue) - drive the FSM to the next state. If the event * next(eventValue) - drive the FSM to the next state. If the event
@@ -40,47 +39,69 @@ Example:
const fsm = new StateMachine("A", transitions, () => { throw new Error("oops") }); const fsm = new StateMachine("A", transitions, () => { throw new Error("oops") });
fsm.next("yo"); // returns 42 fsm.next("yo"); // returns 42
*/ */
export default class StateMachine {
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
events: any;
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. export type FsmState = number | string;
graph: any; export type FsmEvent = string; // by convention, we assume Events are redux action types, aka strings
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. export type FsmActionFn<ActionReturnType> = (
onError: any; fsm: StateMachine<ActionReturnType>,
transition: FsmTransition<ActionReturnType>,
data: unknown
) => ActionReturnType;
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. export interface FsmTransition<ActionReturnType> {
state: any; from: FsmState;
to: FsmState;
event: FsmEvent;
action: FsmActionFn<ActionReturnType>;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. export type FsmErrorFn<ActionReturnType> = (
states: any; fsm: StateMachine<ActionReturnType>,
event: FsmEvent,
state: FsmState
) => ActionReturnType;
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS. export class StateMachine<ActionReturnType> {
constructor(initState: any, transitions: any, onError: any) { events: Set<FsmEvent>;
this.onError = onError || (() => undefined);
graph: Map<FsmEvent, Map<FsmState, FsmTransition<ActionReturnType>>>;
onError: FsmErrorFn<ActionReturnType>;
state: FsmState;
states: Set<FsmState>;
constructor(
initState: FsmState,
transitions: FsmTransition<ActionReturnType>[],
onError: FsmErrorFn<ActionReturnType>
) {
this.onError = onError;
this.state = initState; this.state = initState;
// all states // all states
this.states = new Set( this.states = new Set(
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. transitions.reduce(
transitions.reduce((names: any, tsn: any) => { (names: Array<FsmState>, tsn: FsmTransition<ActionReturnType>) => {
names.push(tsn.from); names.push(tsn.from);
names.push(tsn.to); names.push(tsn.to);
return names; return names;
}, []) },
[]
)
); );
// all transition names (aka events) // all transition names (aka events)
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. this.events = new Set(
this.events = new Set(transitions.map((tsn: any) => tsn.event)); transitions.map((tsn: FsmTransition<ActionReturnType>) => tsn.event)
);
// the transition graph. // the transition graph.
// graph[event][from] -> transition // graph[event][from] -> transition
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. this.graph = transitions.reduce((graph, tsn) => {
this.graph = transitions.reduce((graph: any, tsn: any) => {
const { event, from } = tsn; const { event, from } = tsn;
if (!graph.has(event)) graph.set(event, new Map()); if (!graph.has(event)) graph.set(event, new Map());
const tsnMap = graph.get(event); const tsnMap = graph.get(event);
@@ -89,29 +110,23 @@ export default class StateMachine {
}, new Map()); }, new Map());
} }
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS. clone(initState: FsmState): StateMachine<ActionReturnType> {
clone(initState: any) { const fsm = new StateMachine<ActionReturnType>(initState, [], this.onError);
// @ts-expect-error ts-migrate(2554) FIXME: Expected 3 arguments, but got 2.
const fsm = new StateMachine(initState, []);
fsm.onError = this.onError;
fsm.states = this.states; fsm.states = this.states;
fsm.events = this.events; fsm.events = this.events;
fsm.graph = this.graph; fsm.graph = this.graph;
return fsm; return fsm;
} }
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS. next(event: FsmEvent, data: unknown): ActionReturnType {
next(event: any, data: any) {
const { graph, state } = this; const { graph, state } = this;
const tsnMap = graph.get(event); const tsnMap = graph.get(event);
if (!tsnMap) return this.onError(this, event, state, undefined); if (!tsnMap) return this.onError(this, event, state);
const transition = tsnMap.get(state); const transition = tsnMap.get(state);
if (!transition) return this.onError(this, event, state, undefined); if (!transition) return this.onError(this, event, state);
this.state = transition.to; this.state = transition.to;
return transition.action return transition.action(this, transition, data);
? transition.action(this, transition, data)
: undefined;
} }
} }
-32
View File
@@ -1,32 +0,0 @@
/*
Various type and schema related helper functions.
*/
/*
Utility function to test for a typed array
*/
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
export function isTypedArray(x: any) {
return (
ArrayBuffer.isView(x) &&
Object.prototype.toString.call(x) !== "[object DataView]"
);
}
/*
Test for float typed array, ie, Float32TypedArray or Float64TypedArray
*/
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
export function isFpTypedArray(x: any) {
let constructor;
const isFloatArray =
x &&
({ constructor } = x) &&
(constructor === Float32Array || constructor === Float64Array);
return isFloatArray;
}
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
export function isArrayOrTypedArray(x: any) {
return Array.isArray(x) || isTypedArray(x);
}
@@ -9,6 +9,7 @@ import {
upperBoundIndirect, upperBoundIndirect,
} from "./sort"; } from "./sort";
import { makeSortIndex } from "./util"; import { makeSortIndex } from "./util";
import { isAnyArray } from "../../common/types/arraytypes";
class NotImplementedError extends Error { class NotImplementedError extends Error {
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
@@ -450,7 +451,7 @@ class ImmutableScalarDimension extends _ImmutableBaseDimension {
value, value,
new ValueArrayType(data.length) new ValueArrayType(data.length)
); );
} else if (isArrayOrTypedArray(value)) { } else if (isAnyArray(value)) {
// Create value array from user-provided array. Typically used // Create value array from user-provided array. Typically used
// only by enumerated dimensions // only by enumerated dimensions
array = this._createValueArray( array = this._createValueArray(
@@ -729,15 +730,6 @@ export const DimTypes = {
spatial: ImmutableSpatialDimension, spatial: ImmutableSpatialDimension,
}; };
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
function isArrayOrTypedArray(x: any) {
return (
Array.isArray(x) ||
(ArrayBuffer.isView(x) &&
Object.prototype.toString.call(x) !== "[object DataView]")
);
}
/* return bounding box of the polygon */ /* return bounding box of the polygon */
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS. // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
function polygonBoundingBox(polygon: any) { function polygonBoundingBox(polygon: any) {
+7 -7
View File
@@ -1,4 +1,4 @@
import { isTypedArray, isFpTypedArray } from "../typeHelpers"; import { isTypedArray, isFloatTypedArray } from "../../common/types/arraytypes";
/* eslint-disable no-bitwise -- code relies on bitwise ops */ /* eslint-disable no-bitwise -- code relies on bitwise ops */
@@ -219,7 +219,7 @@ export function sortArray(arr: any) {
return quicksort(arr, 0, arr.length - 1); return quicksort(arr, 0, arr.length - 1);
} }
if (isTypedArray(arr)) { if (isTypedArray(arr)) {
if (isFpTypedArray(arr)) { if (isFloatTypedArray(arr)) {
return quicksortFloats(arr, 0, arr.length - 1); return quicksortFloats(arr, 0, arr.length - 1);
} }
return quicksort(arr, 0, arr.length - 1); return quicksort(arr, 0, arr.length - 1);
@@ -230,7 +230,7 @@ export function sortArray(arr: any) {
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS. // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
export function sortIndex(index: any, source: any) { export function sortIndex(index: any, source: any) {
if (isFpTypedArray(source)) if (isFloatTypedArray(source))
return quicksortFloatsIndirect(index, source, 0, index.length - 1); return quicksortFloatsIndirect(index, source, 0, index.length - 1);
return quicksortIndirect(index, source, 0, index.length - 1); return quicksortIndirect(index, source, 0, index.length - 1);
} }
@@ -293,7 +293,7 @@ function lowerBoundFloat(valueArray: any, value: any, first: any, last: any) {
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS. // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
export function lowerBound(valueArray: any, value: any, first: any, last: any) { export function lowerBound(valueArray: any, value: any, first: any, last: any) {
if (isFpTypedArray(valueArray)) { if (isFloatTypedArray(valueArray)) {
return lowerBoundFloat(valueArray, value, first, last); return lowerBoundFloat(valueArray, value, first, last);
} }
return lowerBoundNonFloat(valueArray, value, first, last); return lowerBoundNonFloat(valueArray, value, first, last);
@@ -366,7 +366,7 @@ export function lowerBoundIndirect(
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS. // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
last: any last: any
) { ) {
if (isFpTypedArray(valueArray)) { if (isFloatTypedArray(valueArray)) {
return lowerBoundFloatIndirect(valueArray, indexArray, value, first, last); return lowerBoundFloatIndirect(valueArray, indexArray, value, first, last);
} }
return lowerBoundNonFloatIndirect(valueArray, indexArray, value, first, last); return lowerBoundNonFloatIndirect(valueArray, indexArray, value, first, last);
@@ -425,7 +425,7 @@ function upperBoundFloat(valueArray: any, value: any, first: any, last: any) {
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS. // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
export function upperBound(valueArray: any, value: any, first: any, last: any) { export function upperBound(valueArray: any, value: any, first: any, last: any) {
if (isFpTypedArray(valueArray)) { if (isFloatTypedArray(valueArray)) {
return upperBoundFloat(valueArray, value, first, last); return upperBoundFloat(valueArray, value, first, last);
} }
return upperBoundNonFloat(valueArray, value, first, last); return upperBoundNonFloat(valueArray, value, first, last);
@@ -498,7 +498,7 @@ export function upperBoundIndirect(
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS. // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
last: any last: any
) { ) {
if (isFpTypedArray(valueArray)) { if (isFloatTypedArray(valueArray)) {
return upperBoundFloatIndirect(valueArray, indexArray, value, first, last); return upperBoundFloatIndirect(valueArray, indexArray, value, first, last);
} }
return upperBoundNonFloatIndirect(valueArray, indexArray, value, first, last); return upperBoundNonFloatIndirect(valueArray, indexArray, value, first, last);
+1 -1
View File
@@ -26,7 +26,7 @@ Please scroll down the section below for how to release a patch version. Follow
- Write the release title and release notes and add to [release notes document](https://docs.google.com/document/d/1KnHwkYfhyWO5H8BDcMu7y3ogjvq5Yi4OwpmZ8DB6w0Y/edit) - Write the release title and release notes and add to [release notes document](https://docs.google.com/document/d/1KnHwkYfhyWO5H8BDcMu7y3ogjvq5Yi4OwpmZ8DB6w0Y/edit)
2. Create a release branch, eg, `release-version-0.16.0` 2. Create a release branch, eg, `release-version-0.16.0`
3. In the release branch, run `make create-release-candidate PART=[major | minor | patch]` where you choose major/minor/patch depending on which part of the version is being bumped (e.g., `0.2.9` -> `0.3.0` is minor version bump). This will bump the version and create a release *candidate* version (i.e. `0.3.0-rc.0`). 3. In the release branch, run `make create-release-candidate PART=[major | minor | patch]` where you choose major/minor/patch depending on which part of the version is being bumped (e.g., `0.2.9` -> `0.3.0` is minor version bump). This will bump the version and create a release *candidate* version (i.e. `0.3.0-rc.0`).
4. Commit and push the new branch. This will trigger tests to ensure that your branch isn't broken. 4. Push the new branch to origin and open a `DO NOT MERGE` PR, this will run tests on your branch.
5. Upload the release candidate to Test PyPI by running the command `make release-candidate-to-test-pypi`. (Make sure you are registered for PyPI and Test PyPI and you have write access to the cellxgene PyPI package for both). 5. Upload the release candidate to Test PyPI by running the command `make release-candidate-to-test-pypi`. (Make sure you are registered for PyPI and Test PyPI and you have write access to the cellxgene PyPI package for both).
6. Verify the release candidate in a fresh virtual environment by running `make install-release-test` which installs the cellxgene build you just uploaded the Test PyPI. 6. Verify the release candidate in a fresh virtual environment by running `make install-release-test` which installs the cellxgene build you just uploaded the Test PyPI.
7. If you find errors with the release candidate, run `make recreate-release-candidate` to increment the release candidate version (i.e. `0.3.0-rc.0` -> `0.3.0-rc.1`). Then go back to Steps 5 and 6 to re-upload and re-test the new release candidate. 7. If you find errors with the release candidate, run `make recreate-release-candidate` to increment the release candidate version (i.e. `0.3.0-rc.0` -> `0.3.0-rc.1`). Then go back to Steps 5 and 6 to re-upload and re-test the new release candidate.