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

Siubaak / sval / 14771539826

01 May 2025 07:10AM UTC coverage: 73.748% (+8.3%) from 65.487%
14771539826

push

github

Siubaak
[update] rollup -> vite

753 of 922 branches covered (81.67%)

Branch coverage included in aggregate %.

60 of 60 new or added lines in 12 files covered. (100.0%)

358 existing lines in 15 files now uncovered.

2545 of 3550 relevant lines covered (71.69%)

932.53 hits per line

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

61.37
/src/evaluate/expression.ts
1
import { define, freeze, getGetter, getSetter, createSymbol, assign, getDptor, callSuper, WINDOW } from '../share/util.ts'
1✔
2
import { SUPER, NOCTOR, AWAIT, CLSCTOR, NEWTARGET, SUPERCALL, PRIVATE, IMPORT } from '../share/const.ts'
1✔
3
import { pattern, createFunc, createClass } from './helper.ts'
1✔
4
import { Variable, Prop } from '../scope/variable.ts'
1✔
5
import { Identifier } from './identifier.ts'
1✔
6
import { Literal } from './literal.ts'
1✔
7
import Scope from '../scope/index.ts'
1✔
8
import evaluate from './index.ts'
1✔
9
import * as acorn from 'acorn'
10

11
export function* ThisExpression(node: acorn.ThisExpression, scope: Scope) {
1✔
12
  const superCall = scope.find(SUPERCALL)
4✔
13
  if (superCall && superCall.get() !== true) {
4!
14
    throw new ReferenceError('Must call super constructor in derived class '
×
UNCOV
15
      + 'before accessing \'this\' or returning from derived constructor')
×
16
  } else {
4✔
17
    return scope.find('this').get()
4✔
18
  }
4✔
19
}
4✔
20

21
export function* ArrayExpression(node: acorn.ArrayExpression, scope: Scope) {
1✔
22
  let results: any[] = []
32✔
23
  for (let i = 0; i < node.elements.length; i++) {
32✔
24
    const item = node.elements[i]
76✔
25
    if (item.type === 'SpreadElement') {
76!
26
      results = results.concat(yield* SpreadElement(item, scope))
×
27
    } else {
76✔
28
      results.push(yield* evaluate(item, scope))
76✔
29
    }
76✔
30
  }
76✔
31
  return results
32✔
32
}
32✔
33

34
export function* ObjectExpression(node: acorn.ObjectExpression, scope: Scope) {
1✔
35
  const object: { [key: string]: any } = {}
12✔
36
  for (let i = 0; i < node.properties.length; i++) {
12✔
37
    const property = node.properties[i]
17✔
38
    if (property.type === 'SpreadElement') {
17!
39
      assign(object, yield* SpreadElement(property, scope, { spreadProps: true }))
×
40
    } else {
17✔
41
      let key: string
17✔
42
      const propKey = property.key
17✔
43
      if (property.computed) {
17!
44
        key = yield* evaluate(propKey, scope)
×
45
      } else {
17✔
46
        if (propKey.type === 'Identifier') {
17✔
47
          key = propKey.name
14✔
48
        } else {
14✔
49
          key = '' + (yield* Literal(propKey as acorn.Literal, scope))
3✔
50
        }
3✔
51
      }
17✔
52
  
53
      const value = yield* evaluate(property.value, scope)
17✔
54
  
55
      const propKind = property.kind
17✔
56
      if (propKind === 'init') {
17✔
57
        object[key] = value
15✔
58
      } else if (propKind === 'get') {
17✔
59
        const oriDptor = getDptor(object, key)
1✔
60
        define(object, key, {
1✔
61
          get: value,
1✔
62
          set: oriDptor && oriDptor.set,
1!
63
          enumerable: true,
1✔
64
          configurable: true
1✔
65
        })
1✔
66
      } else { // propKind === 'set'
1✔
67
        const oriDptor = getDptor(object, key)
1✔
68
        define(object, key, {
1✔
69
          get: oriDptor && oriDptor.get,
1✔
70
          set: value,
1✔
71
          enumerable: true,
1✔
72
          configurable: true
1✔
73
        })
1✔
74
      }
1✔
75
    }
17✔
76
  }
17✔
77
  return object
12✔
78
}
12✔
79

