• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

okcontract / cells / 20256082112

16 Dec 2025 04:03AM UTC coverage: 88.23% (-4.7%) from 92.948%
20256082112

Pull #41

github

hbbio
github: update workflows
Pull Request #41: Vite 7

175 of 195 branches covered (89.74%)

Branch coverage included in aggregate %.

807 of 918 relevant lines covered (87.91%)

3307.18 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

55.06
/src/debug.ts
1
import type { Graph } from "@okcontract/graph";
2

3
import type { AnyCell, Cell } from "./cell";
4
import { isCellError } from "./errors";
5
import { simplifier } from "./printer";
6
import type { Sheet } from "./sheet";
7

8
/**
9
 * Debugger for a Sheet.
10
 * @description When debugging, your application should export the debugger to
11
 * window: `window["debug"] = new Debugger(sheet);`.
12
 */
13
export class Debugger {
14
  sheet: Sheet;
15
  cells: { [key: number]: Cell<unknown, boolean, boolean> };
16
  g: Graph<number>;
17

18
  constructor(sheet: Sheet) {
19
    this.sheet = sheet;
4✔
20
    // activate debugging for the sheet
21
    this.sheet._debug = true;
4✔
22
    // @ts-expect-error private
23
    this.cells = sheet._cells;
4✔
24
    // @ts-expect-error private
25
    this.g = sheet.g;
4✔
26
  }
27

28
  /**
29
   * help
30
   */
31
  get h() {
32
    console.log("h         -- this help");
×
33
    console.log("w(id...)  -- watch cells");
×
34
    console.log("aw(name)  -- auto-watch cells with matching name");
×
35
    console.log("uw(id...) -- unwatch cells");
×
36
    console.log("p(id)     -- print a cell and its deps");
×
37
    console.log('s("...")  -- search cell names');
×
38
    console.log("e         -- show all cell errors");
×
39
    console.log("u         -- show all undefined cells");
×
40
    console.log("dot       -- generate graphviz dot graph");
×
41
    console.log("sub       -- subscribe to a given cell");
×
42
    console.log("map       -- map a given cell");
×
43
    return undefined;
×
44
  }
45

46
  /**
47
   * watch cells
48
   */
49
  w(...cells: number[]) {
50
    this.sheet._debug = true;
×
51
    this.sheet._logList.push(...cells);
×
52
  }
53

54
  aw(pat: string) {
55
    this.sheet._debug = true;
×
56
    // @ts-expect-error private
57
    this.sheet._autoWatch.push(pat.toLowerCase());
×
58
  }
59

60
  /**
61
   * unwatch cells
62
   */
63
  uw(...cells: number[]) {
64
    this.sheet._logList = this.sheet._logList.filter((c) => !cells.includes(c));
×
65
  }
66

67
  /**
68
   * search: print all cells whose name matches substring.
69
   * @param substring
70
   */
71
  s(substring: string) {
72
    const res = [];
1✔
73
    const low = substring.toLowerCase();
1✔
74
    for (const k of Object.keys(this.cells)) {
1✔
75
      const v = this.cells[k];
4✔
76
      if (v.name.toLowerCase().includes(low)) {
4✔
77
        res.push({ cell: v.id, name: v.name, value: v.value });
1✔
78
      }
79
    }
80
    return res;
1✔
81
  }
82

83
  /**
84
   * print: a cell and all its dependencies.
85
   * @param cell number
86
   */
87
  p(cell: number, to?: number) {
88
    // List all cell names in range.
89
    if (to) {
2✔
90
      for (let i = cell; i <= to; i++)
1✔
91
        console.log(`${i}: ${this.cells?.[i]?.name}`);
2✔
92
      return;
1✔
93
    }
94
    if (!this.cells[cell]) {
1✔
95
      console.log("not found");
×
96
      return;
×
97
    }
98
    const pred = this.g.predecessors(cell);
1✔
99
    const succ = this.g.get(cell);
1✔
100
    for (const id of pred)
1✔
101
      console.log({
×
102
        "<==": id,
103
        name: this.cells[id].name,
104
        value: this.cells[id].value
105
      });
106
    console.log("=====");
1✔
107
    console.log({
1✔
108
      cell: cell,
109
      name: this.cells[cell].name,
110
      value: this.cells[cell].value
111
    });
112
    console.log("=====");
1✔
113
    for (const id of succ)
1✔
114
      console.log({
1✔
115
        "==>": id,
116
        name: this.cells[id].name,
117
        value: this.cells[id].value
118
      });
119
    return `[${pred.join(",")}] ==> {${cell}} ==> [${succ.join(",")}]`;
1✔
120
  }
121

122
  sub(cell: number, cb: (v: unknown) => void, delay = 30) {
123
    const cells = this.cells;
×
124
    return new Promise((resolve) => {
×
125
      function checkAndSubscribe() {
126
        if (cells[cell]) resolve(cells[cell].subscribe(cb));
×
127
        else setTimeout(checkAndSubscribe, delay);
×
128
      }
129
      checkAndSubscribe();
×
130
    });
131
  }
132

133
  map(cell: number, cb: (v: unknown) => void, delay = 30) {
134
    const cells = this.cells;
×
135
    return new Promise((resolve) => {
×
136
      function checkAndSubscribe() {
137
        if (cells[cell]) resolve(cells[cell].map(cb));
×
138
        else setTimeout(checkAndSubscribe, delay);
×
139
      }
140
      checkAndSubscribe();
×
141
    });
142
  }
143

144
  /**
145
   * errors retrieves all cells in error.
146
   * @param
147
   * @returns list
148
   */
149
  errors(first = false) {
150
    const res = [];
1✔
151
    for (const k of Object.keys(this.cells)) {
1✔
152
      const v = this.cells[k];
4✔
153
      if (v.value instanceof Error && (!first || !isCellError(v.value))) {
4✔
154
        res.push({ cell: v.id, name: v.name, error: v.value });
1✔
155
      }
156
    }
157
    return res;
1✔
158
  }
159

160
  /**
161
   * e: all errors.
162
   */
163
  get e() {
164
    return this.errors();
1✔
165
  }
166

167
  /**
168
   * ee: only first errors.
169
   */
170
  get ee() {
171
    return this.errors(true);
×
172
  }
173

174
  /**
175
   * u: print all undefined cells.
176
   */
177
  get u() {
178
    const ids: number[] = [];
×
179
    for (const [id, cell] of Object.entries(this.cells)) {
×
180
      if (cell.value === undefined) {
×
181
        ids.push(+id);
×
182
        console.log({
×
183
          id,
184
          name: cell.name || this.g.name(+id),
185
          undefined: true
186
        });
187
      }
188
    }
189
    return this.g.topologicalSort()?.filter((id) => ids.includes(id));
×
190
  }
191

192
  _cell_types() {
193
    const ty: {
194
      string: number[];
195
      number: number[];
196
      object: number[];
197
      undefined: number[];
198
      boolean: number[];
199
      bigint: number[];
200
      symbol: number[];
201
      function: number[];
202
      null: number[];
203
    } = {
5✔
204
      string: [],
205
      number: [],
206
      object: [],
207
      undefined: [],
208
      boolean: [],
209
      bigint: [],
210
      symbol: [],
211
      function: [],
212
      null: []
213
    };
214
    for (const [id, cell] of Object.entries(this.cells)) {
5✔
215
      const v = cell.value;
28✔
216
      ty[v === null ? "null" : typeof v].push(+id);
28✔
217
    }
218
    return ty;
5✔
219
  }
220

221
  dot(title?: string) {
222
    return this.g.toDot(
5✔
223
      this._cell_types(),
224
      {
225
        ...(title && { title }),
226
        string: "style=filled,fillcolor=aquamarine",
227
        number: "style=filled,fillcolor=gold",
228
        object: "style=filled,fillcolor=hotpink",
229
        undefined: "style=filled,fillcolor=gray",
230
        boolean: "style=filled,fillcolor=deepskyblue",
231
        bigint: "style=filled,fillcolor=goldenrod1",
232
        symbol: "style=filled,fillcolor=green",
233
        function: "style=filled,fillcolor=orangered",
234
        null: "style=filled,fillcolor=red"
235
      },
236
      // @ts-expect-error private
237
      this.sheet._pointers
238
    );
239
  }
240
}
241

242
export const getClassNameOrType = (value: unknown) =>
3✔
243
  value !== null && typeof value === "object" && value.constructor
12✔
244
    ? value.constructor.name
245
    : typeof value;
246

247
export const logger = <T>(cell: AnyCell<T>, fn?: (v: T) => unknown) =>
3✔
248
  cell.subscribe((v) =>
4✔
249
    console.log(
4✔
250
      cell.name,
251
      fn !== undefined && !(v instanceof Error)
252
        ? { [fn.name]: simplifier(fn(v)) }
253
        : { [getClassNameOrType(v)]: simplifier(v) }
254
    )
255
  );
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc