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

satisfactory-dev / ajv-utilities / 24665792620

20 Apr 2026 11:48AM UTC coverage: 98.2% (-1.8%) from 100.0%
24665792620

push

github

SignpostMarv
adjusting indentation

185 of 193 branches covered (95.85%)

Branch coverage included in aggregate %.

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

23 existing lines in 1 file now uncovered.

1506 of 1529 relevant lines covered (98.5%)

564.27 hits per line

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

98.05
/src/TypeScriptify.ts
1
import type {
1✔
2
        ValidateFunction,
1✔
3
} from 'ajv';
1✔
4

1✔
5
import {
1✔
6
        esmify,
1✔
7
} from './AjvUtilities.ts';
1✔
8
import type {
1✔
9
        BinaryExpression,
1✔
10
        BinaryOperatorToken,
1✔
11
        BindingPattern,
1✔
12
        CallExpression,
1✔
13
        EmptyStatement,
1✔
14
        Expression,
1✔
15
        FunctionDeclaration,
1✔
16
        Identifier,
1✔
17
        IfStatement,
1✔
18
        ImportDeclaration,
1✔
19
        Node,
1✔
20
        NodeArray,
1✔
21
        ObjectLiteralExpression,
1✔
22
        ParameterDeclaration,
1✔
23
        PrefixUnaryExpression,
1✔
24
        PropertyAccessExpression,
1✔
25
        SourceFile,
1✔
26
        Statement,
1✔
27
        StringLiteral,
1✔
28
        TransformationContext,
1✔
29
        TypeOfExpression,
1✔
30
        VariableDeclaration,
1✔
31
        VariableDeclarationList,
1✔
32
        VariableStatement,
1✔
33
        Visitor,
1✔
34
} from 'typescript';
1✔
35

1✔
36
import {
1✔
37
        createPrinter,
1✔
38
        createSourceFile,
1✔
39
        factory,
1✔
40
        isBinaryExpression,
1✔
41
        isCallExpression,
1✔
42
        isEmptyStatement,
1✔
43
        isFunctionDeclaration,
1✔
44
        isIdentifier,
1✔
45
        isIfStatement,
1✔
46
        isObjectBindingPattern,
1✔
47
        isObjectLiteralExpression,
1✔
48
        isPrefixUnaryExpression,
1✔
49
        isPropertyAccessExpression,
1✔
50
        isStringLiteral,
1✔
51
        isTypeOfExpression,
1✔
52
        isVariableDeclaration,
1✔
53
        isVariableStatement,
1✔
54
        ScriptTarget,
1✔
55
        SyntaxKind,
1✔
56
        transform,
1✔
57
        visitEachChild,
1✔
58
        visitNode,
1✔
59
} from 'typescript';
1✔
60

1✔
61
export type Config = {
1✔
62
        remove_schema: boolean,
1✔
63
        remove_dataCtxKeys: [
1✔
64
                keyof Exclude<Parameters<ValidateFunction>[1], undefined>,
1✔
65
                ...(keyof Exclude<
1✔
66
                        Parameters<ValidateFunction>[1],
1✔
67
                        undefined
1✔
68
                >)[],
1✔
69
        ],
1✔
70
        specify_types: {
1✔
71
                [key: string]: [string, string],
1✔
72
        },
1✔
73
};
1✔
74

1✔
75
type prepend_with_imports = {
1✔
76
        [key: string]: Set<string>,
1✔
77
        ajv: Set<string>,
1✔
78
};
1✔
79

1✔
80
abstract class ConditionalVisitor<
1✔
81
        TNode extends Node,
1✔
82
        TReturn extends (
1✔
83
                | void
1✔
84
                | (
1✔
85
                        | Node // replace the node
1✔
86
                        | false // no action needed
1✔
87
                        | undefined // remove the node
1✔
88
                )
1✔
89
        ),
1✔
90
> {
1✔
91
        protected validate_function_name = /^validate\d+$/;
1✔
92

174✔
93
        readonly visit: ((
174✔
94
                node: TNode,
174✔
95
                config?: Partial<Config>,
174✔
96
        ) => TReturn);
174✔
97

174✔
98
        readonly passes: ((
1✔
99
                maybe: Node,
1✔
100
                config?: Partial<Config>,
1✔
101
        ) => maybe is TNode);
1✔
102

1✔
103
        constructor(
1✔
104
                passes: ConditionalVisitor<TNode, TReturn>['passes'],
174✔
105
                visit: ConditionalVisitor<TNode, TReturn>['visit'],
174✔
106
        ) {
174✔
107
                this.passes = passes;
174✔
108
                this.visit = visit;
174✔
109
        }
174✔
110
}
1✔
111

1✔
112
abstract class ConditionalPreprocessor<
1✔
113
        T extends Node,
1✔
114
> extends ConditionalVisitor<T, void> {
1✔
115
}
1✔
116

1✔
117
abstract class ConditionalModification<
1✔
118
        T extends Node,
1✔
119
> extends ConditionalVisitor<T, (Node | false | undefined)> {
1✔
120
}
1✔
121

1✔
122
type ValidateFunctionDeclaration = (
1✔
123
        & FunctionDeclaration
1✔
124
        & {
1✔
125
                name: (
1✔
126
                        & Identifier
1✔
127
                        & {
1✔
128
                                getText(): `validate${number}`,
1✔
129
                        }
1✔
130
                ),
1✔
131
                parameters: [
1✔
132
                        ParameterDeclaration,
1✔
133
                        ParameterDeclaration,
1✔
134
                ],
1✔
135
        }
1✔
136
);
1✔
137

1✔
138
export default class TypeScriptify {
1✔
139
        ify(code: string, config?: Partial<Config>): string {
1✔
140
                code = esmify(code);
14✔
141
                const source = createSourceFile(
14✔
142
                        'ify.js',
14✔
143
                        code,
14✔
144
                        ScriptTarget.ESNext,
14✔
145
                        true,
14✔
146
                );
14✔
147

14✔
148
                const specify_types: {
14✔
149
                        [key: string]: Config['specify_types'][string][0],
14✔
150
                } = {};
14✔
151

14✔
152
                let result = transform(source, [
14✔
153
                        (context) => this.#first_pass(
14✔
154
                                context,
14✔
155
                                config || {},
14!
156
                                specify_types,
14✔
157
                        ),
14✔
158
                ]);
14✔
159

14✔
160
                result = transform(result.transformed[0], [
14✔
161
                        (context) => this.#second_pass(
14✔
162
                                context,
14✔
163
                                config || {},
14!
164
                                Object.freeze(specify_types),
14✔
165
                        ),
14✔
166
                ]);
14✔
167

14✔
168
                code = createPrinter().printFile(result.transformed[0]);
14✔
169

14✔
170
                return code.replace('"use strict";\n', '');
14✔
171
        }
14✔
172

1✔
173
        #patch_is_array() {