80
export function* FunctionExpression(node: acorn.FunctionExpression, scope: Scope) {
1✔
81
  if (node.id && node.id.name) {
13!
82
    // it's for accessing function expression by its name inside
83
    // e.g. const a = function b() { console.log(b) }
84
    const tmpScope = new Scope(scope)
×
85
    const func = createFunc(node, tmpScope)
×
86
    tmpScope.const(node.id.name, func)
×
87
    return func
×
88
  } else {
13✔
89
    return createFunc(node, scope)
13✔
90
  }
13✔
91
}
13✔
92

93
export function* UnaryExpression(node: acorn.UnaryExpression, scope: Scope) {
1✔
94
  const arg = node.argument
8✔
95
  switch (node.operator) {
8✔
96
    case '+': return +(yield* evaluate(arg, scope))
8✔
97
    case '-': return -(yield* evaluate(arg, scope))
8✔
98
    case '!': return !(yield* evaluate(arg, scope))
8✔
99
    case '~': return ~(yield* evaluate(arg, scope))
8✔
100
    case 'void': return void (yield* evaluate(arg, scope))
8✔
101
    case 'typeof':
8✔
102
      if (arg.type === 'Identifier') {
2✔
103
        return typeof (yield* Identifier(arg, scope, { throwErr: false }))
1✔
104
      } else {
1✔
105
        return typeof (yield* evaluate(arg, scope))
1✔
106
      }
1✔
107
    case 'delete':
8✔
108
      if (arg.type === 'MemberExpression') {
1✔
109
        const variable: Prop = yield* MemberExpression(arg, scope, { getVar: true })
1✔
110
        return variable.del()
1✔
111
      } else if (arg.type === 'Identifier') {
1!
112
        throw new SyntaxError('Delete of an unqualified identifier in strict mode')
×
UNCOV
113
      } else {
×
114
        yield* evaluate(arg, scope)
×
115
        return true
×
UNCOV
116
      }
×
117
    /* istanbul ignore next */
118
    default: throw new SyntaxError(`Unexpected token ${node.operator}`)
8!
119
  }
8✔
120
}
8✔
121

122
export function* UpdateExpression(node: acorn.UpdateExpression, scope: Scope) {
1✔
123
  const arg = node.argument
4✔
124
  
125
  let variable: Variable
4✔
126
  if (arg.type === 'Identifier') {
4✔
127
    variable = yield* Identifier(arg, scope, { getVar: true })
4✔
128
  } else if (arg.type === 'MemberExpression') {
4!
129
    variable = yield* MemberExpression(arg, scope, { getVar: true })
×
UNCOV
130
  } else {
×
131
    /* istanbul ignore next */
UNCOV
132
    throw new SyntaxError('Unexpected token')
×
UNCOV
133
  }
×
134

135
  const value = variable.get()
4✔
136
  if (node.operator === '++') {
4✔
137
    variable.set(value + 1)
4✔
138
    return node.prefix ? variable.get() : value
4!
139
  } else if (node.operator === '--') {
4!
140
    variable.set(value - 1)
×
141
    return node.prefix ? variable.get() : value
×
UNCOV
142
  } else {
×
143
    /* istanbul ignore next */
UNCOV
144
    throw new SyntaxError(`Unexpected token ${node.operator}`)
×
UNCOV
145
  }
×
146
}
4✔
147

