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

source-academy / js-slang / 19080105112

04 Nov 2025 07:13PM UTC coverage: 76.655% (-1.5%) from 78.192%
19080105112

push

github

web-flow
Migrate to Vitest (#1815)

* Upgrade TS to 5.8

* Remove deprecated tsconfig option

* Remove duplicate properties

* Upgrade TS to v5.9

* Add types for mathjs

* Fix some type errors

* Update tsconfig

* Fix more type errors

* Fix remaining errors

* Update GitHub workflows

* Fix type error

* Update scm-slang to latest

* Add newline to EOF

* Fix cse-machine types and utils to use fewer type assertions

* Migrate to vitest tests

* Migrate tests to vitest

* Relocate base error files and types

* Get modules tests working

* run format

* Sort tsconfig compiler options

* Update eslint packages to match typescript version

* Small linting change

* Use function names instead of strings for describe blocks

* Include scripts in linting

* Move tests and replace describe titles with functions

* Add type modifiers and reformat tests

* Simplify isEnvDependent code

* Instruct tsc to ignore py-slang's tests during build

* Move walkers to be under utils/ast

* Update tests failing due to timeout

* Update cse-machine typings

* Incorporate import assertions into docs importer

* Add context property to error result

* Update test timeout and add no-restricted-import rule for commander imports

* Update snapshots

* Run format

* Update snapshots again....

* Run format

* Change to use the test.each

* Disable the svmc snapshot test cause it doesn't work

* Add a new test for properties when loading modules

* Run format

* Convert stdlib parser to use nodetypetonode helper type

* A working version of the statementSeqTransform

* More compact version of seq transform

* Remove unnecessary type assertions

* Clean up some documentation bits and pieces

* Use type imports for tracer

* Swap the list library to use generics

* Fix some error messages and tests

* Fix list tests

* Run format

* Update stream library and tests

* Running format

* Add some documentation for the scripts

* Remove unnecessary packages

* Remove even more unnecessary ty... (continued)

3501 of 4761 branches covered (73.53%)

Branch coverage included in aggregate %.

429 of 636 new or added lines in 54 files covered. (67.45%)

34 existing lines in 12 files now uncovered.

7085 of 9049 relevant lines covered (78.3%)

193248.37 hits per line

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

24.68
/src/utils/statementSeqTransform.ts
1
import type es from 'estree'
2
import type { Node, NodeTypeToNode } from '../types'
3
import * as ast from './ast/astCreator'
4
import { hasNoDeclarations } from './ast/helpers'
5

6
function hasImportDeclarations(node: es.Program): boolean {
7
  for (const statement of node.body) {
852✔
8
    if (statement.type === 'ImportDeclaration') {
19,967✔
9
      return true
5✔
10
    }
11
  }
12
  return false
847✔
13
}
14

15
/**
16
 * Utility type for getting all the keys of a ControlItem that have values
17
 * that are assignable to Nodes
18
 */
19
type GetNodeKeys<T extends Node> = {
20
  [K in keyof T as T[K] extends Node | null | undefined ? K : never]: K
21
}
22
/**
23
 * Extracts all the keys of a ControlItem that have values that are assignable to Nodes
24
 * as a union
25
 */
26
type KeysOfNodeProperties<T extends Node> = GetNodeKeys<T>[keyof GetNodeKeys<T>]
27

28
type NodeTransformer<T extends Node> =
29
  | KeysOfNodeProperties<T>
30
  | KeysOfNodeProperties<T>[]
31
  | ((node: T) => Node)
32

33
type NodeTransformers = {
34
  [K in Node['type']]?: NodeTransformer<NodeTypeToNode<K>>
35
}
36

37
const transformers: NodeTransformers = {
74✔
38
  ArrayExpression: node => {
NEW
39
    node.elements = node.elements.map(x => (x ? transform(x) : null))
×
NEW
40
    return node
×
41
  },
42
  ArrowFunctionExpression: node => {
NEW
43
    node.params = node.params.map(transform)
×
NEW
44
    node.body = transform(node.body)
×
NEW
45
    return node
×
46
  },
47
  AssignmentExpression: ['left', 'right'],
48
  BinaryExpression: ['left', 'right'],
49
  BlockStatement: node => {
NEW
50
    node.body = node.body.map(transform)
×
NEW
51
    if (hasNoDeclarations(node.body)) {
×
NEW
52
      return ast.statementSequence(node.body, node.loc)
×
53
    } else {
NEW
54
      return node
×
55
    }
56
  },
57
  BreakStatement: 'label',
58
  CallExpression: node => {
NEW
59
    node.callee = transform(node.callee)
×
NEW
60
    node.arguments = node.arguments.map(transform)
×
NEW
61
    return node
×
62
  },
63
  ClassDeclaration: ['body', 'id', 'superClass'],
64
  ConditionalExpression: ['alternate', 'consequent', 'test'],
65
  ContinueStatement: 'label',
66
  ExportDefaultDeclaration: 'declaration',
67
  ExportNamedDeclaration: node => {
NEW
68
    if (node.declaration) {
×
69
      node.declaration = transform(node.declaration)
×
70
    }
NEW
71
    node.specifiers = node.specifiers.map(x => transform(x))
×
NEW
72
    if (node.source) {
×
NEW
73
      transform(node.source)
×
74
    }
NEW
75
    return node
×
76
  },
77
  ExportSpecifier: ['exported', 'local'],
78
  ExpressionStatement: 'expression',
79
  ForStatement: ['body', 'init', 'test', 'update'],
80
  FunctionDeclaration: node => {
NEW
81
    node.params = node.params.map(transform)
×
NEW
82
    node.body = transform(node.body)
×
NEW
83
    if (node.id) {
×
NEW
84
      node.id = transform(node.id)
×
85
    }
NEW
86
    return node
×
87
  },
88
  FunctionExpression: node => {
NEW
89
    if (node.id) {
×
NEW
90
      node.id = transform(node.id)
×
91
    }
NEW
92
    node.params = node.params.map(transform)
×
NEW
93
    node.body = transform(node.body)
×
NEW
94
    return node
×
95
  },
96
  IfStatement: ['alternate', 'consequent', 'test'],
97
  ImportDeclaration: node => {
NEW
98
    node.specifiers = node.specifiers.map(transform)
×
NEW
99
    node.source = transform(node.source)
×
NEW
100
    return node
×
101
  },
102
  ImportDefaultSpecifier: 'local',
103
  ImportSpecifier: ['imported', 'local'],
104
  LogicalExpression: ['left', 'right'],
105
  MemberExpression: ['object', 'property'],
106
  MethodDefinition: ['key', 'value'],
107
  NewExpression: node => {
NEW
108
    node.arguments = node.arguments.map(transform)
×
NEW
109
    return node
×
110
  },
111
  ObjectExpression: node => {
NEW
112
    node.properties = node.properties.map(transform)
×
NEW
113
    return node
×
114
  },
115
  Program: node => {
116
    if (!hasNoDeclarations(node.body) && !hasImportDeclarations(node)) {
1,035✔
117
      return ast.statementSequence(node.body as es.Statement[], node.loc)
847✔
118
    } else {
119
      return node
188✔
120
    }
121
  },
122
  Property: ['key', 'value'],
123
  RestElement: 'argument',
124
  ReturnStatement: 'argument',
125
  SpreadElement: 'argument',
126
  StatementSequence: node => {
NEW
127
    node.body = node.body.map(transform)
×
NEW
128
    return node
×
129
  },
130
  ThrowStatement: 'argument',
131
  TryStatement: ['block', 'finalizer', 'handler'],
132
  UnaryExpression: 'argument',
133
  VariableDeclarator: ['id', 'init'],
134
  VariableDeclaration: node => {
NEW
135
    node.declarations = node.declarations.map(transform)
×
NEW
136
    return node
×
137
  },
138
  WhileStatement: ['body', 'test']
139
}
140

141
export function transform<NodeType extends Node>(node: NodeType): NodeType {
142
  const transformer = transformers[node.type]
1,035✔
143

144
  switch (typeof transformer) {
1,035!
145
    case 'undefined':
UNCOV
146
      return node
×
147
    case 'function':
148
      // @ts-expect-error Node type gets narrowed to never
149
      return transformer(node) as NodeType
1,035✔
150
  }
151

NEW
152
  const properties = typeof transformer === 'string' ? [transformer] : transformer
×
153
  for (const prop of properties) {
1,035✔
154
    // @ts-expect-error Weird typescript shennenigans going on here don't mind this
NEW
155
    node[prop!] = transform(node[prop])
×
156
  }
157

NEW
158
  return node
×
159
}
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