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

ota-meshi / eslint-plugin-jsonc / 22181448961

19 Feb 2026 12:17PM UTC coverage: 73.221% (+28.0%) from 45.195%
22181448961

push

github

web-flow
Convert to ESM-only package with tsdown bundling (#469)

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: ota-meshi <16508807+ota-meshi@users.noreply.github.com>
Co-authored-by: yosuke ota <otameshiyo23@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

949 of 1185 branches covered (80.08%)

Branch coverage included in aggregate %.

133 of 141 new or added lines in 11 files covered. (94.33%)

2429 existing lines in 30 files now uncovered.

6841 of 9454 relevant lines covered (72.36%)

48.76 hits per line

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

60.88
/lib/rules/sort-array-values.ts
1
import naturalCompare from "natural-compare";
1✔
2
import { createRule } from "../utils";
1✔
3
import type { AST } from "jsonc-eslint-parser";
1✔
4
import { getStaticJSONValue } from "jsonc-eslint-parser";
1✔
5
import type { SourceCode } from "eslint";
1✔
6
import type { AroundTarget } from "../utils/fix-sort-elements";
1✔
7
import {
1✔
8
  fixToMoveDownForSorting,
1✔
9
  fixToMoveUpForSorting,
1✔
10
} from "../utils/fix-sort-elements";
1✔
11
import { calcShortestEditScript } from "../utils/calc-shortest-edit-script";
1✔
12

1✔
13
type JSONValue = ReturnType<typeof getStaticJSONValue>;
1✔
14

1✔
15
//------------------------------------------------------------------------------
1✔
16
// Helpers
1✔
17
//------------------------------------------------------------------------------
1✔
18

1✔
19
type UserOptions = PatternOption[];
1✔
20
type OrderTypeOption = "asc" | "desc";
1✔
21
type PatternOption = {
1✔
22
  pathPattern: string;
1✔
23
  order:
1✔
24
    | OrderObject
1✔
25
    | (
1✔
26
        | string
1✔
27
        | {
1✔
28
            valuePattern?: string;
1✔
29
            order?: OrderObject;
1✔
30
          }
1✔
31
      )[];
1✔
32
  minValues?: number;
1✔
33
};
1✔
34
type OrderObject = {
1✔
35
  type?: OrderTypeOption;
1✔
36
  caseSensitive?: boolean;
1✔
37
  natural?: boolean;
1✔
38
};
1✔
39
type ParsedOption = {
1✔
40
  isTargetArray: (node: JSONArrayData) => boolean;
1✔
41
  ignore: (data: JSONElementData) => boolean;
1✔
42
  isValidOrder: Validator;
1✔
43
  orderText: (data: JSONElementData) => string;
1✔
44
};
1✔
45
type Validator = (a: JSONElementData, b: JSONElementData) => boolean;
1✔
46

1✔
47
type JSONElement = AST.JSONArrayExpression["elements"][number];
1✔
48
class JSONElementData {
1✔
49
  public readonly array: JSONArrayData;
1✔
50

1✔
51
  public readonly node: JSONElement;
1✔
52

1✔
53
  public readonly index: number;
1✔
54

1✔
55
  private cached: { value: JSONValue } | null = null;
1✔
56

1✔
57
  private cachedAround: AroundTarget | null = null;
1✔
58

1✔
59
  public get reportLoc() {
1✔
60
    if (this.node) {
1✔
61
      return this.node.loc;
1✔
62
    }
1✔
63
    const around = this.around;
1!
64
    return {
1✔
65
      start: around.before.loc.end,
1✔
66
      end: around.after.loc.start,
1✔
67
    };
1✔
68
  }
1✔
69

1✔
70
  public get around(): AroundTarget {
1✔
71
    if (this.cachedAround) {
1✔
72
      return this.cachedAround;
1✔
73
    }
1✔
74
    const sourceCode = this.array.sourceCode;
1✔
75
    if (this.node) {
1✔
76
      return (this.cachedAround = {
1✔
77
        node: this.node,
1✔
78
        before: sourceCode.getTokenBefore(this.node as never)!,
1✔
79
        after: sourceCode.getTokenAfter(this.node as never)!,
1✔
80
      });
1✔
81
    }
1✔
82
    const before =
1!
83
      this.index > 0
1✔
84
        ? this.array.elements[this.index - 1].around.after
1✔
85
        : sourceCode.getFirstToken(this.array.node as never)!;
1✔
86
    const after = sourceCode.getTokenAfter(before)!;
1✔
87
    return (this.cachedAround = { before, after });
1✔
88
  }
1✔
89

1✔
90
  public constructor(array: JSONArrayData, node: JSONElement, index: number) {
1✔
91
    this.array = array;
1✔
92
    this.node = node;
1✔
93
    this.index = index;
1✔
94
  }
1✔
95

1✔
96
  public get value() {
1✔
97
    return (
1✔
98
      this.cached ??
1✔
99
      (this.cached = {
1✔
100
        value: this.node == null ? null : getStaticJSONValue(this.node),
1✔
101
      })
1✔
102
    ).value;
1✔
103
  }
1✔
104
}
1✔
105
class JSONArrayData {
1✔
106
  public readonly node: AST.JSONArrayExpression;
94✔
107

94✔
108
  public readonly sourceCode: SourceCode;
94✔
109

94✔
110
  private cachedElements: JSONElementData[] | null = null;
94✔
111

94✔
112
  public constructor(node: AST.JSONArrayExpression, sourceCode: SourceCode) {
94✔
113
    this.node = node;
94✔
114
    this.sourceCode = sourceCode;
94✔
115
  }
94✔
116

94✔
117
  public get elements() {
94✔
118
    return (this.cachedElements ??= this.node.elements.map(
88✔
119
      (e, index) => new JSONElementData(this, e, index),
88✔
120
    ));
88✔
121
  }
88✔
122
}
94✔
UNCOV
123

×
UNCOV
124
/**
×
UNCOV
125
 * Build function which check that the given 2 names are in specific order.
×
UNCOV
126
 */
×
127
function buildValidatorFromType(
74✔
UNCOV
128
  order: OrderTypeOption,
×
UNCOV
129
  insensitive: boolean,
×
UNCOV
130
  natural: boolean,
×
UNCOV
131
): Validator {
×
UNCOV
132
  type Compare<T> = ([a, b]: T[]) => boolean;
×
UNCOV
133

×
UNCOV
134
  let compareValue: Compare<any> = ([a, b]) => a <= b;
✔
UNCOV
135
  let compareText: Compare<string> = compareValue;
×
UNCOV
136

×
UNCOV
137
  if (natural) {
✔
UNCOV
138
    compareText = ([a, b]) => naturalCompare(a, b) <= 0;
✔
UNCOV
139
  }
×
UNCOV
140
  if (insensitive) {
✔
UNCOV
141
    const baseCompareText = compareText;
×
142
    compareText = ([a, b]: string[]) =>
6✔
143
      baseCompareText([a.toLowerCase(), b.toLowerCase()]);
24✔
UNCOV
144
  }
×
UNCOV
145
  if (order === "desc") {
✔
UNCOV
146
    const baseCompareText = compareText;
×
UNCOV
147
    compareText = (args: string[]) => baseCompareText(args.reverse());
✔
148
    const baseCompareValue = compareValue;
×
UNCOV
149
    compareValue = (args) => baseCompareValue(args.reverse());
✔
UNCOV
150
  }
×
UNCOV
151
  return (a: JSONElementData, b: JSONElementData) => {
✔
152
    if (typeof a.value === "string" && typeof b.value === "string") {
321✔
153
      return compareText([a.value, b.value]);
278✔
UNCOV
154
    }
×
UNCOV
155
    const type = getJSONPrimitiveType(a.value);
✔
UNCOV
156
    if (type && type === getJSONPrimitiveType(b.value)) {
✔
UNCOV
157
      return compareValue([a.value, b.value]);
×
UNCOV
158
    }
×
UNCOV
159
    // Unknown
×
UNCOV
160
    return true;
✔
UNCOV
161
  };
×
UNCOV
162
}
×
UNCOV
163

×
UNCOV
164
/**
×
UNCOV
165
 * Parse options
×
UNCOV
166
 */
×
167
function parseOptions(options: UserOptions): ParsedOption[] {
90✔
168
  return options.map((opt) => {
90✔
169
    const order = opt.order;
90✔
170
    const pathPattern = new RegExp(opt.pathPattern);
90✔
UNCOV
171
    const minValues: number = opt.minValues ?? 2;
×
UNCOV
172
    if (!Array.isArray(order)) {
✔
UNCOV
173
      const type: OrderTypeOption = order.type ?? "asc";
×
UNCOV
174
      const insensitive = order.caseSensitive === false;
×
UNCOV
175
      const natural = Boolean(order.natural);
×
UNCOV
176

×
UNCOV
177
      return {
×
UNCOV
178
        isTargetArray,
×
UNCOV
179
        ignore: () => false,
✔
180
        isValidOrder: buildValidatorFromType(type, insensitive, natural),
56✔
181
        orderText(data) {
56✔
182
          if (typeof data.value === "string") {
35✔
UNCOV
183
            return `${natural ? "natural " : ""}${
✔
UNCOV
184
              insensitive ? "insensitive " : ""
✔
UNCOV
185
            }${type}ending`;
×
UNCOV
186
          }
×
UNCOV
187
          return `${type}ending`;
✔
UNCOV
188
        },
×
UNCOV
189
      };
×
UNCOV
190
    }
×
UNCOV
191
    const parsedOrder: {
✔
UNCOV
192
      test: (v: JSONElementData) => boolean;
×
UNCOV
193
      isValidNestOrder: Validator;
×
UNCOV
194
    }[] = [];
×
UNCOV
195
    for (const o of order) {
✔
UNCOV
196
      if (typeof o === "string") {
✔
UNCOV
197
        parsedOrder.push({
×
UNCOV
198
          test: (v) => v.value === o,
✔
UNCOV
199
          isValidNestOrder: () => true,
×
UNCOV
200
        });
×
UNCOV
201
      } else {
✔
UNCOV
202
        const valuePattern = o.valuePattern ? new RegExp(o.valuePattern) : null;
×
UNCOV
203
        const nestOrder = o.order ?? {};
×
204
        const type: OrderTypeOption = nestOrder.type ?? "asc";
×
205
        const insensitive = nestOrder.caseSensitive === false;
×
UNCOV
206
        const natural = Boolean(nestOrder.natural);
×
UNCOV
207
        parsedOrder.push({
×
UNCOV
208
          test: (v) =>
✔
209
            valuePattern
238!
UNCOV
210
              ? Boolean(getJSONPrimitiveType(v.value)) &&
×
UNCOV
211
                valuePattern.test(String(v.value))
×
212
              : true,
238✔
UNCOV
213
          isValidNestOrder: buildValidatorFromType(type, insensitive, natural),
×
UNCOV
214
        });
×
UNCOV
215
      }
×
UNCOV
216
    }
×
UNCOV
217

×
UNCOV
218
    return {
✔
UNCOV
219
      isTargetArray,
×
UNCOV
220
      ignore: (v) => parsedOrder.every((p) => !p.test(v)),
✔
221
      isValidOrder(a, b) {
✔
222
        for (const p of parsedOrder) {
290✔
223
          const matchA = p.test(a);
734✔
224
          const matchB = p.test(b);
734✔
225
          if (!matchA || !matchB) {
734✔
226
            if (matchA) {
642✔
227
              return true;
168✔
228
            }
168✔
229
            if (matchB) {
642✔
230
              return false;
30✔
231
            }
30✔
232
            continue;
642✔
233
          }
444✔
234
          return p.isValidNestOrder(a, b);
734✔
235
        }
92✔
236
        return false;
290!
237
      },
290✔
UNCOV
238
      orderText: () => "specified",
✔
UNCOV
239
    };
×
240

×
UNCOV
241
    /**
×
UNCOV
242
     * Checks whether given node data is verify target
×
UNCOV
243
     */
×
UNCOV
244
    function isTargetArray(data: JSONArrayData) {
×
245
      if (data.node.elements.length < minValues) {
94✔
246
        return false;
4✔
247
      }
4✔
248

94✔
249
      // Check whether the path is match or not.
94✔
250
      let path = "";
94✔
251
      let curr: AST.JSONNode = data.node;
90✔
UNCOV
252
      let p: AST.JSONNode | null = curr.parent;
×
UNCOV
253
      while (p) {
✔
UNCOV
254
        if (p.type === "JSONProperty") {
✔
UNCOV
255
          const name = getPropertyName(p);
×
UNCOV
256
          if (/^[$a-z_][\w$]*$/iu.test(name)) {
✔
UNCOV
257
            path = `.${name}${path}`;
×
UNCOV
258
          } else {
✔
UNCOV
259
            path = `[${JSON.stringify(name)}]${path}`;
×
UNCOV
260
          }
×
UNCOV
261
        } else if (p.type === "JSONArrayExpression") {
×
UNCOV
262
          const index = p.elements.indexOf(curr as never);
×
UNCOV
263
          path = `[${index}]${path}`;
×
UNCOV
264
        }
×
UNCOV
265
        curr = p;
×
UNCOV
266
        p = curr.parent;
×
UNCOV
267
      }
×
UNCOV
268
      if (path.startsWith(".")) {
✔
UNCOV
269
        path = path.slice(1);
×
UNCOV
270
      }
×
UNCOV
271
      return pathPattern.test(path);
✔
UNCOV
272
    }
×
UNCOV
273
  });
×
UNCOV
274

×
UNCOV
275
  /**
×
UNCOV
276
   * Gets the property name of the given `Property` node.
×
UNCOV
277
   */
×
UNCOV
278
  function getPropertyName(node: AST.JSONProperty): string {
×
279
    const prop = node.key;
78✔
280
    if (prop.type === "JSONIdentifier") {
78!
UNCOV
281
      return prop.name;
×
UNCOV
282
    }
×
283
    return String(getStaticJSONValue(prop));
78✔
284
  }
78✔
UNCOV
285
}
×
UNCOV
286

×
UNCOV
287
/**
×
UNCOV
288
 * Get the type name from given value when value is primitive like value
×
UNCOV
289
 */
×
290
function getJSONPrimitiveType(val: JSONValue) {
220✔
291
  const t = typeof val;
220✔
292
  if (t === "string" || t === "number" || t === "boolean" || t === "bigint") {
220✔
293
    return t;
201✔
294
  }
201✔
295
  if (val === null) {
220✔
296
    return "null";
15✔
297
  }
15✔
298
  if (val === undefined) {
220!
UNCOV
299
    return "undefined";
×
UNCOV
300
  }
×
301
  if (val instanceof RegExp) {
220!
UNCOV
302
    return "regexp";
×
UNCOV
303
  }
×
304
  return null;
220✔
305
}
220✔
UNCOV
306

×
UNCOV
307
const ALLOW_ORDER_TYPES: OrderTypeOption[] = ["asc", "desc"];
×
UNCOV
308
const ORDER_OBJECT_SCHEMA = {
×
UNCOV
309
  type: "object",
×
UNCOV
310
  properties: {
×
UNCOV
311
    type: {
×
UNCOV
312
      enum: ALLOW_ORDER_TYPES,
×
UNCOV
313
    },
×
UNCOV
314
    caseSensitive: {
×
UNCOV
315
      type: "boolean",
×
UNCOV
316
    },
×
UNCOV
317
    natural: {
×
UNCOV
318
      type: "boolean",
×
UNCOV
319
    },
×
UNCOV
320
  },
×
UNCOV
321
  additionalProperties: false,
×
UNCOV
322
} as const;
×
UNCOV
323

×
UNCOV
324
//------------------------------------------------------------------------------
×
UNCOV
325
// Rule Definition
×
UNCOV
326
//------------------------------------------------------------------------------
×
UNCOV
327

×
328
export default createRule<UserOptions>("sort-array-values", {
×
UNCOV
329
  meta: {
×
UNCOV
330
    docs: {
×
UNCOV
331
      description: "require array values to be sorted",
×
UNCOV
332
      recommended: null,
×
UNCOV
333
      extensionRule: false,
×
UNCOV
334
      layout: false,
×
UNCOV
335
    },
×
UNCOV
336
    fixable: "code",
×
UNCOV
337
    schema: {
×
UNCOV
338
      type: "array",
×
UNCOV
339
      items: {
×
UNCOV
340
        type: "object",
×
UNCOV
341
        properties: {
×
UNCOV
342
          pathPattern: { type: "string" },
×
UNCOV
343
          order: {
×
UNCOV
344
            oneOf: [
×
UNCOV
345
              {
×
UNCOV
346
                type: "array",
×
UNCOV
347
                items: {
×
UNCOV
348
                  anyOf: [
×
UNCOV
349
                    { type: "string" },
×
UNCOV
350
                    {
×
UNCOV
351
                      type: "object",
×
UNCOV
352
                      properties: {
×
UNCOV
353
                        valuePattern: {
×
UNCOV
354
                          type: "string",
×
UNCOV
355
                        },
×
UNCOV
356
                        order: ORDER_OBJECT_SCHEMA,
×
UNCOV
357
                      },
×
UNCOV
358
                      additionalProperties: false,
×
UNCOV
359
                    },
×
UNCOV
360
                  ],
×
UNCOV
361
                },
×
UNCOV
362
                uniqueItems: true,
×
UNCOV
363
              },
×
364
              ORDER_OBJECT_SCHEMA,
×
UNCOV
365
            ],
×
UNCOV
366
          },
×
UNCOV
367
          minValues: {
×
UNCOV
368
            type: "integer",
×
369
            minimum: 2,
×
UNCOV
370
          },
×
UNCOV
371
        },
×
UNCOV
372
        required: ["pathPattern", "order"],
×
UNCOV
373
        additionalProperties: false,
×
UNCOV
374
      },
×
UNCOV
375
      minItems: 1,
×
UNCOV
376
    },
×
UNCOV
377

×
UNCOV
378
    messages: {
×
UNCOV
379
      shouldBeBefore:
×
UNCOV
380
        "Expected array values to be in {{orderText}} order. '{{thisValue}}' should be before '{{targetValue}}'.",
×
UNCOV
381
      shouldBeAfter:
×
UNCOV
382
        "Expected array values to be in {{orderText}} order. '{{thisValue}}' should be after '{{targetValue}}'.",
×
UNCOV
383
    },
×
UNCOV
384
    type: "suggestion",
×
UNCOV
385
  },
×
386
  create(context) {
✔
387
    const sourceCode = context.sourceCode;
90✔
388
    if (!sourceCode.parserServices.isJSON) {
90!
UNCOV
389
      return {};
×
UNCOV
390
    }
×
391
    // Parse options.
90✔
392
    const parsedOptions = parseOptions(context.options);
90✔
393

90✔
394
    /**
90✔
395
     * Sort elements by bubble sort.
90✔
396
     */
90✔
397
    function bubbleSort(elements: JSONElementData[], option: ParsedOption) {
90✔
398
      const l = elements.length;
88✔
399
      const result = [...elements];
88✔
400
      let swapped: boolean;
88✔
401
      do {
88✔
402
        swapped = false;
167✔
403
        for (let nextIndex = 1; nextIndex < l; nextIndex++) {
167✔
404
          const prevIndex = nextIndex - 1;
519✔
405
          if (option.isValidOrder(result[prevIndex], result[nextIndex]))
519✔
406
            continue;
519✔
407
          [result[prevIndex], result[nextIndex]] = [
519✔
408
            result[nextIndex],
107✔
409
            result[prevIndex],
107✔
410
          ];
107✔
411
          swapped = true;
107✔
412
        }
107✔
413
      } while (swapped);
88✔
414
      return result;
88✔
415
    }
88✔
416

90✔
417
    /**
90✔
418
     * Verify for array elements
90✔
419
     */
90✔
420
    function verifyArrayElements(
90✔
421
      elements: JSONElementData[],
88✔
422
      option: ParsedOption,
88✔
423
    ) {
88✔
424
      const sorted = bubbleSort(elements, option);
88✔
425
      const editScript = calcShortestEditScript(elements, sorted);
88✔
426
      for (let index = 0; index < editScript.length; index++) {
88✔
427
        const edit = editScript[index];
415✔
428
        if (edit.type !== "delete") continue;
415✔
429
        const insertEditIndex = editScript.findIndex(
415✔
430
          (e) => e.type === "insert" && e.b === edit.a,
69✔
431
        );
69✔
432
        if (insertEditIndex === -1) {
415!
433
          // should not happen
×
434
          continue;
×
435
        }
×
436
        if (index < insertEditIndex) {
415✔
437
          const target = findInsertAfterTarget(edit.a, insertEditIndex);
51✔
438
          if (!target) {
51!
UNCOV
439
            // should not happen
×
440
            continue;
×
UNCOV
441
          }
×
442
          context.report({
51✔
443
            loc: edit.a.reportLoc,
51✔
444
            messageId: "shouldBeAfter",
51✔
445
            data: {
51✔
446
              thisValue: toText(edit.a),
51✔
447
              targetValue: toText(target),
51✔
448
              orderText: option.orderText(edit.a),
51✔
449
            },
51✔
450
            *fix(fixer) {
51✔
451
              yield* fixToMoveDownForSorting(
51✔
452
                fixer,
51✔
453
                sourceCode,
51✔
454
                edit.a.around,
51✔
455
                target.around,
51✔
456
              );
51✔
457
            },
51✔
458
          });
51✔
459
        } else {
415✔
460
          const target = findInsertBeforeTarget(edit.a, insertEditIndex);
18✔
461
          if (!target) {
18!
UNCOV
462
            // should not happen
×
UNCOV
463
            continue;
×
UNCOV
464
          }
×
465
          context.report({
18✔
466
            loc: edit.a.reportLoc,
18✔
467
            messageId: "shouldBeBefore",
18✔
468
            data: {
18✔
469
              thisValue: toText(edit.a),
18✔
470
              targetValue: toText(target),
18✔
471
              orderText: option.orderText(edit.a),
18✔
472
            },
18✔
473
            *fix(fixer) {
18✔
474
              yield* fixToMoveUpForSorting(
18✔
475
                fixer,
18✔
476
                sourceCode,
18✔
477
                edit.a.around,
18✔
478
                target.around,
18✔
479
              );
18✔
480
            },
18✔
481
          });
18✔
482
        }
18✔
483
      }
415✔
484

415✔
485
      /**
415✔
486
       * Find insert after target
415✔
487
       */
415✔
488
      function findInsertAfterTarget(
415✔
489
        element: JSONElementData,
51✔
490
        insertEditIndex: number,
51✔
491
      ) {
51✔
492
        for (let index = insertEditIndex - 1; index >= 0; index--) {
51✔
493
          const edit = editScript[index];
65✔
494
          if (edit.type === "delete" && edit.a === element) break;
65!
495
          if (edit.type !== "common") continue;
65✔
496
          return edit.a;
65✔
497
        }
51✔
498

51✔
499
        let lastTarget: JSONElementData | null = null;
51!
UNCOV
500
        for (
×
UNCOV
501
          let index = elements.indexOf(element) + 1;
×
UNCOV
502
          index < elements.length;
×
UNCOV
503
          index++
×
UNCOV
504
        ) {
×
UNCOV
505
          const el = elements[index];
×
UNCOV
506
          if (option.isValidOrder(el, element)) {
×
UNCOV
507
            lastTarget = el;
×
UNCOV
508
            continue;
×
UNCOV
509
          }
×
UNCOV
510
          return lastTarget;
×
UNCOV
511
        }
×
UNCOV
512
        return lastTarget;
×
513
      }
51✔
514

415✔
515
      /**
415✔
516
       * Find insert before target
415✔
517
       */
415✔
518
      function findInsertBeforeTarget(
415✔
519
        element: JSONElementData,
18✔
520
        insertEditIndex: number,
18✔
521
      ) {
18✔
522
        for (
18✔
523
          let index = insertEditIndex + 1;
18✔
524
          index < editScript.length;
18✔
525
          index++
18✔
526
        ) {
18✔
527
          const edit = editScript[index];
18✔
528
          if (edit.type === "delete" && edit.a === element) break;
18!
529
          if (edit.type !== "common") continue;
18!
530
          return edit.a;
18✔
531
        }
18✔
532

18✔
533
        let lastTarget: JSONElementData | null = null;
18!
UNCOV
534
        for (let index = elements.indexOf(element) - 1; index >= 0; index--) {
×
UNCOV
535
          const el = elements[index];
×
UNCOV
536
          if (option.isValidOrder(element, el)) {
×
UNCOV
537
            lastTarget = el;
×
UNCOV
538
            continue;
×
UNCOV
539
          }
×
UNCOV
540
          return lastTarget;
×
UNCOV
541
        }
×
UNCOV
542
        return lastTarget;
×
UNCOV
543
      }
×
UNCOV
544
    }
×
UNCOV
545

×
UNCOV
546
    /**
×
UNCOV
547
     * Convert to display text.
×
UNCOV
548
     */
×
UNCOV
549
    function toText(data: JSONElementData) {
✔
550
      if (getJSONPrimitiveType(data.value)) {
138✔
551
        return String(data.value);
138✔
552
      }
138✔
553
      return sourceCode.getText(data.node! as never);
138!
554
    }
138✔
555

90✔
556
    return {
90✔
557
      JSONArrayExpression(node) {
90✔
558
        const data = new JSONArrayData(node, sourceCode);
94✔
559
        const option = parsedOptions.find((o) => o.isTargetArray(data));
94✔
560
        if (!option) {
94✔
561
          return;
6✔
562
        }
6✔
563
        verifyArrayElements(
94✔
564
          data.elements.filter((d) => !option.ignore(d)),
88✔
565
          option,
88✔
566
        );
88✔
567
      },
94✔
568
    };
90✔
569
  },
90✔
570
});
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