1✔
174
                return factory.createFunctionDeclaration(
3✔
175
                        undefined,
3✔
176
                        undefined,
3✔
177
                        'ajv_utilities__is_probably_array',
3✔
178
                        undefined,
3✔
179
                        [
3✔
180
                                factory.createParameterDeclaration(
3✔
181
                                        undefined,
3✔
182
                                        undefined,
3✔
183
                                        'maybe',
3✔
184
                                        undefined,
3✔
185
                                        factory.createKeywordTypeNode(SyntaxKind.UnknownKeyword),
3✔
186
                                ),
3✔
187
                        ],
3✔
188
                        factory.createTypePredicateNode(
3✔
189
                                undefined,
3✔
190
                                'maybe',
3✔
191
                                factory.createArrayTypeNode(
3✔
192
                                        factory.createKeywordTypeNode(
3✔
193
                                                SyntaxKind.UnknownKeyword,
3✔
194
                                        ),
3✔
195
                                ),
3✔
196
                        ),
3✔
197
                        factory.createBlock([
3✔
198
                                factory.createReturnStatement(
3✔
199
                                        factory.createCallExpression(
3✔
200
                                                factory.createPropertyAccessExpression(
3✔
201
                                                        factory.createIdentifier('Array'),
3✔
202
                                                        factory.createIdentifier('isArray'),
3✔
203
                                                ),
3✔
204
                                                undefined,
3✔
205
                                                [
3✔
206
                                                        factory.createIdentifier('maybe'),
3✔
207
                                                ],
3✔
208
                                        ),
3✔
209
                                ),
3✔
210
                        ]),
3✔
211
                );
3✔
212
        }
3✔
213

1✔
214
        #patch_is_object() {
1✔
215
                return factory.createFunctionDeclaration(
8✔
216
                        undefined,
8✔
217
                        undefined,
8✔
218
                        'ajv_utilities__is_probably_object',
8✔
219
                        undefined,
8✔
220
                        [
8✔
221
                                factory.createParameterDeclaration(
8✔
222
                                        undefined,
8✔
223
                                        undefined,
8✔
224
                                        'maybe',
8✔
225
                                        undefined,
8✔
226
                                        factory.createKeywordTypeNode(SyntaxKind.UnknownKeyword),
8✔
227
                                ),
8✔
228
                        ],
8✔
229
                        factory.createTypePredicateNode(
8✔
230
                                undefined,
8✔
231
                                'maybe',
8✔
232
                                factory.createTypeReferenceNode(
8✔
233
                                        'Record',
8✔
234
                                        [
8✔
235
                                                factory.createKeywordTypeNode(
8✔
236
                                                        SyntaxKind.StringKeyword,
8✔
237
                                                ),
8✔
238
                                                factory.createKeywordTypeNode(
8✔
239
                                                        SyntaxKind.UnknownKeyword,
8✔
240
                                                ),
8✔
241
                                        ],
8✔
242
                                ),
8✔
243
                        ),
8✔
244
                        factory.createBlock([
8✔
245
                                factory.createReturnStatement(
8✔
246
                                        factory.createBinaryExpression(
8✔
247
                                                factory.createBinaryExpression(
8✔
248
                                                        factory.createPrefixUnaryExpression(
8✔
249
                                                                SyntaxKind.ExclamationToken,
8✔
250
                                                                factory.createPrefixUnaryExpression(
8✔
251
                                                                        SyntaxKind.ExclamationToken,
8✔
252
                                                                        factory.createIdentifier('maybe'),
8✔
253
                                                                ),
8✔
254
                                                        ),
8✔
255
                                                        factory.createToken(
8✔
256
                                                                SyntaxKind.AmpersandAmpersandToken,
8✔
257
                                                        ),
8✔
258
                                                        factory.createBinaryExpression(
8✔
259
                                                                factory.createTypeOfExpression(
8✔
260
                                                                        factory.createIdentifier('maybe'),
8✔
261
                                                                ),
8✔
262
                                                                factory.createToken(
8✔
263
                                                                        SyntaxKind.EqualsEqualsEqualsToken,
8✔
264
                                                                ),
8✔
265
                                                                factory.createStringLiteral('object'),
8✔
266
                                                        ),
8✔
267
                                                ),
8✔
268
                                                factory.createToken(
8✔
269
                                                        SyntaxKind.AmpersandAmpersandToken,
8✔
270
                                                ),
8✔
271
                                                factory.createPrefixUnaryExpression(
8✔
272
                                                        SyntaxKind.ExclamationToken,
8✔
273
                                                        factory.createCallExpression(
8✔
274
                                                                factory.createPropertyAccessExpression(
8✔
275
                                                                        factory.createIdentifier('Array'),
8✔
276
                                                                        factory.createIdentifier('isArray'),
8✔
277
                                                                ),
8✔
278
                                                                undefined,
8✔
279
                                                                [
8✔
280
                                                                        factory.createIdentifier('maybe'),
8✔
281
                                                                ],
8✔
282
                                                        ),
8✔
283
                                                ),
8✔
284
                                        ),
8✔
285
                                ),
8✔
286
                        ]),
8✔
287
                );
8✔
288
        }
8✔
289

1✔
290
        #sanity_check_preprocess(
1✔
291
                maybe: unknown[],
20✔
292
        ): asserts maybe is ConditionalPreprocessor<Node>[] {
20✔
293
                if(!maybe.every((
20✔
294
                        value,
14✔
295
                ) => value instanceof ConditionalPreprocessor)) {
20!
UNCOV
296
                        throw new TypeError(`Array should consist entirely of ${
×
UNCOV
297
                                ConditionalPreprocessor.name
×
UNCOV
298
                        } instances`);
×
UNCOV
299
                }
×
300
        }
20✔
301

1✔
302
        #sanity_check_modifiers(
1✔
303
                maybe: unknown[],
20✔
304
        ): asserts maybe is ConditionalModification<Node>[] {
20✔
305
                if(!maybe.every((
20✔
306
                        value,
160✔
307
                ) => value instanceof ConditionalModification)) {
20!
UNCOV
308
                        throw new TypeError(`Array should consist entirely of ${
×
UNCOV
309
                                ConditionalModification.name
×
UNCOV
310
                        } instances`);
×
UNCOV
311
                }
×
312
        }
20✔
313

1✔
314
        #generate_visitor(
1✔
315
                context: TransformationContext,
20✔
316
                config: Partial<Config> | undefined,
20✔
317
                preprocess: unknown[],
20✔
318
                modifiers: unknown[],
20✔
319
        ) {
20✔
320
                this.#sanity_check_preprocess(preprocess);
20✔
321
                this.#sanity_check_modifiers(modifiers);
20✔
322

20✔
323
                const visitor: Visitor = (node: Node) => {
20✔
324
                        for (const non_modifier of preprocess) {
11,965✔
325
                                if (non_modifier.passes(node, config)) {
6,699✔
326
                                        non_modifier.visit(node, config);
7✔
327
                                }
7✔
328
                        }
6,699✔
329

11,965✔
330
                        for (const maybe of modifiers) {
11,965✔
331
                                if (maybe.passes(node, config)) {
77,867✔
332
                                        const action = maybe.visit(node, config);
257✔
333

257✔
334
                                        if (false === action) {
257✔
335
                                                continue;
22✔
336
                                        } else if (undefined === action) {
257✔
337
                                                return undefined;
3✔
338
                                        }
3✔
339

232✔
340
                                        return visitEachChild(
232✔
341
                                                action,
232✔
342
                                                visitor,
232✔
343
                                                context,
232✔
344
                                        );
232✔
345
                                }
232✔
346
                        }
77,867✔
347

11,730✔
348
                        return visitEachChild(node, visitor, context);
11,730✔
349
                };
20✔
350

20✔
351
                return visitor;
20✔
352
        }
