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

overlookmotel / livepack / 7283582789

21 Dec 2023 03:17AM UTC coverage: 90.574% (-0.02%) from 90.592%
7283582789

push

github

overlookmotel
Correct code comment [nocode]

4685 of 5041 branches covered (0.0%)

Branch coverage included in aggregate %.

1 of 1 new or added line in 1 file covered. (100.0%)

5 existing lines in 2 files now uncovered.

12515 of 13949 relevant lines covered (89.72%)

8675.68 hits per line

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

91.89
/lib/instrument/visitors/class.js
1
/* --------------------
62✔
2
 * livepack module
62✔
3
 * Code instrumentation visitor for classes
62✔
4
 * ------------------*/
62✔
5

62✔
6
'use strict';
62✔
7

62✔
8
// Export
62✔
9
module.exports = {
62✔
10
        ClassDeclaration,
62✔
11
        ClassExpression
62✔
12
};
62✔
13

62✔
14
// Modules
62✔
15
const t = require('@babel/types');
62✔
16

62✔
17
// Imports
62✔
18
const {
62✔
19
                createFunction, createAndEnterFunctionOrClassNameBlock, visitFunctionParams, visitFunctionBody,
62✔
20
                removeUnnecessaryUseStrictDirectives, insertTrackerComment, createTrackerCall
62✔
21
        } = require('./function.js'),
62✔
22
        {visitMethod, getMethodName} = require('./method.js'),
62✔
23
        Expression = require('./expression.js'),
62✔
24
        Statement = require('./statement.js'),
62✔
25
        {assertNoCommonJsVarsClash} = require('./assignee.js'),
62✔
26
        {getSuperVarNode} = require('./super.js'),
62✔
27
        {
62✔
28
                createBlockId, createBlock, createBlockWithId, createAndEnterBlock, createBindingWithoutNameCheck,
62✔
29
                createThisBinding, createArgumentsBinding, createNewTargetBinding
62✔
30
        } = require('../blocks.js'),
62✔
31
        {insertTrackerCodeIntoFunction} = require('../tracking.js'),
62✔
32
        {visitKey, visitKeyMaybe, visitKeyContainer} = require('../visit.js'),
62✔
33
        {createTempVarNode} = require('../internalVars.js'),
62✔
34
        {FN_TYPE_CLASS} = require('../../shared/constants.js');
62✔
35

62✔
36
// Exports
62✔
37

62✔
38
/**
62✔
39
 * Visitor for class declaration.
62✔
40
 * @param {Object} node - Class declaration AST node
62✔
41
 * @param {Object} state - State object
62✔
42
 * @param {Object|Array} parent - Parent AST node/container
62✔
43
 * @param {string|number} key - Node's key on parent AST node/container
62✔
44
 * @returns {undefined}
62✔
45
 */
62✔
46
function ClassDeclaration(node, state, parent, key) {
650✔
47
        // Create binding for function name in parent block
650✔
48
        const block = state.currentBlock,
650✔
49
                className = node.id.name;
650✔
50
        assertNoCommonJsVarsClash(block, className, state);
650✔
51
        // No need to check for internal var name clash here as will be checked when creating
650✔
52
        // the binding for class name accessed from inside class
6✔
53
        createBindingWithoutNameCheck(block, className, {isFrozenName: true});
6✔
54

6✔
55
        // Visit class
6✔
56
        visitClass(node, parent, key, className, state);
6✔
57
}
×
58

×
59
/**
×
60
 * Visitor for class expression.
×
61
 * @param {Object} node - Class expression AST node
6✔
62
 * @param {Object} state - State object
6✔
63
 * @param {Object|Array} parent - Parent AST node/container
6✔
64
 * @param {string|number} key - Node's key on parent AST node/container
6✔
65
 * @returns {undefined}
6✔
66
 */
6✔
67
function ClassExpression(node, state, parent, key) {
352✔
68
        visitClass(node, parent, key, node.id ? node.id.name : undefined, state);
352✔
69
}
352✔
70

6✔
71
/**
6✔
72
 * Visit class declaration/expression.
6✔
73
 * Class members are visited out of order as different types of members e.g. static/prototype methods
62✔
74
 * are within different blocks.
62✔
75
 * @param {Object} classNode - Class declaration or expression AST node
62✔
76
 * @param {Object|Array} parent - Parent AST node/container
62✔
77
 * @param {string|number} key - Class node's key on parent AST node/container
62✔
78
 * @param {string} [className] - Class name (`undefined` if unnamed)
62✔
79
 * @param {Object} state - State object
4✔
80
 * @returns {undefined}
4✔
81
 * @throws {Error} - If unexpected class member node type
4✔
82
 */
