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

okcontract / cells / 8519452181

02 Apr 2024 08:05AM UTC coverage: 90.416% (+3.6%) from 86.862%
8519452181

Pull #27

github

hbbio
sheet: Computations<V> reverts to array
Pull Request #27: Rewrite debugging, collect removes subgraph by default

390 of 440 branches covered (88.64%)

Branch coverage included in aggregate %.

234 of 299 new or added lines in 5 files covered. (78.26%)

3 existing lines in 2 files now uncovered.

3025 of 3337 relevant lines covered (90.65%)

1073.55 hits per line

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

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

1✔
3
import type { Cell } from "./cell";
1✔
4
import type { Sheet } from "./sheet";
1✔
5

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

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

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

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

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

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

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

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

1✔
114
  sub(cell: number, cb: (v: unknown) => void, delay = 30) {
1✔
NEW
115
    const cells = this.cells;
×
NEW
116
    return new Promise((resolve) => {
×
NEW
117
      function checkAndSubscribe() {
×
NEW
118
        if (cells[cell]) resolve(cells[cell].subscribe(cb));
×
NEW
119
        else setTimeout(checkAndSubscribe, delay);
×
NEW
120
      }
×
NEW
121
      checkAndSubscribe();
×
NEW
122
    });
×
NEW
123
  }
×
124

1✔
125
  map(cell: number, cb: (v: unknown) => void, delay = 30) {
1✔
NEW
126
    const cells = this.cells;
×
NEW
127
    return new Promise((resolve) => {
×
NEW
128
      function checkAndSubscribe() {
×
NEW
129
        if (cells[cell]) resolve(cells[cell].map(cb));
×
NEW
130
        else setTimeout(checkAndSubscribe, delay);
×
NEW
131
      }
×
NEW
132
      checkAndSubscribe();
×
NEW
133
    });
×
NEW
134
  }
×
135

1✔
136
  /**
1✔
137
   * e: print all cells containing errors.
1✔
138
   * @returns
1✔
139
   */
1✔
140
  get e() {
1✔
141
    const res = [];
1✔
142
    for (const k of Object.keys(this.cells)) {
1✔
143
      const v = this.cells[k];
4✔
144
      if (v.value instanceof Error) {
4✔
145
        res.push({ cell: v.id, name: v.name, error: v.value });
1✔
146
      }
1✔
147
    }
4✔
148
    return res;
1✔
149
  }
1✔
150

1✔
151
  /**
1✔
152
   * u: print all undefined cells.
1✔
153
   */
1✔
154
  get u() {
1✔
155
    const ids: number[] = [];
×
156
    for (const [id, cell] of Object.entries(this.cells)) {
×
157
      if (cell.value === undefined) {
×
158
        ids.push(+id);
×
159
        console.log({ id, name: this.g.name(+id), cell, undefined: true });
×
160
      }
×
161
    }
×
162
    return this.g.topologicalSort()?.filter((id) => ids.includes(id));
×
163
  }
×
164

1✔
165
  _cell_types() {
1✔
166
    const ty: {
1✔
167
      string: number[];
1✔
168
      number: number[];
1✔
169
      object: number[];
1✔
170
      undefined: number[];
1✔
171
      boolean: number[];
1✔
172
      bigint: number[];
1✔
173
      symbol: number[];
1✔
174
      function: number[];
1✔
175
      null: number[];
1✔
176
    } = {
1✔
177
      string: [],
1✔
178
      number: [],
1✔
179
      object: [],
1✔
180
      undefined: [],
1✔
181
      boolean: [],
1✔
182
      bigint: [],
1✔
183
      symbol: [],
1✔
184
      function: [],
1✔
185
      null: []
1✔
186
    };
1✔
187
    for (const [id, cell] of Object.entries(this.cells)) {
1✔
188
      const v = cell.value;
4✔
189
      ty[v === null ? "null" : typeof v].push(+id);
4!
190
    }
4✔
191
    return ty;
1✔
192
  }
1✔
193

1✔
194
  dot(title?: string) {
1✔
195
    return this.g.toDot(
1✔
196
      this._cell_types(),
1✔
197
      {
1✔
198
        ...(title && { title }),
1!
199
        string: "style=filled,fillcolor=aquamarine",
1✔
200
        number: "style=filled,fillcolor=gold",
1✔
201
        object: "style=filled,fillcolor=hotpink",
1✔
202
        undefined: "style=filled,fillcolor=gray",
1✔
203
        boolean: "style=filled,fillcolor=deepskyblue",
1✔
204
        bigint: "style=filled,fillcolor=goldenrod1",
1✔
205
        symbol: "style=filled,fillcolor=green",
1✔
206
        function: "style=filled,fillcolor=orangered",
1✔
207
        null: "style=filled,fillcolor=red"
1✔
208
      },
1✔
209
      // @ts-expect-error private
1✔
210
      this.sheet._pointers
1✔
211
    );
1✔
212
  }
1✔
213
}
1✔
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