148
export function* BinaryExpression(node: acorn.BinaryExpression, scope: Scope) {
1✔
149
  let left: any
27✔
150
  let right: any
27✔
151

152
  if (node.left.type === 'PrivateIdentifier') {
27!
153
    left = node.left.name
×
154
    right = yield* evaluate(node.right, scope)
×
155
    right = right[PRIVATE] || {} // compatible with checking by "#private in object"
×
156
  } else {
27✔
157
    left = yield* evaluate(node.left, scope)
27✔
158
    right = yield* evaluate(node.right, scope)
27✔
159
  }
27✔
160

161
  switch (node.operator) {
27✔
162
    case '==': return left == right
27✔
163
    case '!=': return left != right
27✔
164
    case '===': return left === right
27✔
165
    case '!==': return left !== right
27✔
166
    case '<': return left < right
27✔
167
    case '<=': return left <= right
27✔
168
    case '>': return left > right
27✔
169
    case '>=': return left >= right
27✔
170
    case '<<': return left << right
27✔
171
    case '>>': return left >> right
27✔
172
    case '>>>': return left >>> right
27✔
173
    case '+': return left + right
27✔
174
    case '-': return left - right
27✔
175
    case '*': return left * right
27✔
176
    case '**': return left ** right
27✔
177
    case '/': return left / right
27✔
178
    case '%': return left % right
27✔
179
    case '|': return left | right
27✔
180
    case '^': return left ^ right
27✔
181
    case '&': return left & right
27✔
182
    case 'in': return left in right
27✔
183
    case 'instanceof': return left instanceof right
27✔
184
    /* istanbul ignore next */
185
    default: throw new SyntaxError(`Unexpected token ${node.operator}`)
27!
186
  }
27✔
187
}
27✔
188

189
export function* AssignmentExpression(node: acorn.AssignmentExpression, scope: Scope) {
1✔
190
  const left = node.left
79✔
191
  let variable: Variable
79✔
192
  if (left.type === 'Identifier') {
79!
193
    variable = yield* Identifier(left, scope, { getVar: true, throwErr: false })
×
194
    if (!variable) {
×
195
      const win = scope.global().find('window').get()
×
196
      variable = new Prop(win, left.name)
×
UNCOV
197
    }
×
198
  } else if (left.type === 'MemberExpression') {
79✔
199
    variable = yield* MemberExpression(left, scope, { getVar: true })
79✔
200
  } else {
79!
201
    const value = yield* evaluate(node.right, scope)
×
202
    return yield* pattern(left, scope, { feed: value })
×
UNCOV
203
  }
×
204

205
  const value = yield* evaluate(node.right, scope)
79✔
206
  switch (node.operator) {
78✔
207
    case '=': variable.set(value); return variable.get()
78✔
208
    case '+=': variable.set(variable.get() + value); return variable.get()
79✔
209
    case '-=': variable.set(variable.get() - value); return variable.get()
79✔
210
    case '*=': variable.set(variable.get() * value); return variable.get()
79✔
211
    case '/=': variable.set(variable.get() / value); return variable.get()
79✔
212
    case '%=': variable.set(variable.get() % value); return variable.get()
79✔
213
    case '**=': variable.set(variable.get() ** value); return variable.get()
79✔
214
    case '<<=': variable.set(variable.get() << value); return variable.get()
79✔
215
    case '>>=': variable.set(variable.get() >> value); return variable.get()
79✔
216
    case '>>>=': variable.set(variable.get() >>> value); return variable.get()
79✔
217
    case '|=': variable.set(variable.get() | value); return variable.get()
79✔
218
    case '^=': variable.set(variable.get() ^ value); return variable.get()
79✔
219
    case '&=': variable.set(variable.get() & value); return variable.get()
79✔
220
    case '??=': variable.set(variable.get() ?? value); return variable.get()
79✔
221
    case '&&=': variable.set(variable.get() && value); return variable.get()
79✔
222
    case '||=': variable.set(variable.get() || value); return variable.get()
79✔
223
    /* istanbul ignore next */
224
    default: throw new SyntaxError(`Unexpected token ${node.operator}`)
79!
225
  }
79✔
226
}
79✔
227