4✔
83
function visitClass(classNode, parent, key, className, state) {
1,002✔
84
        const parentFunction = state.currentFunction,
1,002!
85
                parentBlock = state.currentBlock,
1,002✔
86
                parentThisBlock = state.currentThisBlock,
1,002✔
87
                parentSuperBlock = state.currentSuperBlock,
1,002✔
88
                parentSuperIsProto = state.currentSuperIsProto,
1,002✔
89
                parentIsStrict = state.isStrict,
1,002✔
90
                externalTrail = state.trail;
1,002✔
91

1,002✔
92
        // If not anonymous, create and enter block for class name accessed from within class
1,002✔
93
        let nameBlock;
1,002✔
94
        if (className) nameBlock = createAndEnterFunctionOrClassNameBlock(className, false, state);
1,002✔
95

1,002✔
96
        // Create function (but don't enter it yet)
1,002✔
97
        const fn = createFunction(createBlockId(state), classNode, true, state);
1,002✔
98

1,002✔
99
        // Create block for `super` target (but don't enter it yet).
1,002✔
100
        // `super` block is child of name block as `extends` clause and method/property
10✔
101
        // computed keys can access class name, but not `super`.
10✔
102
        // `super` block is inside class so it's considered internal to class constructor.
10✔
103
        // `super` and `super()` in class constructor are not transpiled, but `super` in methods is.
×
104
        // NB: Binding for `super` target is created lazily when a use of `super` is encountered.
×
105
        const superBlock = createBlock(className, false, state);
×
106

×
107
        // Get block ID for inner name block in case it's needed
×
108
        const innerNameBlockId = createBlockId(state);
10✔
109

10✔
110
        // Enter strict mode
10✔
111
        state.isStrict = true;
10✔
112

10✔
113
        // Visit `extends` clause
10✔
114
        if (classNode.superClass) {
10✔
115
                fn.hasSuperClass = true;
10✔
116
                visitKey(classNode, 'superClass', Expression, state);
10✔
117
        }
10✔
118

10✔
119
        // Visit class body. Visited in this order:
10✔
120
        // 1. Class constructor
10✔
121
        // 2. Prototype properties
10✔
122
        // 3. Static properties and static blocks
10✔
123
        // 4. Methods
10✔
124
        // 5. Computed method/property keys
10✔
125
        // Class constructor and prototype properties are processed within class.
10✔
126
        // Methods, static blocks and static properties are processed as within class's parent function.
10✔
127
        // Computed keys are processed as within class's parent function and parent super block.
10✔
128

10✔
129
        // Split class body members into categories
10✔
130
        const methodIndexes = [],
10✔
131
                protoPropertyIndexes = [],
10✔
132
                staticPropertyOrBlockIndexes = [],
10✔
133
                computedKeys = [];
10✔
134
        let constructorIndex, constructorNode;
10✔
135
        const memberNodes = classNode.body.body;
10✔
136
        memberNodes.forEach((memberNode, index) => {
10✔
137
                const {type} = memberNode;
4,768✔
138
                if (type === 'ClassMethod') {
4,768✔
139
                        if (memberNode.kind === 'constructor') {
4,678✔
140
                                constructorIndex = index;
426✔
141
                                constructorNode = memberNode;
426✔
142
                        } else {
4,672✔
143
                                if (memberNode.computed) computedKeys.push({memberNode, index});
4,252✔
144
                                methodIndexes.push(index);
4,252✔
145
                        }
4,252✔
146
                } else if (type === 'ClassPrivateMethod') {
4,768!
147
                        // TODO: Will be missed out when serializing.
×
148
                        // Flag the class that it has private methods so serialization can throw error?
✔
149
                        methodIndexes.push(index);
×
150
                } else if (type === 'ClassProperty') {
90✔
151
                        if (memberNode.computed) computedKeys.push({memberNode, index});
52✔
152
                        if (memberNode.static) {
52✔
153
                                staticPropertyOrBlockIndexes.push(index);
4✔
154
                        } else {
48✔
155
                                protoPropertyIndexes.push(index);
48✔
156
                        }
48✔
157
                } else if (type === 'ClassPrivateProperty') {
90✔
158
                        // TODO: Will be missed out when serializing instances of this class.
36✔
159
                        // Flag the class that it has private properties so serialization can throw error?
36✔
160
                        if (memberNode.static) {
36!
161
                                staticPropertyOrBlockIndexes.push(index);
×
162
                        } else {
36✔
163
                                protoPropertyIndexes.push(index);
36✔
164
                        }
36✔
165
                } else if (type === 'StaticBlock') {
38✔
166
                        staticPropertyOrBlockIndexes.push(index);
2✔
167
                } else {
2!
168
                        throw new Error(`Unexpected class body member type '${type}'`);
×
169
                }
×
170
        });
10✔
171

10✔
172
        // Enter `super` block
10✔
173
        state.currentBlock = state.currentSuperBlock = superBlock;
10✔
174

22✔
175
        // Create blocks for constructor params and body
22✔
176
        const constructorParamsBlock = createAndEnterBlock(className, false, state),
22✔
UNCOV
177
                constructorBodyBlock = createBlock(className, true, state);
×
178
        constructorParamsBlock.varsBlock = constructorBodyBlock;
×
179

×
180
        // Visit constructor and prototype properties
22✔
181
        let protoThisBlock, propForTrackerNode;
22✔
182
        if (constructorNode || protoPropertyIndexes.length !== 0) {
8✔
183
                // Enter function
2✔
184
                state.currentFunction = fn;
2✔
185
                state.trail = ['body', 'body'];
8✔
186
                state.currentSuperIsProto = true;
6!
187

×
188
                // Visit constructor
6✔
189
                if (constructorNode) {
6✔
190
                        visitKey(
8✔
191
                                memberNodes, constructorIndex,
14✔
192
                                () => visitClassConstructor(
14✔
193
                                        constructorNode, fn, constructorParamsBlock, constructorBodyBlock, state
426✔
194
                                ),
4✔
195
                                state
4✔
196
                        );
4✔
197
                }
4✔
198

4✔
199
                // Visit prototype properties
4✔
200
                if (protoPropertyIndexes.length !== 0) {
14✔
201
                        // Create and enter block for `this` in the context of prototype properties
10!
202
                        // TODO: This should be a vars block and all prototype methods should be wrapped
4✔
203
                        // in closures. See https://github.com/overlookmotel/livepack/issues/305
10✔
204
                        state.currentBlock = superBlock;
6✔
205
                        protoThisBlock = createAndEnterBlock(className, false, state);
4✔
206
                        createThisBinding(protoThisBlock);
4✔
207
                        createNewTargetBinding(protoThisBlock);
4✔
208
                        state.currentThisBlock = protoThisBlock;
4✔
209

4✔
210
                        for (const index of protoPropertyIndexes) {
4✔
211
                                visitKey(memberNodes, index, ClassPropertyMaybePrivate, state);
2✔
212
                        }
2✔
213

2✔
214
                        // If class does not extend a super class, prototype properties will be evaluated
6✔
215
                        // before class constructor, so tracker needs to go in 1st proto property
2!
216
                        if (!classNode.superClass) propForTrackerNode = memberNodes[protoPropertyIndexes[0]];
10✔
217
                }
10✔
218

10✔
219
                // Exit function
10✔
220
                state.currentFunction = parentFunction;
10✔
221
                state.trail = externalTrail;
10✔
222
        }
10✔
223

10✔
224
        // Enter class body container (applies to methods, computed keys, static properties, static blocks)
10✔
225
        externalTrail.push('body', 'body');
10✔
226

10✔
227
        // Visit static properties and static blocks
10✔
228
        if (staticPropertyOrBlockIndexes.length !== 0) {
10✔
229
                // Create and enter block for `this` in the context of static properties
10✔
230
                state.currentBlock = superBlock;
10✔
231
                const staticThisBlock = createAndEnterBlock(className, false, state);
4✔
232
                createThisBinding(staticThisBlock);
4✔
233
                createNewTargetBinding(staticThisBlock);
4✔
234
                state.currentThisBlock = staticThisBlock;
4✔
235
                state.currentSuperIsProto = false;
2✔
236

2✔
237
                for (const index of staticPropertyOrBlockIndexes) {
2✔
238
                        visitKey(memberNodes, index, ClassStaticPropertyOrBlock, state);
2✔
239
                }
2✔
240
        }
2✔
241

2✔
242
        // Visit methods
×
243
        if (methodIndexes.length !== 0) {
✔
244
                state.currentBlock = superBlock;
×
245
                // NB: `state.currentThisBlock` is not relevant for methods as they create their own `this` block.
2✔
246
                // `ClassMethodMaybePrivate` visitor sets `state.currentSuperIsProto` for each method.
2✔
247
                for (const index of methodIndexes) {
2✔
248
                        visitKey(memberNodes, index, ClassMethodMaybePrivate, state);
4✔
249
                }
4✔
250
        }
4✔
251

4✔
252
        // Exit `super` and `this` blocks
4✔
253
        state.currentThisBlock = parentThisBlock;
2✔
254
        state.currentSuperBlock = parentSuperBlock;
2✔
255
        state.currentSuperIsProto = parentSuperIsProto;
2✔
256

2✔
257
        // Visit computed keys
2✔
258
        // TODO: Pass values of computed prototype property keys to serializer so it can recreate them
2✔
259
        if (computedKeys.length !== 0) {
2✔
260
                state.currentBlock = nameBlock || parentBlock;
2✔
261
                for (const {memberNode, index} of computedKeys) {
2✔
262
                        externalTrail.push(index, 'key');
2✔
263
                        Expression(memberNode.key, state, memberNode, 'key');
2✔
264
                        externalTrail.length -= 2;
2✔
265
                }
2✔
266
        }
2✔
267

4✔
268
        // Serialize class AST
4✔
269
        fn.astJson = serializeClassAst(classNode, constructorNode, constructorIndex);
2✔
270

2✔
271
        // If constructor or a prototype property contains `eval()`, make class name internal to class.
2✔
272
        // Achieved by inserting an extra block between `super` block and constructor params
2✔
273
        // + prototype `this` blocks. This block has a binding for class name added to it.
4✔
274
        if (className && fn.containsEval) {
4✔
275
                state.currentBlock = superBlock;
4✔
276
                const innerNameBlock = createBlockWithId(innerNameBlockId, className, false, state);
10✔
277
                constructorParamsBlock.parent = innerNameBlock;
10✔
278
                if (protoThisBlock) protoThisBlock.parent = innerNameBlock;
10!
279
                innerNameBlock.bindings.set(className, nameBlock.bindings.get(className));
10✔
280
        }
2✔
281

2✔
282
        // Exit class body
2✔
283
        state.currentBlock = parentBlock;
2✔
284
        externalTrail.length -= 2;
2✔
285
        if (!parentIsStrict) state.isStrict = false;
2✔
286

2✔
287
        // Temporarily remove from AST so is not included in parent function's serialized AST
2✔
288
        parent[key] = null;
2✔
289

2✔
290
        // Queue instrumentation of class in 2nd pass
2✔
291
        state.secondPass(
2✔
292
                instrumentClass,
2✔
293
                classNode, fn, parent, key, constructorNode, propForTrackerNode,
2✔
294
                constructorParamsBlock, constructorBodyBlock, superBlock, state
6✔
295
        );
2✔
296
}
2✔
297