20✔
353

1✔
354
        #first_pass(
1✔
355
                context: TransformationContext,
14✔
356
                config: Partial<Config>,
14✔
357
                specify_types: {
14✔
358
                        [key: string]: Config['specify_types'][string][0],
14✔
359
                },
14✔
360
        ) {
14✔
361
                const prepend_with_imports: prepend_with_imports = {
14✔
362
                        ajv: new Set<string>(),
14✔
363
                };
14✔
364

14✔
365
                let patch_with_is_array = false;
14✔
366
                let patch_with_is_object = false;
14✔
367

14✔
368
                const visitor = this.#generate_visitor(
14✔
369
                        context,
14✔
370
                        config,
14✔
371
                        [
14✔
372
                                new SpecifyTypes(prepend_with_imports, specify_types),
14✔
373
                        ],
14✔
374
                        [
14✔
375
                                new RemoveSchemaDeclaration(),
14✔
376
                                new ModifyValidate(prepend_with_imports),
14✔
377
                                new ModifyVErrors(prepend_with_imports),
14✔
378
                                new TypecastEvalulated(prepend_with_imports),
14✔
379
                                new TypecastSetErrors(prepend_with_imports),
14✔
380
                                new AddErrorObjectType(prepend_with_imports),
14✔
381
                                new TypecastVErrorsPush(prepend_with_imports),
14✔
382
                                new QuestionableCondition(),
14✔
383
                                new Ucs2LengthCorrection(),
14✔
384
                                new PatchIsObject(() => {
14✔
385
                                        patch_with_is_object = true;
9✔
386
                                }),
14✔
387
                                new PatchIsArray(() => {
14✔
388
                                        patch_with_is_array = true;
3✔
389
                                }),
14✔
390
                        ],
14✔
391
                );
14✔
392

14✔
393
                const transformer = (
14✔
394
                        source: SourceFile,
14✔
395
                ) => {
14✔
396
                        const result = visitNode(source, visitor) as SourceFile;
14✔
397

14✔
398
                        const imports: ImportDeclaration[] = [];
14✔
399

14✔
400
                        for (const [from, types] of Object.entries(prepend_with_imports)) {
14✔
401
                                if (types.size < 1) {
20✔
402
                                        continue;
4✔
403
                                }
4✔
404

16✔
405
                                imports.push(factory.createImportDeclaration(
16✔
406
                                        undefined,
16✔
407
                                        factory.createImportClause(
16✔
408
                                                SyntaxKind.TypeKeyword,
16✔
409
                                                undefined,
16✔
410
                                                factory.createNamedImports([
16✔
411
                                                        ...types,
16✔
412
                                                ].sort((a, b) => a.localeCompare(b)).map((
16✔
413
                                                        identifier,
25✔
414
                                                ) => factory.createImportSpecifier(
25✔
415
                                                        false,
25✔
416
                                                        undefined,
25✔
417
                                                        factory.createIdentifier(identifier),
25✔
418
                                                ))),
16✔
419
                                        ),
16✔
420
                                        factory.createStringLiteral(from, true),
16✔
421
                                ));
16✔
422
                        }
16✔
423

14✔
424
                        let modified: Statement[] | undefined = undefined;
14✔
425

14✔
426
                        if (patch_with_is_array) {
14✔
427
                                modified = [
3✔
428
                                        this.#patch_is_array(),
3✔
429
                                        ...(modified || result.statements),
3✔
430
                                ];
3✔
431
                        }
3✔
432

14✔
433
                        if (patch_with_is_object) {
14✔
434
                                modified = [
8✔
435
                                        this.#patch_is_object(),
8✔
436
                                        ...(modified || result.statements),
8✔
437
                                ];
8✔
438
                        }
8✔
439

14✔
440
                        if (imports.length > 0) {
14✔
441
                                modified = [
10✔
442
                                        ...imports,
10✔
443
                                        ...(modified || result.statements),
10✔
444
                                ];
10✔
445
                        }
10✔
446

14✔
447
                        if (modified) {
14✔
448
                                return factory.updateSourceFile(
10✔
449
                                        source,
10✔
450
                                        modified,
10✔
451
                                );
10✔
452
                        }
10✔
453

4✔
454
                        return result;
4✔
455
                };
14✔
456

14✔
457
                return transformer;
14✔
458
        }
14✔
459

1✔
460
        #second_pass(
1✔
461
                context: TransformationContext,
14✔
462
                config: Partial<Config>,
14✔
463
                specify_types: Readonly<{
14✔
464
                        [key: string]: Config['specify_types'][string][0],
14✔
465
                }>,
14✔
466
        ) {
14✔
467
                if (Object.keys(specify_types).length < 1) {
14✔
468
                        return (source: SourceFile) => source;
8✔
469
                }
8✔
470

6✔
471
                const visitor = this.#generate_visitor(
6✔
472
                        context,
6✔
473
                        config,
6✔
474
                        [],
6✔
475
                        [
6✔
476
                                new SpecifyTypePredicate(specify_types),
6✔
477
                        ],
6✔
478
                );
6✔
479

6✔
480
                return (
6✔
481
                        source: SourceFile,
6✔
482
                ) => visitNode(source, visitor) as SourceFile;
6✔
483
        }
14✔
484
}
1✔
485

1✔
486
type SpecifyTypesCandidate = (
1✔
487
        & EmptyStatement
1✔
488
        & {
1✔
489
                parent: (
1✔
490
                        & Node
1✔
491
                        & {
1✔
492
                                parent: (
1✔
493
                                        & FunctionDeclaration
1✔
494
                                        & {
1✔
495
                                                name: (
1✔
496
                                                        & Identifier
1✔
497
                                                        & {
1✔
498
                                                                getText(): `validate${number}`,
1✔
499
                                                        }
1✔
500
                                                ),
1✔
501
                                        }
1✔
502
                                ),
1✔
503
                        }
1✔
504
                ),
1✔
505
        }
1✔
506
);
1✔
507

1✔
508
class SpecifyTypes extends ConditionalPreprocessor<
1✔
509
        SpecifyTypesCandidate
1✔
510
> {
1✔
511
        #configEntry(
1✔
512
                config: Config['specify_types'],
7✔
513
                node: EmptyStatement,
7✔
514
        ): Config['specify_types'][string] | undefined {
7✔
515
                const keys = Object.keys(config);
7✔
516

7✔
517
                if (0 === keys.length) {
7!
UNCOV
518
                        return;
×
UNCOV
519
                }
×
520

7✔
521
                const code = node.getFullText();
7✔
522

7✔
523
                const has_match = new RegExp(
7✔
524
                        `\\/\\*# sourceURL="(${
7✔
525
                                keys.map((key) => RegExp.escape(key)).join('|')
7✔
526
                        })" \\*\\/`,
7✔
527
                );
7✔
528

7✔
529
                const maybe = has_match.exec(code);
7✔
530

7✔
531
                if (maybe && maybe[1] in config) {
7✔
532
                        return config[maybe[1]];
7✔
533
                }
7✔
534
        }
7✔
535