228
export function* LogicalExpression(node: acorn.LogicalExpression, scope: Scope) {
1✔
229
  switch (node.operator) {
×
UNCOV
230
    case '||':
×
231
      return (yield* evaluate(node.left, scope)) || (yield* evaluate(node.right, scope))
×
UNCOV
232
    case '&&':
×
233
      return (yield* evaluate(node.left, scope)) && (yield* evaluate(node.right, scope))
×
UNCOV
234
    case '??':
×
235
      return (yield* evaluate(node.left, scope)) ?? (yield* evaluate(node.right, scope))
×
UNCOV
236
    default:
×
237
      /* istanbul ignore next */
UNCOV
238
      throw new SyntaxError(`Unexpected token ${node.operator}`)
×
UNCOV
239
  }
×
UNCOV
240
}
×
241

242
export interface MemberExpressionOptions {
243
  getObj?: boolean
244
  getVar?: boolean
245
}
246

247
export function* MemberExpression(
1✔
248
  node: acorn.MemberExpression,
194✔
249
  scope: Scope,
194✔
250
  options: MemberExpressionOptions = {},
194✔
251
) {
194✔
252
  const { getObj = false, getVar = false } = options
194✔
253

254
  let object: any
194✔
255
  if (node.object.type === 'Super') {
194!
256
    object = yield* Super(node.object, scope, { getProto: true })
×
257
  } else {
194✔
258
    object = yield* evaluate(node.object, scope)
194✔
259
  }
194✔
260

261
  if (getObj) return object
194✔
262

263
  let key: string
112✔
264
  let priv: boolean = false
112✔
265

266
  if (node.computed) {
173!
267
    key = yield* evaluate(node.property, scope)
×
268
  } else if (node.property.type === 'PrivateIdentifier') {
173✔
269
    key = node.property.name
×
270
    priv = true
×
271
  } else {
112✔
272
    key = (node.property as acorn.Identifier).name
112✔
273
  }
112✔
274

275
  if (priv) {
173!
276
    object = object[PRIVATE]
×
UNCOV
277
  }
✔
278

279
  if (getVar) {
173✔
280
    // left value
281
    const setter = getSetter(object, key)
80✔
282
    if (node.object.type === 'Super' && setter) {
80!
283
      // transfer the setter from super to this with a private key
284
      const thisObject = scope.find('this').get()
×
285
      const privateKey = createSymbol(key)
×
286
      define(thisObject, privateKey, { set: setter })
×
287
      return new Prop(thisObject, privateKey)
×
288
    } else {
80✔
289
      return new Prop(object, key)
80✔
290
    }
80✔
291
  } else {
173✔
292
    // right value
293
    const getter = getGetter(object, key)
32✔
294
    if (node.object.type === 'Super' && getter) {
32!
295
      const thisObject = scope.find('this').get()
×
296
      // if it's optional chaining, check if this ref is null or undefined, so use ==
297
      if (node.optional && thisObject == null) {
×
298
        return undefined
×
UNCOV
299
      }
×
300
      return getter.call(thisObject)
×
301
    } else {
32✔
302
      // if it's optional chaining, check if object is null or undefined, so use ==
303
      if (node.optional && object == null) {
32!
304
        return undefined
×
UNCOV
305
      }
×
306
      return object[key]
32✔
307
    }
32✔
308
  }
32✔
309
}
194✔
310

311
export function* ConditionalExpression(node: acorn.ConditionalExpression, scope: Scope) {
1✔
312
  return (yield* evaluate(node.test, scope))
×
UNCOV
313
    ? (yield* evaluate(node.consequent, scope))
×
UNCOV
314
    : (yield* evaluate(node.alternate, scope))
×
UNCOV
315
}
×
316