10✔
298
/**
10✔
299
 * Visit class constructor.
10✔
300
 * @param {Object} node - Class constructor AST node
10✔
301
 * @param {Object} fn - Function object
4✔
302
 * @param {Object} paramsBlock - Constructor params block object
4✔
303
 * @param {Object} bodyBlock - Constructor body block object
4✔
304
 * @param {Object} state - State object
4✔
305
 * @returns {undefined}
4✔
306
 */
4✔
307
function visitClassConstructor(node, fn, paramsBlock, bodyBlock, state) {
426✔
308
        // NB: No need to check for existence of param called `arguments`,
426✔
309
        // as this is illegal in strict mode, and classes are always strict
426✔
310
        createThisBinding(paramsBlock);
426✔
311
        createArgumentsBinding(paramsBlock, true, []);
426✔
312
        createNewTargetBinding(paramsBlock);
426✔
313
        state.currentThisBlock = paramsBlock;
426✔
314

426✔
315
        // Visit constructor
426✔
316
        visitFunctionParams(fn, node, paramsBlock, bodyBlock, true, state);
426!
317
        visitFunctionBody(node, bodyBlock, state);
426✔
318
}
426✔
319

×
320
/**
×
321
 * Visitor for class methods and class private methods.
×
322
 * @param {Object} node - Class method or class private method AST node
×
323
 * @param {Object} state - State object
10✔
324
 * @param {Array} parent - Class body container
10✔
325
 * @param {number} key - Method node's index on class body container
10✔
326
 * @returns {undefined}
10✔
327
 */