1✔
536
        constructor(
1✔
537
                prepend_with_imports: prepend_with_imports,
14✔
538
                specify_types: {
14✔
539
                        [key: string]: Config['specify_types'][string][0],
14✔
540
                },
14✔
541
        ) {
14✔
542
                super(
14✔
543
                        (node, config): node is SpecifyTypesCandidate => (
14✔
544
                                !!config
6,699✔
545
                                && !!config.specify_types
6,699✔
546
                                && isEmptyStatement(node)
6,699✔
547
                                && isFunctionDeclaration(node.parent.parent)
6,699✔
548
                                && !!node.parent.parent.name
6,699✔
549
                                && this.validate_function_name.test(
6,699✔
550
                                        node.parent.parent.name.getText(),
7✔
551
                                )
7✔
552
                        ),
14✔
553
                        (node, config) => {
14✔
554
                                const maybe = this.#configEntry(
7✔
555
                                        config?.specify_types || {},
7!
556
                                        node,
7✔
557
                                );
7✔
558

7✔
559
                                if (maybe) {
7✔
560
                                        specify_types[
7✔
561
                                                node.parent.parent.name.getText()
7✔
562
                                        ] = maybe[0];
7✔
563
                                        prepend_with_imports.ajv.add('ValidateFunction');
7✔
564

7✔
565
                                        if (!(maybe[1] in prepend_with_imports)) {
7✔
566
                                                prepend_with_imports[maybe[1]] = new Set([maybe[0]]);
6✔
567
                                        } else {
7✔
568
                                                prepend_with_imports[maybe[1]].add(maybe[0]);
1✔
569
                                        }
1✔
570
                                }
7✔
571
                        },
14✔
572
                );
14✔
573
        }
14✔
574
}
1✔
575

1✔
576
type RemoveSchemaDeclarationCandiate = (
1✔
577
        & VariableStatement
1✔
578
        & {
1✔
579
                modifiers: undefined,
1✔
580
                declarationList: (
1✔
581
                        & VariableDeclarationList
1✔
582
                        & {
1✔
583
                                length: Exclude<number, 0>,
1✔
584
                        }
1✔
585
                ),
1✔
586
        }
1✔
587
);
1✔
588

1✔
589
class RemoveSchemaDeclaration extends ConditionalModification<
1✔
590
        RemoveSchemaDeclarationCandiate
1✔
591
> {
1✔
592
        constructor() {
1✔
593
                super(
14✔
594
                        (node, config): node is RemoveSchemaDeclarationCandiate => (
14✔
595
                                !!config
6,699✔
596
                                && !!config.remove_schema
6,699✔
597
                                && isVariableStatement(node)
6,699✔
598
                                && !node.modifiers
6,699✔
599
                                && node.declarationList.declarations.length > 0
6,699✔
600
                        ),
14✔
601
                        (node) => {
14✔
602
                                const was = node.declarationList.declarations.length;
25✔
603

25✔
604
                                const declarartions = node.declarationList.declarations
25✔
605
                                        .filter((
25✔
606
                                                maybe,
25✔
607
                                        ) => {
25✔
608
                                                return (
25✔
609
                                                        !isIdentifier(maybe.name)
25✔
610
                                                        || !/^schema\d+$/.test(maybe.name.getText())
25✔
611
                                                );
25✔
612
                                        });
25✔
613

25✔
614
                                if (was !== declarartions.length) {
25✔
615
                                        if (declarartions.length < 1) {
3✔
616
                                                return undefined;
3✔
617
                                        } else {
3!
UNCOV
618
                                                return (
×
UNCOV
619
                                                        factory.updateVariableStatement(
×
UNCOV
620
                                                                node,
×
UNCOV
621
                                                                node.modifiers,
×
UNCOV
622
                                                                factory.updateVariableDeclarationList(
×
UNCOV
623
                                                                        node.declarationList,
×
UNCOV
624
                                                                        declarartions,
×
UNCOV
625
                                                                ),
×
UNCOV
626
                                                        )
×
UNCOV
627
                                                );
×
UNCOV
628
                                        }
×
629
                                }
3✔
630

22✔
631
                                return false;
22✔
632
                        },
14✔
633
                );
14✔
634
        }
14✔
635
}
1✔
636

1✔
637
class ModifyValidate extends ConditionalModification<
1✔
638
        ValidateFunctionDeclaration
1✔
639
> {
1✔
640
        #prepend_with_imports: prepend_with_imports;
1✔
641

1✔
642
        constructor(prepend_with_imports: prepend_with_imports) {
1✔
643
                super(
14✔
644
                        (node): node is ValidateFunctionDeclaration => (
14✔
645
                                isFunctionDeclaration(node)
6,696✔
646
                                && !!node.name
6,696✔
647
                                && this.validate_function_name.test(
6,696✔
648
                                        node.name.getText(),
11✔
649
                                )
11✔
650
                                && 2 === node.parameters.length
6,696✔
651
                        ),
14✔
652
                        (node, config) => this.#modify_validate(node, config),
14✔
653
                );
14✔
654

14✔
655
                this.#prepend_with_imports = prepend_with_imports;
14✔
656
        }
14✔
657

1✔
658
        #shim_DataValidationCxt() {
1✔
659
                this.#prepend_with_imports.ajv.add('ValidateFunction');
11✔
660

11✔
661
                return factory.createIntersectionTypeNode([
11✔
662
                        factory.createIndexedAccessTypeNode(
11✔
663
                                factory.createTypeReferenceNode(
11✔
664
                                        'Parameters',
11✔
665
                                        [
11✔
666
                                                factory.createTypeReferenceNode(
11✔
667
                                                        'ValidateFunction',
11✔
668
                                                ),
11✔
669
                                        ],
11✔
670
                                ),
11✔
671
                                factory.createLiteralTypeNode(
11✔
672
                                        factory.createNumericLiteral(1),
11✔
673
                                ),
11✔
674
                        ),
11✔
675
                        factory.createTypeLiteralNode([
11✔
676
                                factory.createPropertySignature(
11✔
677
                                        undefined,
11✔
678
                                        'rootData',
11✔
679
                                        undefined,
11✔
680
                                        factory.createKeywordTypeNode(
11✔
681
                                                SyntaxKind.UnknownKeyword,
11✔
682
                                        ),
11✔
683
                                ),
11✔
684
                        ]),
11✔
685
                ]);
11✔
686
        }
11✔
687

1✔
688
        #modify_validate(
1✔
689
                node: FunctionDeclaration,
11✔
690
                config?: Partial<Config>,