317
export function* CallExpression(node: acorn.CallExpression, scope: Scope) {
1✔
318
  let func: any
151✔
319
  let object: any
151✔
320

321
  if (node.callee.type === 'MemberExpression') {
151✔
322
    object = yield* MemberExpression(node.callee, scope, { getObj: true })
82✔
323

324
    // if it's optional chaining, check if object is null or undefined, so use ==
325
    if (node.callee.optional && object == null) {
82!
326
      return undefined
×
UNCOV
327
    }
×
328

329
    // get key
330
    let key: string
82✔
331
    let priv: boolean = false
82✔
332

333
    if (node.callee.computed) {
82!
334
      key = yield* evaluate(node.callee.property, scope)
×
335
    } else if (node.callee.property.type === 'PrivateIdentifier') {
82!
336
      key = node.callee.property.name
×
337
      priv = true
×
338
    } else {
82✔
339
      key = (node.callee.property as acorn.Identifier).name
82✔
340
    }
82✔
341

342
    let obj = object
82✔
343

344
    if (priv) {
82!
345
      obj = obj[PRIVATE]
×
UNCOV
346
    }
×
347

348
    // right value
349
    if (node.callee.object.type === 'Super') {
82!
350
      const thisObject = scope.find('this').get()
×
351
      func = obj[key].bind(thisObject)
×
352
    } else {
82✔
353
      func = obj[key]
82✔
354
    }
82✔
355

356
    // if it's optional chaining, check if function is null or undefined, so use ==
357
    if (node.optional && func == null) {
82!
358
      return undefined
×
UNCOV
359
    }
×
360

361
    if (typeof func !== 'function') {
82!
362
      throw new TypeError(`${key} is not a function`)
×
363
    } else if (CLSCTOR in func) {
82!
364
      throw new TypeError(`Class constructor ${key} cannot be invoked without 'new'`)
×
UNCOV
365
    }
×
366
  } else {
132✔
367
    object = scope.find('this').get()
69✔
368
    func = yield* evaluate(node.callee, scope)
69✔
369

370
    // if it's optional chaining, check if function is null or undefined, so use ==
371
    if (node.optional && func == null) {
69!
372
      return undefined
×
UNCOV
373
    }
×
374

375
    if (typeof func !== 'function' || node.callee.type !== 'Super' && CLSCTOR in func) {
69!
UNCOV
376
      let name: string
×
377
      if (node.callee.type === 'Identifier') {
×
378
        name = node.callee.name
×
UNCOV
379
      } else {
×
380
        try {
×
381
          name = JSON.stringify(func)
×
UNCOV
382
        } catch (err) {
×
383
          name = '' + func
×
UNCOV
384
        }
×
UNCOV
385
      }
×
386
      if (typeof func !== 'function') {
×
387
        throw new TypeError(`${name} is not a function`)
×
UNCOV
388
      } else {
×
389
        throw new TypeError(`Class constructor ${name} cannot be invoked without 'new'`)
×
UNCOV
390
      }
×
UNCOV
391
    }
×
392
  }
69✔
393

394
  let args: any[] = []
151✔
395
  for (let i = 0; i < node.arguments.length; i++) {
151✔
396
    const arg = node.arguments[i]
139✔
397
    if (arg.type === 'SpreadElement') {
139!
398
      args = args.concat(yield* SpreadElement(arg, scope))
×
399
    } else {
139✔
400
      args.push(yield* evaluate(arg, scope))
139✔
401
    }
137✔
402
  }
139✔
403

404
  if (node.callee.type === 'Super') {
151!
405
    const superCall = scope.find(SUPERCALL)
×
406
    const construct = superCall.get()
×
407
    if (construct === true) {
×
408
      throw new ReferenceError('Super constructor may only be called once')
×
UNCOV
409
    }
×
410
    const inst = callSuper(object, func, args)
×
411
    yield* construct(inst)
×
412
    scope.find('this').set(inst)
×
413
    scope.find(SUPERCALL).set(true)
×
414
    return inst
×
UNCOV
415
  }
✔
416

417
  try {
149✔
418
    return func.apply(object, args)
149✔
419
  } catch (err) {
151✔
420
    if (
1✔
421
      err instanceof TypeError && err.message === 'Illegal invocation'
1!
UNCOV
422
      && func.toString().indexOf('[native code]') !== -1
×
423
    ) {
1!
424
      // you will get "TypeError: Illegal invocation" if not binding native function with window
425
      const win = scope.global().find('window').get()
×
426
      if (win && win[WINDOW]) {
×
427
        return func.apply(win[WINDOW], args)
×
UNCOV
428
      }
×
UNCOV
429
    }
×
430
    throw err
1✔
431
  }
1✔
432
}
151✔
433

