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
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,6 @@ Read it before working in `R/` or `srcts/`.

## Conventions

- Source is TypeScript (`tsconfig.json`, `strict` off for now). Lint is eslint 10 + typescript-eslint + prettier 3 (`eslint.config.mjs`, `prettier.config.js`).
- Source is TypeScript (`tsconfig.json`, `strict` on). Lint is eslint 10 + typescript-eslint + prettier 3 (`eslint.config.mjs`, `prettier.config.js`).
- Add a NEWS.md entry for user-facing changes (CONTRIBUTING.md).
- New top-level files need an entry in `.Rbuildignore`, or R CMD check will warn.
10 changes: 5 additions & 5 deletions inst/reactlog/reactlogAsset/reactlog.js

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions inst/reactlog/reactlogAsset/reactlog.js.map

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions memory-bank/jsBuild.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ blank lines.
| File | Role |
| --- | --- |
| `package.json` | npm scripts, `pre-commit` / `lint-staged` hook config, dependencies |
| `tsconfig.json` | `tsc` settings: `noEmit`, `target` es2021, `moduleResolution` bundler, `strict` off |
| `tsconfig.json` | `tsc` settings: `noEmit`, `target` es2021, `moduleResolution` bundler, `strict` on |
| `srcts/modules.d.ts` | `declare module` for untyped `cytoscape` / `cytoscape-dagre`, and the `window` globals |
| `srcts/cyto/cytoFlowType.ts` | Hand-written types for the parts of cytoscape the app uses |
| `eslint.config.mjs` / `prettier.config.js` | Lint and format rules |
Expand Down Expand Up @@ -68,9 +68,9 @@ blank lines.
- `typescript` is pinned to `~6.0`. TypeScript 7 (the Go port) does not offer
the JS API that `typescript-eslint` needs, and `typescript-eslint` 8 lists
`typescript <6.1` as its peer.
- `strict` is off. `npx tsc -p . --strict` reports about 40 errors, mostly
missing null checks, implicit `any`, and class fields that are set outside
the constructor. Fix those in their own change.
- `strict` is on. `GraphAtStep` fields filled by `initStepInfo()` and
`updateFinalFilteredGraph()` (called from the constructor) are marked with
`!`. `no-explicit-any` is still off, so `any` still skips checks.
- cytoscape 3.15 (the locked version) has no bundled types, so it is declared
as an untyped module and the app uses the hand-written types in
`cyto/cytoFlowType.ts`. Newer cytoscape ships `index.d.ts`, but upgrading it
Expand Down
4 changes: 2 additions & 2 deletions memory-bank/viewerUi.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Key files:
| `srcts/layout/progressBar.ts` | Timeline fill, ticks, click/drag to seek |
| `srcts/layout/logEntry.ts` | Step / time / session / status text and the raw JSON panel |
| `srcts/cyto/cytoOn.ts` | Mouse events on the graph (hover, tap, double click) |
| `srcts/utils/queryString.ts`, `srcts/utils/shinytest.ts` | Read `?test=1` |
| `srcts/utils/shinytest.ts` | Read `?test=1` |
| `inst/reactlog/reactlogAsset/` | `reactlog.css`, font CSS, `images/*.svg`, built `reactlog.js` |