11✔
691
        ) {
11✔
692
                const [
11✔
693
                        data,
11✔
694
                        options,
11✔
695
                ] = node.parameters;
11✔
696

11✔
697
                const new_data = factory.updateParameterDeclaration(
11✔
698
                        data,
11✔
699
                        data.modifiers,
11✔
700
                        data.dotDotDotToken,
11✔
701
                        data.name,
11✔
702
                        data.questionToken,
11✔
703
                        factory.createKeywordTypeNode(SyntaxKind.UnknownKeyword),
11✔
704
                        data.initializer,
11✔
705
                );
11✔
706

11✔
707
                let options_name: (
11✔
708
                        | BindingPattern
11✔
709
                        | Identifier
11✔
710
                ) = options.name;
11✔
711

11✔
712
                if (
11✔
713
                        config
11✔
714
                        && config.remove_dataCtxKeys
11✔
715
                        && options_name
11✔
716
                        && isObjectBindingPattern(options_name)
11✔
717
                        && options_name.elements.length > 0
11✔
718
                ) {
11✔
719
                        const elements = options_name.elements.filter((
1✔
720
                                maybe,
5✔
721
                        ) => {
5✔
722
                                return (
5✔
723
                                        isIdentifier(maybe.name)
5✔
724
                                        && !(
5✔
725
                                                config.remove_dataCtxKeys as string[]
5✔
726
                                        ).includes(maybe.name.getText())
5✔
727
                                );
5✔
728
                        });
1✔
729

1✔
730
                        options_name = factory.updateObjectBindingPattern(
1✔
731
                                options_name,
1✔
732
                                elements,
1✔
733
                        );
1✔
734
                }
1✔
735

11✔
736
                const new_options = factory.updateParameterDeclaration(
11✔
737
                        options,
11✔
738
                        options.modifiers,
11✔
739
                        options.dotDotDotToken,
11✔
740
                        options_name,
11✔
741
                        options.questionToken,
11✔
742
                        factory.createTypeReferenceNode('Partial', [
11✔
743
                                this.#shim_DataValidationCxt(),
11✔
744
                        ]),
11✔
745
                        options.initializer,
11✔
746
                );
11✔
747

11✔
748
                return factory.updateFunctionDeclaration(
11✔
749
                        node,
11✔
750
                        node.modifiers,
11✔
751
                        node.asteriskToken,
11✔
752
                        node.name,
11✔
753
                        node.typeParameters,
11✔
754
                        [
11✔
755
                                new_data,
11✔
756
                                new_options,
11✔
757
                        ],
11✔
758
                        node.type,
11✔
759
                        node.body,
11✔
760
                );
11✔
761
        }
11✔
762
}
1✔
763

1✔
764
type VErrors = (
1✔
765
        & VariableDeclaration
1✔
766
        & {
1✔
767
                name: (
1✔
768
                        & Identifier
1✔
769
                        & {
1✔
770
                                getText(): 'vErrors',
1✔
771
                        }
1✔
772
                ),
1✔
773
                initializer: {
1✔
774
                        kind?: SyntaxKind.NullKeyword,
1✔
775
                },
1✔
776
        }
1✔
777
);
1✔
778

1✔
779
class ModifyVErrors extends ConditionalModification<
1✔
780
        VErrors
1✔
781
> {
1✔
782
        constructor(
1✔
783
                prepend_with_imports: prepend_with_imports,
14✔
784
        ) {
14✔
785
                super(
14✔
786
                        (node): node is VErrors => (
14✔
787
                                isVariableDeclaration(node)
6,685✔
788
                                && isIdentifier(node.name)
6,685✔
789
                                && 'vErrors' === node.name.getText()
6,685✔
790
                                && node.initializer?.kind === SyntaxKind.NullKeyword
6,685✔
791
                        ),
14✔
792
                        (node) => {
14✔
793
                                prepend_with_imports.ajv.add('ErrorObject');
9✔
794

9✔
795
                                return factory.updateVariableDeclaration(
9✔
796
                                        node,
9✔
797
                                        node.name,
9✔
798
                                        node.exclamationToken,
9✔
799
                                        factory.createUnionTypeNode([
9✔
800
                                                factory.createArrayTypeNode(
9✔
801
                                                        factory.createTypeReferenceNode('ErrorObject'),
9✔
802
                                                ),
9✔
803
                                                factory.createLiteralTypeNode(factory.createNull()),
9✔
804
                                        ]),
9✔
805
                                        node.initializer,
9✔
806
                                );
9✔
807
                        },
14✔
808
                );
14✔
809
        }
14✔
810
}
1✔
811

1✔
812
type TypecastEvalulatedCandidate = (
1✔
813
        & BinaryExpression
1✔
814
        & {
1✔
815
                left: (
1✔
816
                        & PropertyAccessExpression
1✔
817
                        & {
1✔
818
                                expression: (
1✔
819
                                        & Identifier
1✔
820
                                        & {
1✔
821
                                                getText(): 'evaluated',
1✔
822
                                        }
1✔
823
                                ),
1✔
824
                        }
1✔
825
                ),
1✔
826
                right: ObjectLiteralExpression,
1✔
827
        }
1✔
828
);
1✔
829

1✔
830
class TypecastEvalulated extends ConditionalModification<
1✔
831
        TypecastEvalulatedCandidate
1✔
832
> {
1✔
833
        constructor(prepend_with_imports: prepend_with_imports) {
1✔
834
                super(
14✔
835
                        (node): node is TypecastEvalulatedCandidate => (
14✔
836
                                isBinaryExpression(node)
6,676✔
837
                                && isPropertyAccessExpression(node.left)
6,676✔
838
                                && isIdentifier(node.left.expression)
6,676✔
839
                                && !!this.validate_function_name.test(
6,676✔
840
                                        node.left.expression.getText(),
79✔
841
                                )
79✔
842
                                && 'evaluated' === node.left.name.getText()
6,676✔
843
                                && isObjectLiteralExpression(node.right)
6,676✔
844
                        ),
14✔
845
                        (node) => {
14✔
846
                                prepend_with_imports.ajv.add('ValidateFunction');
11✔
847

11✔
848
                                return factory.updateBinaryExpression(
11✔
849
                                        node,
11✔
850
                                        node.left,
11✔
851
                                        node.operatorToken,
11✔
852
                                        factory.createAsExpression(
11✔
853
                                                node.right,
11✔
854
                                                factory.createIndexedAccessTypeNode(
11✔
855
                                                        factory.createTypeReferenceNode(
11✔
856
                                                                'ValidateFunction',
11✔
857
                                                        ),
11✔
858
                                                        factory.createLiteralTypeNode(
11✔
859
                                                                factory.createStringLiteral('evaluated'),
11✔
860
                                                        ),
11✔
861
                                                ),
11✔
862
                                        ),
11✔
863
                                );
11✔
864
                        },
14✔
865
                );
14✔
866
        }
14✔
867
}
1✔
868

1✔
869
type TypecastSetErrorsCandidate = (
1✔
870
        & BinaryExpression
1✔
871
        & {
1✔
872
                left: (
1✔
873
                        & PropertyAccessExpression
1✔
874
                        & {
1✔
875
                                expression: (
1✔
876
                                        & Identifier
1✔
877
                                        & {
1✔
878
                                                getText(): `validate${number}`,
1✔
879
                                        }
1✔
880
                                ),
1✔
881
                                name: (
1✔
882
                                        & Identifier
1✔
883
                                        & {
1✔
884
                                                getText(): 'errors',
1✔
885
                                        }
1✔
886
                                ),
1✔
887
                        }
1✔
888
                ),
1✔
889
        }
1✔
890
);
1✔
891

1✔
892
class TypecastSetErrors extends ConditionalModification<
1✔
893
        TypecastSetErrorsCandidate