434
export function* NewExpression(node: acorn.NewExpression, scope: Scope) {
1✔
435
  const constructor = yield* evaluate(node.callee, scope)
2✔
436

437
  if (typeof constructor !== 'function') {
2!
UNCOV
438
    let name: string
×
439
    if (node.callee.type === 'Identifier') {
×
440
      name = node.callee.name
×
UNCOV
441
    } else {
×
442
      try {
×
443
        name = JSON.stringify(constructor)
×
UNCOV
444
      } catch (err) {
×
445
        name = '' + constructor
×
UNCOV
446
      }
×
UNCOV
447
    }
×
448
    throw new TypeError(`${name} is not a constructor`)
×
449
  } else if (constructor[NOCTOR]) {
2!
450
    throw new TypeError(`${constructor.name || '(intermediate value)'} is not a constructor`)
×
UNCOV
451
  }
×
452

453
  let args: any[] = []
2✔
454
  for (let i = 0; i < node.arguments.length; i++) {
2✔
455
    const arg = node.arguments[i]
1✔
456
    if (arg.type === 'SpreadElement') {
1!
457
      args = args.concat(yield* SpreadElement(arg, scope))
×
458
    } else {
1✔
459
      args.push(yield* evaluate(arg, scope))
1✔
460
    }
1✔
461
  }
1✔
462

463
  return new constructor(...args)
2✔
464
}
2✔
465

466
export function* MetaProperty(node: acorn.MetaProperty, scope: Scope) {
1✔
467
  if (node.meta.name === 'new' && node.property.name === 'target') {
×
468
    return scope.find(NEWTARGET).get()
×
469
  } else if (node.meta.name === 'import' && node.property.name === 'meta') {
×
470
    return { url: '' }
×
UNCOV
471
  }
×
UNCOV
472
}
×
473

474
export function* SequenceExpression(node: acorn.SequenceExpression, scope: Scope) {
1✔
UNCOV
475
  let result: any
×
476
  for (let i = 0; i < node.expressions.length; i++) {
×
477
    result = yield* evaluate(node.expressions[i], scope)
×
UNCOV
478
  }
×
479
  return result
×
UNCOV
480
}
×
481

482
export function* ArrowFunctionExpression(node: acorn.ArrowFunctionExpression, scope: Scope) {
1✔
483
  return createFunc(node, scope)
3✔
484
}
3✔
485

486
export function* TemplateLiteral(node: acorn.TemplateLiteral, scope: Scope) {
1✔
487
  const quasis = node.quasis.slice()
×
488
  const expressions = node.expressions.slice()
×
489

490
  let result = ''
×
UNCOV
491
  let temEl: acorn.TemplateElement
×
UNCOV
492
  let expr: acorn.Expression
×
493

494
  while (temEl = quasis.shift()) {
×
495
    result += yield* TemplateElement(temEl, scope)
×
496
    expr = expressions.shift()
×
497
    if (expr) {
×
498
      result += yield* evaluate(expr, scope)
×
UNCOV
499
    }
×
UNCOV
500
  }
×
501

502
  return result
×
UNCOV
503
}
×
504

