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

source-academy / js-slang / 24868044425

24 Apr 2026 01:47AM UTC coverage: 78.522% (+0.1%) from 78.391%
24868044425

push

github

web-flow
Error Handling and Stringify Changes (#1893)

* Modify stringify to prioritize toReplString

* Make the extract declarations helper actually work

* Add ability to change loader for source modules

* Add a new option for controlling how Source modules are loaded

* Improve typing for CSE machine

* Add ability to check if modules are loaded with the wrong Source chapter

* Refactor errors to extend from Error class

* Refactor modules errors

* Refactor parser errors

* Refactor cse machine errors

* Mostly fix error handling in the tracer

* Tidy up generator and explainer implementations for tracer

* Remove unnecessary imports and type guards

* Adjust rttc checks to be type guards instead of returning errors

* Adjust miscellanous error changes

* Add eslint rule for useless constructor

* Fix incorrect ordering for checking exceptionerrors

* Minor changes

* Run format

* Run linting

* Override the message property, but also enable noImplicitOverride to prevent accidental overriding

* Add some documentation to some errors

* Add errors to possible imports for modules

* Update getIds helper

* Minor fix to test case

* Run format

* Allow modules to try and load the context of other modules without crashing

* Fix incorrect stdlib name

* Add some more functions to the stdlib list library

* Change to use GeneralRuntimeError for list

* Revert "Change to use GeneralRuntimeError for list"

This reverts commit 642bd99e6.

* Update src/errors/errors.ts

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>

* Add ability to change manifest and docs importers

* Change how external builtins are defined

* Fix typings and list lib overloads

* Miscellanous changes

* Add the Source equality function to stdlib/misc

* Merge from main branch for tracer

* Add handling for the new importers

* Change errors and made redex a local variable

* Improve tracer typing

* Relocate... (continued)

3125 of 4193 branches covered (74.53%)

Branch coverage included in aggregate %.

899 of 1089 new or added lines in 96 files covered. (82.55%)

21 existing lines in 12 files now uncovered.

7031 of 8741 relevant lines covered (80.44%)

185057.72 hits per line

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

69.57
/src/stepper/nodes/Statement/VariableDeclaration.ts
1
import type { Comment, SourceLocation, VariableDeclaration, VariableDeclarator } from 'estree';
2
import { type StepperExpression, type StepperPattern, undefinedNode } from '..';
3
import { convert } from '../../generator';
4
import { StepperBaseNode } from '../../interface';
5
import type { RedexInfo } from '../..';
6

7
export class StepperVariableDeclarator
8
  extends StepperBaseNode<VariableDeclarator>
9
  implements VariableDeclarator
10
{
11
  constructor(
12
    public readonly id: StepperPattern,
1,634✔
13
    public readonly init: StepperExpression | null | undefined,
1,634✔
14
    leadingComments?: Comment[] | undefined,
15
    trailingComments?: Comment[] | undefined,
16
    loc?: SourceLocation | null | undefined,
17
    range?: [number, number] | undefined,
18
  ) {
19
    super('VariableDeclarator', leadingComments, trailingComments, loc, range);
1,634✔
20
  }
21

22
  static create(node: VariableDeclarator) {
23
    return new StepperVariableDeclarator(
350✔
24
      convert(node.id),
25
      node.init ? convert(node.init) : node.init,
350!
26
      node.leadingComments,
27
      node.trailingComments,
28
      node.loc,
29
      node.range,
30
    );
31
  }
32

33
  public override isContractible(redex: RedexInfo): boolean {
NEW
34
    return this.init ? this.init.isContractible(redex) : false;
×
35
  }
36

37
  public override isOneStepPossible(redex: RedexInfo): boolean {
38
    return this.init ? this.init.isOneStepPossible(redex) : false;
417!
39
  }
40

41
  public override contract(redex: RedexInfo): StepperVariableDeclarator {
42
    return new StepperVariableDeclarator(
×
43
      this.id,
44
      this.init!.oneStep(redex),
45
      this.leadingComments,
46
      this.trailingComments,
47
      this.loc,
48
      this.range,
49
    );
50
  }
51

52
  public override oneStep(redex: RedexInfo): StepperVariableDeclarator {
53
    return new StepperVariableDeclarator(
90✔
54
      this.id,
55
      this.init!.oneStep(redex),
56
      this.leadingComments,
57
      this.trailingComments,
58
      this.loc,
59
      this.range,
60
    );
61
  }
62

63
  public override substitute(
64
    id: StepperPattern,
65
    value: StepperExpression,
66
    redex: RedexInfo,
67
  ): StepperBaseNode {
68
    return new StepperVariableDeclarator(
1,149✔
69
      this.id,
70
      this.init!.substitute(id, value, redex),
71
      this.leadingComments,
72
      this.trailingComments,
73
      this.loc,
74
      this.range,
75
    );
76
  }
77

78
  public override freeNames(): string[] {
79
    return this.init!.freeNames();
90✔
80
  }
81

82
  public override allNames(): string[] {
83
    return this.init!.allNames();
527✔
84
  }
85

86
  public override rename(before: string, after: string): StepperVariableDeclarator {
87
    return new StepperVariableDeclarator(
4✔
88
      this.id.rename(before, after),
89
      this.init!.rename(before, after),
90
      this.leadingComments,
91
      this.trailingComments,
92
      this.loc,
93
      this.range,
94
    );
95
  }
96
}
97

98
// After all variable declarators have been contracted,
99
// StepperVariableDeclaration::contract triggers substitution
100
export class StepperVariableDeclaration
101
  extends StepperBaseNode<VariableDeclaration>
102
  implements VariableDeclaration
103
{
104
  constructor(
105
    public readonly declarations: StepperVariableDeclarator[],
1,593✔
106
    public readonly kind: VariableDeclaration['kind'],
1,593✔
107
    leadingComments?: Comment[] | undefined,
108
    trailingComments?: Comment[] | undefined,
109
    loc?: SourceLocation | null | undefined,
110
    range?: [number, number] | undefined,
111
  ) {
112
    super('VariableDeclaration', leadingComments, trailingComments, loc, range);
1,593✔
113
  }
114

115
  static create(node: VariableDeclaration) {
116
    return new StepperVariableDeclaration(
350✔
117
      node.declarations.map(StepperVariableDeclarator.create),
118
      node.kind,
119
      node.leadingComments,
120
      node.trailingComments,
121
      node.loc,
122
      node.range,
123
    );
124
  }
125

126
  public override isContractible(): boolean {
127
    return false;
×
128
  }
129

130
  public override isOneStepPossible(redex: RedexInfo): boolean {
131
    return this.declarations
327✔
132
      .map(x => x.isOneStepPossible(redex))
327✔
133
      .reduce((acc, next) => acc || next, false);
327✔
134
  }
135

136
  public override contract(redex: RedexInfo): typeof undefinedNode {
137
    redex.preRedex = [this];
×
138
    redex.postRedex = [];
×
139
    return undefinedNode;
×
140
  }
141

142
  contractEmpty(redex: RedexInfo) {
143
    redex.preRedex = [this];
×
144
    redex.postRedex = [];
×
145
  }
146

147
  public override oneStep(redex: RedexInfo): StepperVariableDeclaration | typeof undefinedNode {
148
    // Find the one that is not contractible.
149
    for (let i = 0; i < this.declarations.length; i++) {
90✔
150
      const ast = this.declarations[i];
90✔
151
      if (ast.isOneStepPossible(redex)) {
90!
152
        return new StepperVariableDeclaration(
90✔
153
          [
154
            this.declarations.slice(0, i),
155
            ast.oneStep(redex),
156
            this.declarations.slice(i + 1),
157
          ].flat(),
158
          this.kind,
159
          this.leadingComments,
160
          this.trailingComments,
161
          this.loc,
162
          this.range,
163
        );
164
      }
165
    }
166

167
    return this;
×
168
  }
169

170
  public override substitute(
171
    id: StepperPattern,
172
    value: StepperExpression,
173
    redex: RedexInfo,
174
  ): StepperBaseNode {
175
    return new StepperVariableDeclaration(
1,149✔
176
      this.declarations.map(
177
        declaration => declaration.substitute(id, value, redex) as StepperVariableDeclarator,
1,149✔
178
      ),
179
      this.kind,
180
      this.leadingComments,
181
      this.trailingComments,
182
      this.loc,
183
      this.range,
184
    );
185
  }
186

187
  public override freeNames(): string[] {
188
    return Array.from(new Set(this.declarations.flatMap(ast => ast.freeNames())));
90✔
189
  }
190

191
  public override allNames(): string[] {
192
    return Array.from(new Set(this.declarations.flatMap(ast => ast.allNames())));
527✔
193
  }
194

195
  rename(before: string, after: string): StepperVariableDeclaration {
196
    return new StepperVariableDeclaration(
4✔
197
      this.declarations.map(declaration => declaration.rename(before, after)),
4✔
198
      this.kind,
199
      this.leadingComments,
200
      this.trailingComments,
201
      this.loc,
202
      this.range,
203
    );
204
  }
205
}
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