1✔
894
> {
1✔
895
        constructor(prepend_with_imports: prepend_with_imports) {
1✔
896
                super(
14✔
897
                        (node): node is TypecastSetErrorsCandidate => (
14✔
898
                                isBinaryExpression(node)
6,665✔
899
                                && isPropertyAccessExpression(node.left)
6,665✔
900
                                && isIdentifier(node.left.expression)
6,665✔
901
                                && this.validate_function_name.test(
6,665✔
902
                                        node.left.expression.getText(),
68✔
903
                                )
68✔
904
                                && isIdentifier(node.left.name)
6,665✔
905
                                && 'errors' === node.left.name.getText()
6,665✔
906
                        ),
14✔
907
                        (node) => {
14✔
908
                                prepend_with_imports.ajv.add('ValidateFunction');
11✔
909

11✔
910
                                return factory.updateBinaryExpression(
11✔
911
                                        node,
11✔
912
                                        factory.updatePropertyAccessExpression(
11✔
913
                                                node.left,
11✔
914
                                                factory.createAsExpression(
11✔
915
                                                        node.left.expression,
11✔
916
                                                        factory.createTypeReferenceNode(
11✔
917
                                                                'ValidateFunction',
11✔
918
                                                        ),
11✔
919
                                                ),
11✔
920
                                                node.left.name,
11✔
921
                                        ),
11✔
922
                                        node.operatorToken,
11✔
923
                                        node.right,
11✔
924
                                );
11✔
925
                        },
14✔
926
                );
14✔
927
        }
14✔
928
}
1✔
929

1✔
930
type AddErrorObjectTypeCandidate = (
1✔
931
        & VariableDeclaration
1✔
932
        & {
1✔
933
                name: (
1✔
934
                        & Identifier
1✔
935
                        & {
1✔
936
                                getText(): `err${number}`,
1✔
937
                        }
1✔
938
                ),
1✔
939
        }
1✔
940
);
1✔
941

1✔
942
class AddErrorObjectType extends ConditionalModification<
1✔
943
        AddErrorObjectTypeCandidate
1✔
944
> {
1✔
945
        constructor(prepend_with_imports: prepend_with_imports) {
1✔
946
                super(
14✔
947
                        (node): node is AddErrorObjectTypeCandidate => (
14✔
948
                                isVariableDeclaration(node)
6,654✔
949
                                && isIdentifier(node.name)
6,654✔
950
                                && /^err\d+$/.test(node.name.getText())
6,654✔
951
                        ),
14✔
952
                        (node) => {
14✔
953
                                prepend_with_imports.ajv.add('ErrorObject');
75✔
954

75✔
955
                                return factory.updateVariableDeclaration(
75✔
956
                                        node,
75✔
957
                                        node.name,
75✔
958
                                        node.exclamationToken,
75✔
959
                                        factory.createTypeReferenceNode('ErrorObject'),
75✔
960
                                        node.initializer,
75✔
961
                                );
75✔
962
                        },
14✔
963
                );
14✔
964
        }
14✔
965
}
1✔
966

1✔
967
type TypecastVErrorsPushCandidate = (
1✔
968
        & CallExpression
1✔
969
        & {
1✔
970
                expression: (
1✔
971
                        & PropertyAccessExpression
1✔
972
                        & {
1✔
973
                                expression: (
1✔
974
                                        & Identifier
1✔
975
                                        & {
1✔
976
                                                getText(): 'vErrors',
1✔
977
                                        }
1✔
978
                                ),
1✔
979
                                name: (
1✔
980
                                        & Identifier
1✔
981
                                        & {
1✔
982
                                                getText(): 'push',
1✔
983
                                        }
1✔
984
                                ),
1✔
985
                        }
1✔
986
                ),
1✔
987
        }
1✔
988
);
1✔
989

1✔
990
class TypecastVErrorsPush extends ConditionalModification<
1✔
991
        TypecastVErrorsPushCandidate
1✔
992
> {
1✔
993
        constructor(prepend_with_imports: prepend_with_imports) {
1✔
994
                super(
14✔
995
                        (node): node is TypecastVErrorsPushCandidate => (
14✔
996
                                isCallExpression(node)
6,579✔
997
                                && isPropertyAccessExpression(node.expression)
6,579✔
998
                                && isIdentifier(node.expression.expression)
6,579✔
999
                                && 'vErrors' === node.expression.expression.getText()
6,579✔
1000
                                && isIdentifier(node.expression.name)
6,579✔
1001
                                && 'push' === node.expression.name.getText()
6,579✔
1002
                        ),
14✔
1003
                        (node) => {
14✔
1004
                                prepend_with_imports.ajv.add('ErrorObject');
75✔
1005

75✔
1006
                                return factory.updateCallExpression(
75✔
1007
                                        node,
75✔
1008
                                        factory.updatePropertyAccessExpression(
75✔
1009
                                                node.expression,
75✔
1010
                                                factory.createAsExpression(
75✔
1011
                                                        node.expression.expression,
75✔
1012
                                                        factory.createArrayTypeNode(
75✔
1013
                                                                factory.createTypeReferenceNode('ErrorObject'),
75✔
1014
                                                        ),
75✔
1015
                                                ),
75✔
1016
                                                node.expression.name,
75✔
1017
                                        ),
75✔
1018
                                        node.typeArguments,
75✔
1019
                                        node.arguments,
75✔
1020
                                );
75✔
1021
                        },
14✔
1022
                );
14✔
1023
        }
14✔
1024
}
1✔
1025

1✔
1026
type QuestionableConditionCandidate = (
1✔
1027
        & PropertyAccessExpression
1✔
1028
        & {
1✔
1029
                parent: (
1✔
1030
                        & IfStatement
1✔
1031
                        & {
1✔
1032
                                expression: (
1✔
1033
                                        & Identifier
1✔
1034
                                        & {
1✔
1035
                                                getText(): `evaluated${number}`,
1✔
1036
                                        }
1✔
1037
                                ),
1✔
1038
                        }
1✔
1039
                ),
1✔
1040
                questionDotToken: undefined,
1✔
1041
        }
1✔
1042
);
1✔
1043

1✔
1044
class QuestionableCondition extends ConditionalModification<
1✔
1045
        QuestionableConditionCandidate
1✔
1046
> {
1✔
1047
        constructor() {
1✔
1048
                super(
14✔
1049
                        (node): node is QuestionableConditionCandidate => (
14✔
1050
                                isPropertyAccessExpression(node)
6,504✔
1051
                                && node.parent
6,504✔
1052
                                && isIfStatement(node.parent)
6,504✔
1053
                                && isIdentifier(node.expression)
6,504✔
1054
                                && /^evaluated\d+$/.test(node.expression.getText())
6,504✔
1055
                                && !node.questionDotToken
6,504✔
1056
                        ),
14✔
1057
                        (node) => factory.createPropertyAccessChain(
14✔
1058
                                node.expression,
18✔
1059
                                factory.createToken(SyntaxKind.QuestionDotToken),
18✔
1060
                                node.name,
18✔
1061
                        ),
14✔
1062
                );
14✔
1063
        }
14✔
1064
}
1✔
1065

1✔
1066
type ucs2lengthCorrectionCandidate = (
1✔
1067
        & PropertyAccessExpression
1✔
1068
        & {
1✔
1069
                expression: (
1✔
1070
                        & Identifier
1✔
1071
                        & {
1✔
1072
                                getText(): 'ucs2length',
1✔
1073
                        }
1✔
1074
                ),
1✔
1075
                name: (
1✔
1076
                        & Identifier
1✔
1077
                        & {
1✔
1078
                                getText(): 'default',
1✔
1079
                        }
1✔
1080
                ),
1✔
1081
        }
1✔
1082
);
1✔
1083

1✔
1084
class Ucs2LengthCorrection extends ConditionalModification<
1✔
1085
        ucs2lengthCorrectionCandidate