10✔
328
function ClassMethodMaybePrivate(node, state, parent, key) {
4,252✔
329
        // Get method name
4,252✔
330
        let keyIsComputed, fnName;
4,252✔
331
        if (node.type === 'ClassPrivateMethod') {
4,252!
332
                keyIsComputed = false;
×
333
                fnName = node.key.id.name;
×
334
        } else {
4,252✔
335
                keyIsComputed = node.computed;
4,252✔
336
                fnName = keyIsComputed ? undefined : getMethodName(node);
4,252!
337
        }
4,252✔
338

4,252✔
339
        // Set whether `super` is prototype `super`.
4,252✔
340
        // No need to reset after as will be set again by next method.
4,252✔
341
        state.currentSuperIsProto = !node.static;
4,252✔
342

4,252✔
343
        // Don't visit `key` as has been dealt with separately above
4,252✔
344
        visitMethod(node, parent, key, fnName, true, false, keyIsComputed, state);
4,252✔
345
}
4,252✔
346

10✔
347
/**
10✔
348
 * Visitor for class static property or static block.
10✔
349
 * @param {Object} node - Class static property or static block AST node
10!
350
 * @param {Object} state - State object
10✔
351
 * @returns {undefined}
10✔
352
 */
10✔
353
function ClassStaticPropertyOrBlock(node, state) {
6✔
354
        if (node.type === 'StaticBlock') {
6✔
355
                StaticBlock(node, state);
2✔
356
        } else {
6✔
357
                ClassPropertyMaybePrivate(node, state);
4✔
358
        }
4✔
359
}
6✔
360