505
export function* TaggedTemplateExpression(node: acorn.TaggedTemplateExpression, scope: Scope) {
1✔
506
  const tagFunc = yield* evaluate(node.tag, scope)
×
507

508
  const quasis = node.quasi.quasis
×
509
  const str = quasis.map(v => v.value.cooked)
×
510
  const raw = quasis.map(v => v.value.raw)
×
511

512
  define(str, 'raw', {
×
UNCOV
513
    value: freeze(raw)
×
UNCOV
514
  })
×
515

516
  const expressions = node.quasi.expressions
×
517

518
  const args = []
×
519
  if (expressions) {
×
520
    for (let i = 0; i < expressions.length; i++) {
×
521
      args.push(yield* evaluate(expressions[i], scope))
×
UNCOV
522
    }
×
UNCOV
523
  }
×
524

525
  return tagFunc(freeze(str), ...args)
×
UNCOV
526
}
×
527

528
export function* TemplateElement(node: acorn.TemplateElement, scope: Scope) {
1✔
529
  return node.value.raw
×
UNCOV
530
}
×
531

532
export function* ClassExpression(node: acorn.ClassExpression, scope: Scope) {
1✔
533
  if (node.id && node.id.name) {
×
534
    // it's for accessing class expression by its name inside
535
    // e.g. const a = class b { log() { console.log(b) } }
536
    const tmpScope = new Scope(scope)
×
537
    const klass = yield* createClass(node, tmpScope)
×
538
    tmpScope.const(node.id.name, klass)
×
539
    return klass
×
UNCOV
540
  } else {
×
541
    return yield* createClass(node, scope)
×
UNCOV
542
  }
×
UNCOV
543
}
×
544

545
export interface SuperOptions {
546
  getProto?: boolean
547
}
548

549
export function* Super(node: acorn.Super, scope: Scope, options: SuperOptions = {}) {
1✔
550
  const { getProto = false } = options
×
551
  const superClass = scope.find(SUPER).get()
×
552
  return getProto ? superClass.prototype: superClass
×
UNCOV
553
}
×
554

555
export interface SpreadOptions {
556
  spreadProps?: boolean
557
}
558

559
export function* SpreadElement(node: acorn.SpreadElement, scope: Scope, options: SpreadOptions = {}) {
1✔
560
  const result = yield* evaluate(node.argument, scope)
×
561
  if (options.spreadProps) {
×
562
    return result
×
UNCOV
563
  }
×
564
  if (typeof Symbol === 'function' && typeof result[Symbol.iterator] !== 'function') {
×
565
    throw new TypeError('Spread syntax requires ...iterable[Symbol.iterator] to be a function')
×
UNCOV
566
  }
×
567
  return [...result]
×
UNCOV
568
}
×
569

570
export function* ChainExpression(node: acorn.ChainExpression, scope: Scope) {
1✔
571
  return yield* evaluate(node.expression, scope)
×
UNCOV
572
}
×
573

574
export function* ImportExpression(node: acorn.ImportExpression, scope: Scope) {
1✔
575
  const globalScope = scope.global()
2✔
576

577
  const source = yield* evaluate(node.source, scope)
2✔
578
  const module = globalScope.find(IMPORT + source)
2✔
579
  let value: any
2✔
580
  if (module) {
2✔
581
    const result = module.get()
2✔
582
    if (result) {
2✔
583
      if (typeof result === 'function') {
2✔
584
        value = result()
2✔
585
      } else if (typeof result === 'object') {
2!
586
        value = result
×
UNCOV
587
      }
×
588
    }
2✔
589
  }
2✔
590

591
  if (!value || typeof value !== 'object') {
2!
592
    return Promise.reject(new TypeError(`Failed to resolve module specifier "${source}"`))
×
UNCOV
593
  }
×
594

595
  return Promise.resolve(value)
2✔
596
}
2✔
597

598
/*<remove>*/
599
export function* YieldExpression(node: acorn.YieldExpression, scope: Scope): any {
1✔
600
  const res = yield* evaluate(node.argument, scope)
21✔
601
  return node.delegate ? yield* res : yield res
21✔
602
}
21✔
603

604
export function* AwaitExpression(node: acorn.AwaitExpression, scope: Scope): any {
1✔
605
  AWAIT.RES = yield* evaluate(node.argument, scope)
22✔
606
  return yield AWAIT
21✔
607
}
21✔
608
/*</remove>*/
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