1✔
1086
> {
1✔
1087
        constructor() {
1✔
1088
                super(
14✔
1089
                        (node): node is ucs2lengthCorrectionCandidate => (
14✔
1090
                                isPropertyAccessExpression(node)
6,486✔
1091
                                && isIdentifier(node.expression)
6,486✔
1092
                                && 'ucs2length' === node.expression.getText()
6,486✔
1093
                                && isIdentifier(node.name)
6,486✔
1094
                                && 'default' === node.name.getText()
6,486✔
1095
                        ),
14✔
1096
                        () => factory.createIdentifier('ucs2length'),
14✔
1097
                );
14✔
1098
        }
14✔
1099
}
1✔
1100

1✔
1101
type PatchIsObjectCandidate<
1✔
1102
        IdentifierText extends string = string,
1✔
1103
> = (
1✔
1104
        & IfStatement
1✔
1105
        & {
1✔
1106
                expression: (
1✔
1107
                        & BinaryExpression
1✔
1108
                        & {
1✔
1109
                                left: (
1✔
1110
                                        & BinaryExpression
1✔
1111
                                        & {
1✔
1112
                                                left: (
1✔
1113
                                                        & Identifier
1✔
1114
                                                        & {
1✔
1115
                                                                getText(): IdentifierText,
1✔
1116
                                                        }
1✔
1117
                                                ),
1✔
1118
                                                operatorToken: (
1✔
1119
                                                        & BinaryOperatorToken
1✔
1120
                                                        & {
1✔
1121
                                                                kind: SyntaxKind.AmpersandAmpersandToken,
1✔
1122
                                                        }
1✔
1123
                                                ),
1✔
1124
                                                right: (
1✔
1125
                                                        BinaryExpression
1✔
1126
                                                        & {
1✔
1127
                                                                left: (
1✔
1128
                                                                        & TypeOfExpression
1✔
1129
                                                                        & {
1✔
1130
                                                                                expression: (
1✔
1131
                                                                                        & Identifier
1✔
1132
                                                                                        & {
1✔
1133
                                                                                                getText(): IdentifierText,
1✔
1134
                                                                                        }
1✔
1135
                                                                                ),
1✔
1136
                                                                        }
1✔
1137
                                                                ),
1✔
1138
                                                                operatorToken: (
1✔
1139
                                                                        & BinaryOperatorToken
1✔
1140
                                                                        & {
1✔
1141
                                                                                kind: SyntaxKind.EqualsEqualsToken,
1✔
1142
                                                                        }
1✔
1143
                                                                ),
1✔
1144
                                                                right: (
1✔
1145
                                                                        & StringLiteral
1✔
1146
                                                                        & {
1✔
1147
                                                                                text: 'object',
1✔
1148
                                                                        }
1✔
1149
                                                                ),
1✔
1150
                                                        }
1✔
1151
                                                ),
1✔
1152
                                        }
1✔
1153
                                ),
1✔
1154
                                operatorToken: (
1✔
1155
                                        & BinaryOperatorToken
1✔
1156
                                        & {
1✔
1157
                                                kind: SyntaxKind.AmpersandAmpersandToken,
1✔
1158
                                        }
1✔
1159
                                ),
1✔
1160
                                right: (
1✔
1161
                                        & PrefixUnaryExpression
1✔
1162
                                        & {
1✔
1163
                                                operator: SyntaxKind.ExclamationToken,
1✔
1164
                                                operand: (
1✔
1165
                                                        & CallExpression
1✔
1166
                                                        & {
1✔
1167
                                                                expression: (
1✔
1168
                                                                        & PropertyAccessExpression
1✔
1169
                                                                        & {
1✔
1170
                                                                                expression: (
1✔
1171
                                                                                        & Identifier
1✔
1172
                                                                                        & {
1✔
1173
                                                                                                getText(): 'Array',
1✔
1174
                                                                                        }
1✔
1175
                                                                                ),
1✔
1176
                                                                                name: (
1✔
1177
                                                                                        & Identifier
1✔
1178
                                                                                        & {
1✔
1179
                                                                                                getText(): 'isArray',
1✔
1180
                                                                                        }
1✔
1181
                                                                                ),
1✔
1182
                                                                        }
1✔
1183
                                                                ),
1✔
1184
                                                                arguments: (
1✔
1185
                                                                        & NodeArray<Identifier>
1✔
1186
                                                                        & {
1✔
1187
                                                                                length: 1,
1✔
1188
                                                                                0: (
1✔
1189
                                                                                        & Identifier
1✔
1190
                                                                                        & {
1✔
1191
                                                                                                getText(): IdentifierText,
1✔
1192
                                                                                        }
1✔
1193
                                                                                ),
1✔
1194
                                                                        }
1✔
1195
                                                                ),
1✔
1196
                                                        }
1✔
1197
                                                ),
1✔
1198
                                        }
1✔
1199
                                ),
1✔
1200
                        }
1✔
1201
                ),
1✔
1202
        }
1✔
1203
);
1✔
1204

1✔
1205
class PatchIsObject extends ConditionalModification<
1✔
1206
        PatchIsObjectCandidate
1✔
1207
> {
1✔
1208
        #replace_is_object(
1✔
1209
                name: Expression,
9✔
1210
                then: Statement,
9✔
1211
                else_statement?: Statement,
9✔
1212
        ) {
9✔
1213
                return factory.createIfStatement(
9✔
1214
                        factory.createCallExpression(
9✔
1215
                                factory.createIdentifier('ajv_utilities__is_probably_object'),
9✔
1216
                                undefined,
9✔
1217
                                [name],
9✔
1218
                        ),
9✔
1219
                        then,
9✔
1220
                        else_statement,
9✔
1221
                );
9✔
1222
        }
9✔
1223