## The HTML template
Expand Down Expand Up @@ -157,7 +157,7 @@ Node time labels are separate: `rlog.displayTimeOnNodes` is true unless `window.

## Query params and test mode

`parseQuery()` (`srcts/utils/queryString.ts`) turns `window.location.search` into an object. The only key read is `test`: `inTestMode = parseQuery().test === "1"` (`srcts/utils/shinytest.ts`). In test mode:
`srcts/utils/shinytest.ts` reads the `test` query parameter with `URLSearchParams`: `inTestMode` is true when the URL has `?test=1`. In test mode:

- the header time and session show `(shinytest)` (`logEntry.ts`),
- `Node.calculationTimeStr` returns `(shinytest)`.
Expand Down
3 changes: 2 additions & 1 deletion srcts/cyto/cytoOn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@ let onMouseOver = function (cyto: CytoscapeType) {
};

let onClick = function (cyto: CytoscapeType) {
let cytoClickedBefore, cytoClickedTimeout;
let cytoClickedBefore: CytoEvent["target"] | null = null;
let cytoClickedTimeout: ReturnType<typeof setTimeout> | undefined;

return function (evt: CytoEvent) {
// remove focus on search
Expand Down
41 changes: 20 additions & 21 deletions srcts/graph/Graph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import { GhostEdge } from "./GhostEdge";
import { HoverStatus } from "./HoverStatus";
import { expectPrevStatus } from "./StatusArr";

import { flatMap } from "../utils/ArrayHelper";
import console from "../utils/console";

import type { CytoscapeType } from "../cyto/cytoFlowType";
Expand Down Expand Up @@ -106,7 +105,7 @@ class Graph {

let reactId = data.reactId;
let depOnReactId = data.depOnReactId;
let hasMatchingEdge = function (edges) {
let hasMatchingEdge = function (edges: Array<Edge | GhostEdge>) {
return _some(edges, function (edge) {
if (edge.reactId === reactId && edge.depOnReactId === depOnReactId) {
return true;
Expand Down Expand Up @@ -148,7 +147,7 @@ class Graph {
// highlight all the edges (and ghost edges) that have the same source and target
let reactId = data.reactId;
let depOnReactId = data.depOnReactId;
let selectMatchingEdges = function (edge) {
let selectMatchingEdges = function (edge: Edge | GhostEdge) {
if (edge.reactId === reactId && edge.depOnReactId === depOnReactId) {
onFn(edge);
}
Expand Down Expand Up @@ -239,15 +238,15 @@ class Graph {
let originalReactId = reactId;
let seenMap = new Set<ReactIdType>();
let reactIdArr = [reactId];
while (reactIdArr.length > 0) {
reactId = reactIdArr.pop();
if (!seenMap.has(reactId)) {
this.parentNodeIds(reactId).forEach(function (parentReactId) {
let curId: ReactIdType | undefined;
while ((curId = reactIdArr.pop()) !== undefined) {
if (!seenMap.has(curId)) {
this.parentNodeIds(curId).forEach(function (parentReactId) {
if (parentReactId) {
reactIdArr.push(parentReactId);
}
});
seenMap.add(reactId);
seenMap.add(curId);
}
}
seenMap.delete(originalReactId);
Expand All @@ -260,11 +259,11 @@ class Graph {
let originalReactId = reactId;
let seenMap = new Set<ReactIdType>();
let reactIdArr = [reactId];
while (reactIdArr.length > 0) {
reactId = reactIdArr.pop();
if (!seenMap.has(reactId)) {
reactIdArr = reactIdArr.concat(this.childrenNodeIds(reactId));
seenMap.add(reactId);
let curId: ReactIdType | undefined;
while ((curId = reactIdArr.pop()) !== undefined) {
if (!seenMap.has(curId)) {
reactIdArr = reactIdArr.concat(this.childrenNodeIds(curId));
seenMap.add(curId);
}
}
seenMap.delete(originalReactId);
Expand Down Expand Up @@ -294,23 +293,23 @@ class Graph {
familyTreeNodeIdsForDatas(datas: Array<SomeGraphData>): Array<ReactIdType> {
let self = this;
return _union(
flatMap(datas, function (data) {
datas.flatMap(function (data) {
return self.familyTreeNodeIds(data);
})
);
}
decendentNodeIdsForDatas(datas: Array<SomeGraphData>): Array<ReactIdType> {
let self = this;
return _union(
flatMap(datas, function (data: SomeGraphData) {
datas.flatMap(function (data) {
return self.decendentNodeIds(data);
})
);
}
ancestorNodeIdsForDatas(datas: Array<SomeGraphData>): Array<ReactIdType> {
let self = this;
return _union(
flatMap(datas, function (data) {
datas.flatMap(function (data) {
return self.ancestorNodeIds(data);
})
);
Expand Down Expand Up @@ -475,7 +474,8 @@ class Graph {
node = this.nodes.get(data.reactId);
switch (data.action) {
case LogStates.exit: {
let activeEnterNode = this.nodes.get(_last(this.activeNodeEnter));
lastNodeId = _last(this.activeNodeEnter);
let activeEnterNode = lastNodeId && this.nodes.get(lastNodeId);
if (activeEnterNode) {
activeEnterNode.enterStatus.reset();
}
Expand All @@ -491,9 +491,8 @@ class Graph {
}
case LogStates.invalidateEnd: {
// turn off the previously active node
let curActiveNode = this.nodes.get(
_last(this.activeInvalidateEnter)
);
lastNodeId = _last(this.activeInvalidateEnter);
let curActiveNode = lastNodeId && this.nodes.get(lastNodeId);
if (curActiveNode) {
curActiveNode.invalidateStatus.resetActive();
}
Expand Down Expand Up @@ -572,7 +571,7 @@ class Graph {

if (edge) {
node = this.nodes.get(edge.reactId);
if (node && node.statusLast().action === LogStates.isolateEnter) {
if (node && node.statusLast()?.action === LogStates.isolateEnter) {
edge.status = "isolate";
} else {
edge.status = "normal";
Expand Down
24 changes: 12 additions & 12 deletions srcts/graph/GraphAtStep.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,22 +47,22 @@ class GraphAtStep {
hoverData: SomeGraphData | null | undefined;
stickyDatas: Array<SomeGraphData>;

finalFilteredGraph: Graph;
finalFilteredGraph!: Graph;
finalCompleteGraph: Graph;
finalCyto: any;

cytoLayout: any;

steps: Array<number>;
stepsVisible: Array<number>;
filteredStepsVisible: Array<number>;
stepsAsyncStart: Array<number>;
stepsAsyncStop: Array<number>;
stepsIdle: Array<number>;
stepsOutputCalc: Array<number>;
stepsUserMark: Array<number>;
minStep: number;
maxStep: number;
steps!: Array<number>;
stepsVisible!: Array<number>;
filteredStepsVisible!: Array<number>;
stepsAsyncStart!: Array<number>;
stepsAsyncStop!: Array<number>;
stepsIdle!: Array<number>;
stepsOutputCalc!: Array<number>;
stepsUserMark!: Array<number>;
minStep!: number;
maxStep!: number;

constructor(log: LogType) {
this.originalLog = log;
Expand Down Expand Up @@ -557,7 +557,7 @@ class GraphAtStep {
let nodesLRB = cyNodes.diff(graphNodes);
// .removeStyle()

let onLayoutReady = [];
let onLayoutReady: Array<() => void> = [];
let someNodeHasNewLabel = false;

// enter visible nodes
Expand Down
6 changes: 3 additions & 3 deletions srcts/graph/Node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ class Node {
}
}

get calculationTimeStr(): string {
get calculationTimeStr(): string | null {
if (_isNil(this.calculationTime)) {
return null;
}
Expand Down Expand Up @@ -115,7 +115,7 @@ class Node {
this.statusArr.add(logEntry as StatusEntry);
return this.statusArr;
}
statusRemove(logEntry: LogEntryAnyType): StatusEntry {
statusRemove(logEntry: LogEntryAnyType): StatusEntry | undefined {
if (logEntry.action === LogStates.exit) {
let startEntryTime = this.calculationStartMap.get(logEntry.ctxId);
if (!_isNil(startEntryTime)) {
Expand All @@ -125,7 +125,7 @@ class Node {
}
return this.statusArr.remove();
}
statusLast(): StatusEntry {
statusLast(): StatusEntry | undefined {
return this.statusArr.last();
}
get inEnter(): boolean {
Expand Down
12 changes: 6 additions & 6 deletions srcts/graph/StatusArr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class StatusArr {
constructor(statusArr: StatusArr | Array<StatusEntry> = []) {
if (statusArr instanceof StatusArr) {
this.statusArr = _cloneDeep(statusArr.statusArr);
} else if (Array.isArray(statusArr)) {
} else {
this.statusArr = statusArr;
}
}
Expand All @@ -21,10 +21,10 @@ class StatusArr {
add(obj: StatusEntry) {
return this.statusArr.push(obj);
}
remove(): StatusEntry {
remove(): StatusEntry | undefined {
return this.statusArr.pop();
}
last(): StatusEntry {
last(): StatusEntry | undefined {
return _last(this.statusArr);
}
containsStatus(status: string) {
Expand All @@ -46,15 +46,15 @@ type StatusEntry = {

let expectPrevStatus = function (
curStatus: StatusEntry,
prevStatus: StatusEntry,
prevStatus: StatusEntry | undefined,
expectedAction: string
) {
function onError(msg: string) {
function onError(msg: string): never {
console.error("curStatus: ", curStatus);
console.error("prevStatus: ", prevStatus);
throw msg;
}
if (prevStatus.action !== expectedAction) {
if (prevStatus?.action !== expectedAction) {
onError(`prior node status does not have "${expectedAction}" status`);
}
if (prevStatus.ctxId !== curStatus.ctxId) {
Expand Down
2 changes: 1 addition & 1 deletion srcts/layout/logEntry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ let updateLogEntry = function (): void {
}
}

let stepDisplayValPadding = function (i) {
let stepDisplayValPadding = function (i: number) {
return `${i}`.padStart(`${logInfo.logLength}`.length, " ");
};

Expand Down
2 changes: 1 addition & 1 deletion srcts/layout/progressBar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ let updateFromProgressBar = function (e: JQuery.TriggeredEvent): void {

let timeline = $(e.currentTarget)[0] as HTMLElement;
// pixels from the left edge of the timeline
let pos = e.pageX - $(timeline).offset().left;
let pos = originalEvent.clientX - timeline.getBoundingClientRect().left;

let width = timeline.offsetWidth; // width in pixels

Expand Down
4 changes: 2 additions & 2 deletions srcts/updateGraph/searchString.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ let searchStringWith = function (str: string, exact: boolean = false) {
}
// escape the string
// https://stackoverflow.com/a/17606289
let escapeRegExp = function (str) {
let escapeRegExp = function (str: string) {
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string
};
let pattern = escapeRegExp(str);
Expand Down Expand Up @@ -63,7 +63,7 @@ let searchStringWithData = function (obj: Node | Edge | GhostEdge) {
let searchStringContainer = function (searchElement_: JQuery) {
searchElement = searchElement_;
searchElement.on("input", function (e) {
searchStringWith($(e.target).val().toString());
searchStringWith(`${$(e.target).val() ?? ""}`);
});
};

Expand Down
28 changes: 0 additions & 28 deletions srcts/utils/ArrayHelper.ts

This file was deleted.

14 changes: 0 additions & 14 deletions srcts/utils/queryString.ts

This file was deleted.

5 changes: 2 additions & 3 deletions srcts/utils/shinytest.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { parseQuery } from "./queryString";

let inTestMode = parseQuery().test === "1";
let inTestMode =
new URLSearchParams(window.location.search).get("test") === "1";

const shinytest = "(shinytest)";

Expand Down
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"moduleResolution": "bundler",
"lib": ["es2021", "dom"],
"types": ["jquery"],
"strict": false,
"strict": true,
"noEmit": true,
"isolatedModules": true,
"esModuleInterop": true
Expand Down
Loading