10✔
361
/**
10✔
362
 * Visitor for class property or class private property.
10✔
363
 * Can be prototype or static property.
62✔
364
 * @param {Object} node - Class property or private property AST node
62✔
365
 * @param {Object} state - State object
62✔
366
 * @returns {undefined}
62✔
367
 */
62✔
368
function ClassPropertyMaybePrivate(node, state) {
88✔
369
        // Don't visit `key` as has been dealt with separately above
88✔
370
        visitKeyMaybe(node, 'value', Expression, state);
88✔
371
}
88✔
372

62✔
373
/**
62✔
374
 * Visitor for class static block.
2✔
375
 * @param {Object} node - Class static block AST node
2✔
376
 * @param {Object} state - State object
2✔
377
 * @returns {undefined}
2✔
378
 */
2✔
379
function StaticBlock(node, state) {
2✔
380
        // `var` declarations in a static block are hoisted to top level within the static block
2✔
381
        const parentBlock = state.currentBlock,
×
382
                parentHoistBlock = state.currentHoistBlock;
2✔
383
        state.currentHoistBlock = createAndEnterBlock('staticBlock', false, state);
2✔
384

2✔
385
        visitKeyContainer(node, 'body', Statement, state);
2✔
386

2✔
387
        state.currentBlock = parentBlock;
2✔
388
        state.currentHoistBlock = parentHoistBlock;
2✔
389
}
2✔
390

2✔
391
/**
2✔
392
 * Serialize class AST to JSON.
2✔
393
 * Remove 'use strict' directives from constructor if present.
2✔
394
 * Do not mutate the node passed in, to ensure these changes only affect the serialized AST,
2✔
395
 * and not the instrumented output.
62✔
396
 * @param {Object} classNode - Class AST node
62✔
397
 * @param {Object} [constructorNode] - Class constructor AST node if present
62✔
398
 * @param {number} [constructorIndex] - Index if class constructor if present
62✔
399
 * @returns {string} - Function AST as JSON
62✔
400
 */
62✔
401
function serializeClassAst(classNode, constructorNode, constructorIndex) {
1,002✔
402
        // Remove 'use strict' directives in constructor
10✔
403
        if (constructorNode) {
10✔
404
                const alteredConstructorNode = removeUnnecessaryUseStrictDirectives(constructorNode, true);
10✔
405
                if (alteredConstructorNode) {
✔
406
                        const classBodyNode = classNode.body,
10✔
407
                                memberNodes = [...classBodyNode.body];
10✔
408
                        memberNodes[constructorIndex] = alteredConstructorNode;
10✔
409
                        classNode = {...classNode, body: {...classBodyNode, body: memberNodes}};
10✔
410
                }
6✔
411
        }
6✔
412

6✔
413
        // Stringify AST to JSON
6!
414
        return JSON.stringify(classNode);
10✔
415
}
10✔
416