1✔
1224
        constructor(patch_needed: () => void) {
1✔
1225
                super(
14✔
1226
                        (node): node is PatchIsObjectCandidate => (
14✔
1227
                                isIfStatement(node)
6,483✔
1228
                                && isBinaryExpression(node.expression)
6,483✔
1229
                                && isBinaryExpression(node.expression.left)
6,483✔
1230
                                && isIdentifier(node.expression.left.left)
6,483✔
1231

6,483✔
1232
                                // oxlint-disable-next-line @stylistic/max-len
6,483✔
1233
                                && SyntaxKind.AmpersandAmpersandToken === node.expression.left.operatorToken.kind
6,483✔
1234

6,483✔
1235
                                && isBinaryExpression(node.expression.left.right)
6,483✔
1236
                                && isTypeOfExpression(node.expression.left.right.left)
6,483✔
1237
                                && isIdentifier(node.expression.left.right.left.expression)
6,483✔
1238

6,483✔
1239
                                // oxlint-disable-next-line @stylistic/max-len
6,483✔
1240
                                && node.expression.left.left.getText() === node.expression.left.right.left.expression.getText()
6,483✔
1241

6,483✔
1242
                                // oxlint-disable-next-line @stylistic/max-len
6,483✔
1243
                                && SyntaxKind.EqualsEqualsToken === node.expression.left.right.operatorToken.kind
6,483✔
1244
                                && isStringLiteral(node.expression.left.right.right)
6,483✔
1245
                                && 'object' === node.expression.left.right.right.text
6,483✔
1246

6,483✔
1247
                                // oxlint-disable-next-line @stylistic/max-len
6,483✔
1248
                                && SyntaxKind.AmpersandAmpersandToken === node.expression.operatorToken.kind
6,483✔
1249
                                && isPrefixUnaryExpression(node.expression.right)
6,483✔
1250

6,483✔
1251
                                // oxlint-disable-next-line @stylistic/max-len
6,483✔
1252
                                && SyntaxKind.ExclamationToken === node.expression.right.operator
6,483✔
1253
                                && isCallExpression(node.expression.right.operand)
6,483✔
1254
                                && isPropertyAccessExpression(
6,483✔
1255
                                        node.expression.right.operand.expression,
9✔
1256
                                )
9✔
1257
                                && isIdentifier(
6,483✔
1258
                                        node.expression.right.operand.expression.expression,
9✔
1259
                                )
9✔
1260
                                && isIdentifier(
6,483✔
1261
                                        node.expression.right.operand.expression.name,
9✔
1262
                                )
9✔
1263
                                && 'Array.isArray' === `${
6,483✔
1264

9✔
1265
                                        // oxlint-disable-next-line @stylistic/max-len
9✔
1266
                                        node.expression.right.operand.expression.expression.getText()
9✔
1267
                                }.${
9✔
1268
                                        node.expression.right.operand.expression.name.getText()
9✔
1269
                                }`
9✔
1270
                                && 1 === node.expression.right.operand.arguments.length
6,483✔
1271
                                && isIdentifier(
6,483✔
1272
                                        node.expression.right.operand.arguments[0],
9✔
1273
                                )
9✔
1274
                                && (
6,483✔
1275
                                        node.expression.left.left.getText(
9✔
1276
                                        ) === node.expression.right.operand.arguments[0].getText()
9✔
1277
                                )
9✔
1278
                        ),
14✔
1279
                        (node) => {
14✔
1280
                                patch_needed();
9✔
1281

9✔
1282
                                return this.#replace_is_object(
9✔
1283
                                        node.expression.left.left,
9✔
1284
                                        node.thenStatement,
9✔
1285
                                        node.elseStatement,
9✔
1286
                                );
9✔
1287
                        },
14✔
1288
                );
14✔
1289
        }
14✔
1290
}
1✔
1291

1✔
1292
type PatchIsArrayCandidate = (
1✔
1293
        & IfStatement
1✔
1294
        & {
1✔
1295
                expression: (
1✔
1296
                        & CallExpression
1✔
1297
                        & {
1✔
1298
                                expression: (
1✔
1299
                                        & PropertyAccessExpression
1✔
1300
                                        & {
1✔
1301
                                                expression: (
1✔
1302
                                                        & Identifier
1✔
1303
                                                        & {
1✔
1304
                                                                getText(): 'Array',
1✔
1305
                                                        }
1✔
1306
                                                ),
1✔
1307
                                                name: (
1✔
1308
                                                        & Identifier
1✔
1309
                                                        & {
1✔
1310
                                                                getText(): 'isArray',
1✔
1311
                                                        }
1✔
1312
                                                ),
1✔
1313
                                        }
1✔
1314
                                ),
1✔
1315
                        }
1✔
1316
                ),
1✔
1317
        }
1✔
1318
);
1✔
1319

1✔
1320
class PatchIsArray extends ConditionalModification<
1✔
1321
        PatchIsArrayCandidate
1✔
1322
> {
1✔
1323
        #replace_is_array(
1✔
1324
                args?: Expression[]|NodeArray<Expression>,
3✔
1325
        ) {
3✔
1326
                return factory.createCallExpression(
3✔
1327
                        factory.createIdentifier('ajv_utilities__is_probably_array'),
3✔
1328
                        undefined,
3✔
1329
                        args,
3✔
1330
                );
3✔
1331
        }
3✔
1332

1✔
1333
        constructor(patch_needed: () => void) {
1✔
1334
                super(
14✔
1335
                        (node): node is PatchIsArrayCandidate => (
14✔
1336
                                isIfStatement(node)
6,474✔
1337
                                && isCallExpression(node.expression)
6,474✔
1338
                                && isPropertyAccessExpression(node.expression.expression)
6,474✔
1339
                                && isIdentifier(node.expression.expression.expression)
6,474✔
1340
                                && isIdentifier(node.expression.expression.name)
6,474✔
1341
                                && 'Array.isArray' === `${
6,474✔
1342
                                        node.expression.expression.expression.getText()
3✔
1343
                                }.${
3✔
1344
                                        node.expression.expression.name.getText()
3✔
1345
                                }`
3✔
1346
                        ),
14✔
1347
                        (node) => {
14✔
1348
                                patch_needed();
3✔
1349

3✔
1350
                                return (
3✔
1351
                                        factory.updateIfStatement(
3✔
1352
                                                node,
3✔
1353
                                                this.#replace_is_array(node.expression.arguments),
3✔
1354
                                                node.thenStatement,
3✔
1355
                                                node.elseStatement,
3✔
1356
                                        )
3✔
1357
                                );
3✔
1358
                        },
14✔
1359
                );
14✔
1360
        }
14✔
1361
}
1✔
1362

1✔
1363
type SpecifyTypePredicateCandidate = (
1✔
1364
        & FunctionDeclaration
1✔
1365
        & {
1✔
1366
                name: (
1✔
1367
                        & Identifier
1✔
1368
                        & {
1✔
1369
                                text: Exclude<string, `ajv_utilities__${string}`>,
1✔
1370
                        }
1✔
1371
                ),
1✔
1372
        }
1✔
1373
);
1✔
1374

1✔
1375
class SpecifyTypePredicate extends ConditionalModification<
1✔
1376
        SpecifyTypePredicateCandidate
1✔
1377
> {
1✔
1378
        constructor(
1✔
1379
                specify_types: Readonly<{
6✔
1380
                        [key: string]: Config['specify_types'][string][0],
6✔
1381
                }>,
6✔
1382
        ) {
6✔
1383
                super(
6✔
1384
                        (node): node is SpecifyTypePredicateCandidate => (
6✔
1385
                                isFunctionDeclaration(node)
5,266✔
1386
                                && !!node.name
5,266✔
1387
                                && isIdentifier(node.name)
5,266✔
1388
                                && !node.name.text.startsWith('ajv_utilities__')
5,266✔
1389
                        ),
6✔
1390
                        (node) => {
6✔
1391
                                const function_name = node.name.getText();
7✔
1392

7✔
1393
                                if (function_name in specify_types) {
7✔
1394
                                        return factory.updateFunctionDeclaration(
7✔
1395
                                                node,
7✔
1396
                                                node.modifiers,
7✔
1397
                                                node.asteriskToken,
7✔
1398
                                                node.name,
7✔
1399
                                                node.typeParameters,
7✔
1400
                                                node.parameters,
7✔
1401
                                                factory.createTypePredicateNode(
7✔
1402
                                                        undefined,
7✔
1403
                                                        'data',
7✔
1404
                                                        factory.createTypeReferenceNode(
7✔
1405
                                                                specify_types[function_name],
7✔
1406
                                                        ),
7✔
1407
                                                ),
7✔
1408
                                                node.body,
7✔
1409
                                        );
7✔
1410
                                }
7!
UNCOV
1411

×
UNCOV
1412
                                return false;
×
1413
                        },
6✔
1414
                );
6✔
1415
        }
6✔
1416
}
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