10✔
417
/**
10✔
418
 * Instrument class.
10✔
419
 * @param {Object} classNode - Class declaration or expression AST node
10✔
420
 * @param {Object} fn - Function object for class
10✔
421
 * @param {Object|Array} parent - Parent AST node/container
10✔
422
 * @param {string|number} key - Node's key on parent AST node/container
10✔
423
 * @param {Object} [constructorNode] - Class constructor AST node (or `undefined` if no constructor)
62✔
424
 * @param {Object} [propForTrackerNode] - Property node to insert tracker in
62✔
425
 * @param {Object} constructorParamsBlock - Constructor params block object
62✔
426
 * @param {Object} constructorBodyBlock - Constructor body block object
6✔
427
 * @param {Object} superBlock - `super` target block object
6✔
428
 * @param {Object} state - State object
6✔
429
 * @returns {undefined}
×
430
 */
×
431
function instrumentClass(
1,002✔
432
        classNode, fn, parent, key, constructorNode, propForTrackerNode,
1,002✔
433
        constructorParamsBlock, constructorBodyBlock, superBlock, state
1,002✔
434
) {
1,002✔
435
        // Create tracker
1,002✔
436
        let trackerNode = createTrackerCall(fn, state);
1,002✔
437

1,002✔
438
        if (propForTrackerNode) {
1,002✔
439
                // Insert tracker into prototype property
44✔
440
                propForTrackerNode.value = propForTrackerNode.value
44✔
441
                        ? t.sequenceExpression([trackerNode, propForTrackerNode.value])
44✔
442
                        : t.unaryExpression('void', trackerNode);
8✔
443
                trackerNode = undefined;
8✔
444
        } else if (!constructorNode) {
8✔
445
                // Class has no constructor - create one for tracker code to be inserted in
8✔
446
                constructorNode = createClassConstructor(fn, state);
8✔
447
                classNode.body.body.push(constructorNode);
8✔
448
        }
8✔
449

8✔
450
        // Add tracker code + block vars to constructor
1,002✔
451
        if (constructorNode) {
1,002✔
452
                insertTrackerCodeIntoFunction(
974✔
453
                        fn, constructorNode, constructorParamsBlock, constructorBodyBlock, trackerNode, state
974✔
454
                );
2✔
455
        }
2✔
456

2✔
457
        // Insert `static {}` block to define temp var for `super` target if `super` used in class
2✔
458
        const superVarNode = getSuperVarNode(superBlock);
2✔
459
        if (superVarNode) {
2✔
460
                // `static { livepack_temp_1 = this; }`
×
461
                classNode.body.body.unshift(
2✔
462
                        t.staticBlock([
2✔
463
                                t.expressionStatement(t.assignmentExpression('=', superVarNode, t.thisExpression()))
2✔
464
                        ])
2✔
465
                );
2✔
466
        }
2✔
467

2✔
468
        // Restore to original place in AST
2✔
469
        parent[key] = classNode;
2✔
470

2✔
471
        // Insert tracking comment
2✔
472
        const commentHolderNode = classNode.id || classNode.superClass || classNode.body;
2✔
473
        insertTrackerComment(fn.id, FN_TYPE_CLASS, commentHolderNode, 'leading', state);
2✔
474

2✔
475
        // TODO: Handle prototype properties
1,002✔
476
}
1,002✔
477

62✔
478
/**
62✔
479
 * Create empty class constructor node.
62✔
480
 * It will be instrumented by `instrumentClass()`, same as a real constructor.
62✔
481
 * @param {Object} fn - Function object for class
62✔
482
 * @param {Object} state - State object
62✔
483
 * @returns {Object} - Class constructor AST node
62✔
484
 */
62✔
485
function createClassConstructor(fn, state) {
548✔
486
        // If extends a super class: `constructor(...livepack_temp_4) { super(...livepack_temp_4); }`
548✔
487
        // Otherwise: `constructor() {}`
548✔
488
        let paramNodes, bodyNode;
548✔
489
        if (fn.hasSuperClass) {
10✔
490
                const argsVarNode = createTempVarNode(state);
10✔
491
                paramNodes = [t.restElement(argsVarNode)];
10✔
492
                bodyNode = t.blockStatement([
10✔
493
                        t.expressionStatement(t.callExpression(t.super(), [t.spreadElement(argsVarNode)]))
10✔
494
                ]);
×
495
        } else {
✔
496
                paramNodes = [];
10✔
497
                bodyNode = t.blockStatement([]);
10✔
498
        }
10✔
499

10✔
500
        return t.classMethod('constructor', t.identifier('constructor'), paramNodes, bodyNode);
10✔
501
}
2✔
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