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

ota-meshi / eslint-plugin-jsonc / 22186324748

19 Feb 2026 02:40PM UTC coverage: 71.032% (-2.3%) from 73.311%
22186324748

push

github

web-flow
Add ESLint language plugin support to eslint-plugin-jsonc (#471)

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: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Yosuke Ota <otameshiyo23@gmail.com>

1029 of 1276 branches covered (80.64%)

Branch coverage included in aggregate %.

580 of 1177 new or added lines in 10 files covered. (49.28%)

2 existing lines in 1 file now uncovered.

7448 of 10658 relevant lines covered (69.88%)

77.87 hits per line

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

44.7
/lib/language/jsonc-source-code.ts
1
/**
1✔
2
 * @fileoverview The JSONCSourceCode class.
1✔
3
 */
1✔
4

1✔
5
import { traverseNodes, VisitorKeys } from "jsonc-eslint-parser";
1✔
6
import type { AST } from "jsonc-eslint-parser";
1✔
7
import type {
1✔
8
  TraversalStep,
1✔
9
  IDirective as Directive,
1✔
10
} from "@eslint/plugin-kit";
1✔
11
import {
1✔
12
  TextSourceCodeBase,
1✔
13
  CallMethodStep,
1✔
14
  VisitNodeStep,
1✔
15
  ConfigCommentParser,
1✔
16
  Directive as DirectiveImpl,
1✔
17
} from "@eslint/plugin-kit";
1✔
18
import type { DirectiveType, FileProblem, RulesConfig } from "@eslint/core";
1✔
19
import {
1✔
20
  TokenStore,
1✔
21
  type CursorWithSkipOptionsWithoutFilter,
1✔
22
  type CursorWithSkipOptionsWithFilter,
1✔
23
  type CursorWithSkipOptionsWithComment,
1✔
24
  type CursorWithCountOptionsWithoutFilter,
1✔
25
  type CursorWithCountOptionsWithFilter,
1✔
26
  type CursorWithCountOptionsWithComment,
1✔
27
} from "@ota-meshi/ast-token-store";
1✔
28
import type { AST as ESLintAST } from "eslint";
1✔
29
import type { Scope } from "eslint";
1✔
30
import type { Comment } from "estree";
1✔
31

1✔
32
//-----------------------------------------------------------------------------
1✔
33
// Helpers
1✔
34
//-----------------------------------------------------------------------------
1✔
35

1✔
36
const commentParser = new ConfigCommentParser();
1✔
37

1✔
38
/**
1✔
39
 * Pattern to match ESLint inline configuration comments in JSONC.
1✔
40
 * Matches: eslint, eslint-disable, eslint-enable, eslint-disable-line, eslint-disable-next-line
1✔
41
 */
1✔
42
const INLINE_CONFIG =
1✔
43
  /^\s*eslint(?:-enable|-disable(?:(?:-next)?-line)?)?(?:\s|$)/u;
1✔
44

1✔
45
//-----------------------------------------------------------------------------
1✔
46
// Types
1✔
47
//-----------------------------------------------------------------------------
1✔
48

1✔
49
/**
1✔
50
 * A comment token with required range and loc.
1✔
51
 */
1✔
52
export type JSONCComment = Comment & {
1✔
53
  range: [number, number];
1✔
54
  loc: AST.SourceLocation;
1✔
55
};
1✔
56

1✔
57
/**
1✔
58
 * JSONC-specific syntax element type
1✔
59
 */
1✔
60
export type JSONCSyntaxElement = AST.JSONNode | ESLintAST.Token | JSONCComment;
1✔
61
export type JSONCToken = ESLintAST.Token | JSONCComment;
1✔
62

1✔
63
/**
1✔
64
 * JSONC Source Code Object
1✔
65
 */
1✔
66
export class JSONCSourceCode extends TextSourceCodeBase<{
1✔
67
  LangOptions: Record<never, never>;
1✔
68
  RootNode: AST.JSONProgram;
1✔
69
  SyntaxElementWithLoc: JSONCSyntaxElement;
1✔
70
  ConfigNode: JSONCComment;
1✔
71
}> {
1✔
72
  public readonly hasBOM: boolean;
1,044✔
73

1,044✔
74
  public readonly parserServices: { isJSON?: boolean; parseError?: unknown };
1,044✔
75

1,044✔
76
  public readonly visitorKeys: Record<string, string[]>;
1,044✔
77

1,044✔
78
  private readonly tokenStore: TokenStore<
1,044✔
79
    AST.JSONNode,
1,044✔
80
    ESLintAST.Token,
1,044✔
81
    JSONCComment
1,044✔
82
  >;
1,044✔
83

1,044✔
84
  #steps: TraversalStep[] | null = null;
1,044✔
85

1,044✔
86
  #cacheTokensAndComments: (ESLintAST.Token | JSONCComment)[] | null = null;
1,044✔
87

1,044✔
88
  #inlineConfigComments: JSONCComment[] | null = null;
1,044✔
89

1,044✔
90
  /**
1,044✔
91
   * Creates a new instance.
1,044✔
92
   */
1,044✔
93
  public constructor(config: {
1,044✔
NEW
94
    text: string;
×
NEW
95
    ast: AST.JSONProgram;
×
NEW
96
    hasBOM: boolean;
×
NEW
97
    parserServices: { isJSON: boolean; parseError?: unknown };
×
NEW
98
    visitorKeys?: Record<string, string[]> | null | undefined;
×
NEW
99
  }) {
×
NEW
100
    super({
×
NEW
101
      ast: config.ast,
×
NEW
102
      text: config.text,
×
NEW
103
    });
×
NEW
104
    this.hasBOM = Boolean(config.hasBOM);
×
NEW
105
    this.parserServices = config.parserServices;
×
NEW
106
    this.visitorKeys = config.visitorKeys || VisitorKeys;
×
NEW
107
    this.tokenStore = new TokenStore<
×
NEW
108
      AST.JSONNode,
×
NEW
109
      ESLintAST.Token,
×
NEW
110
      JSONCComment
×
NEW
111
    >({
×
NEW
112
      tokens: [
×
NEW
113
        ...(config.ast.tokens as (ESLintAST.Token | JSONCComment)[]),
×
114
        ...(config.ast.comments as JSONCComment[]),
1,044✔
NEW
115
      ],
×
NEW
116
      isComment: (token): token is JSONCComment =>
✔
117
        token.type === "Block" || token.type === "Line",
3,972✔
NEW
118
    });
×
NEW
119
  }
×
NEW
120

×
NEW
121
  public traverse(): Iterable<TraversalStep> {
✔
122
    if (this.#steps != null) {
1,021!
NEW
123
      return this.#steps;
×
NEW
124
    }
×
125

1,021✔
126
    const steps: (VisitNodeStep | CallMethodStep)[] = [];
1,021✔
127
    this.#steps = steps;
1,021✔
128

1,021✔
129
    const root = this.ast;
1,021✔
130
    steps.push(
1,021✔
NEW
131
      // ESLint core rule compatibility: onCodePathStart is called with two arguments.
×
NEW
132
      new CallMethodStep({
×
NEW
133
        target: "onCodePathStart",
×
NEW
134
        args: [{}, root],
×
NEW
135
      }),
×
NEW
136
    );
×
NEW
137

×
NEW
138
    traverseNodes(root, {
×
NEW
139
      enterNode(n) {
✔
140
        steps.push(
11,368✔
141
          new VisitNodeStep({
11,368✔
142
            target: n,
11,368✔
143
            phase: 1,
11,368✔
NEW
144
            args: [n],
×
NEW
145
          }),
×
NEW
146
        );
×
NEW
147
      },
×
NEW
148
      leaveNode(n) {
✔
149
        steps.push(
11,368✔
150
          new VisitNodeStep({
11,368✔
151
            target: n,
11,368✔
152
            phase: 2,
11,368✔
153
            args: [n],
11,368✔
154
          }),
11,368✔
155
        );
11,368✔
156
      },
11,368✔
NEW
157
    });
×
NEW
158

×
NEW
159
    steps.push(
×
NEW
160
      // ESLint core rule compatibility: onCodePathEnd is called with two arguments.
×
NEW
161
      new CallMethodStep({
×
NEW
162
        target: "onCodePathEnd",
×
NEW
163
        args: [{}, root],
×
NEW
164
      }),
×
NEW
165
    );
×
NEW
166
    return steps;
×
NEW
167
  }
×
NEW
168

×
NEW
169
  /**
×
NEW
170
   * Gets all tokens and comments.
×
NEW
171
   */
×
NEW
172
  public get tokensAndComments(): JSONCToken[] {
✔
173
    return (this.#cacheTokensAndComments ??= [
26✔
NEW
174
      ...this.ast.tokens,
×
NEW
175
      ...(this.ast.comments as JSONCComment[]),
×
NEW
176
    ].sort((a, b) => a.range[0] - b.range[0]));
✔
NEW
177
  }
×
NEW
178

×
NEW
179
  public getLines(): string[] {
✔
180
    return this.lines;
2✔
181
  }
2✔
NEW
182

×
NEW
183
  public getAllComments(): JSONCComment[] {
✔
184
    return this.tokenStore.getAllComments();
63✔
185
  }
63✔
NEW
186

×
NEW
187
  /**
×
NEW
188
   * Returns an array of all inline configuration nodes found in the source code.
×
NEW
189
   * This includes eslint-disable, eslint-enable, eslint-disable-line,
×
NEW
190
   * eslint-disable-next-line, and eslint (for inline config) comments.
×
NEW
191
   */
×
NEW
192
  public getInlineConfigNodes(): JSONCComment[] {
✔
193
    if (!this.#inlineConfigComments) {
2,042✔
194
      this.#inlineConfigComments = (this.ast.comments as JSONCComment[]).filter(
1,021✔
195
        (comment) => INLINE_CONFIG.test(comment.value),
1,021✔
196
      );
1,021✔
197
    }
1,021✔
198

2,042✔
199
    return this.#inlineConfigComments;
2,042✔
200
  }
2,042✔
201

1,044✔
202
  /**
1,044✔
203
   * Returns directives that enable or disable rules along with any problems
1,044✔
204
   * encountered while parsing the directives.
1,044✔
205
   */
1,044✔
206
  public getDisableDirectives(): {
1,044✔
207
    directives: Directive[];
1,021✔
208
    problems: FileProblem[];
1,021✔
209
  } {
1,021✔
210
    const problems: FileProblem[] = [];
1,021✔
211
    const directives: Directive[] = [];
1,021✔
212

1,021✔
213
    this.getInlineConfigNodes().forEach((comment) => {
1,021✔
214
      const directive = commentParser.parseDirective(comment.value);
10✔
215

10✔
216
      if (!directive) {
10!
NEW
217
        return;
×
NEW
218
      }
×
219

10✔
220
      const { label, value, justification } = directive;
10✔
221

10✔
222
      // `eslint-disable-line` directives are not allowed to span multiple lines
10✔
223
      // as it would be confusing to which lines they apply
10✔
224
      if (
10✔
225
        label === "eslint-disable-line" &&
10✔
226
        comment.loc.start.line !== comment.loc.end.line
2✔
227
      ) {
10!
NEW
228
        const message = `${label} comment should not span multiple lines.`;
×
NEW
229

×
NEW
230
        problems.push({
×
NEW
231
          ruleId: null,
×
NEW
232
          message,
×
NEW
233
          loc: comment.loc,
×
NEW
234
        });
×
NEW
235
        return;
×
NEW
236
      }
×
237

10✔
238
      switch (label) {
10✔
239
        case "eslint-disable":
10✔
240
        case "eslint-enable":
3✔
241
        case "eslint-disable-next-line":
10✔
242
        case "eslint-disable-line": {
10✔
243
          const directiveType = label.slice("eslint-".length);
8✔
244

8✔
245
          directives.push(
8✔
246
            new DirectiveImpl({
8✔
247
              type: directiveType as DirectiveType,
8✔
248
              node: comment,
8✔
249
              value,
8✔
250
              justification,
8✔
251
            }),
8✔
252
          );
8✔
253
          break;
8✔
254
        }
8✔
255
        // no default
10✔
256
      }
10✔
257
    });
1,021✔
258

1,021✔
259
    return { problems, directives };
1,021✔
260
  }
1,021✔
261

1,044✔
262
  /**
1,044✔
263
   * Returns inline rule configurations along with any problems
1,044✔
264
   * encountered while parsing the configurations.
1,044✔
265
   */
1,044✔
266
  public applyInlineConfig(): {
1,044✔
267
    configs: { config: { rules: RulesConfig }; loc: AST.SourceLocation }[];
1,021✔
268
    problems: FileProblem[];
1,021✔
269
  } {
1,021✔
270
    const problems: FileProblem[] = [];
1,021✔
271
    const configs: {
1,021✔
272
      config: { rules: RulesConfig };
1,021✔
273
      loc: AST.SourceLocation;
1,021✔
274
    }[] = [];
1,021✔
275

1,021✔
276
    this.getInlineConfigNodes().forEach((comment) => {
1,021✔
277
      const directive = commentParser.parseDirective(comment.value);
10✔
278

10✔
279
      if (!directive) {
10!
NEW
280
        return;
×
NEW
281
      }
×
282

10✔
283
      const { label, value } = directive;
10✔
284

10✔
285
      if (label === "eslint") {
10✔
286
        const parseResult = commentParser.parseJSONLikeConfig(value);
2✔
NEW
287

×
NEW
288
        if (parseResult.ok) {
✔
NEW
289
          configs.push({
×
NEW
290
            config: {
×
NEW
291
              rules: parseResult.config,
×
NEW
292
            },
×
NEW
293
            loc: comment.loc,
×
NEW
294
          });
×
NEW
295
        } else {
×
NEW
296
          problems.push({
×
NEW
297
            ruleId: null,
×
NEW
298
            message: parseResult.error.message,
×
NEW
299
            loc: comment.loc,
×
NEW
300
          });
×
NEW
301
        }
×
NEW
302
      }
×
NEW
303
    });
×
NEW
304

×
NEW
305
    return { configs, problems };
×
NEW
306
  }
×
NEW
307

×
NEW
308
  /**
×
NEW
309
   * Gets the source text for the given node or the entire source if no node is provided.
×
NEW
310
   */
×
NEW
311
  public getText(
✔
312
    node?: JSONCSyntaxElement,
71✔
313
    beforeCount?: number,
71✔
314
    afterCount?: number,
71✔
315
  ): string {
71✔
316
    if (!node) return this.text;
71✔
317
    const range = (node as { range: [number, number] }).range;
71✔
318
    const start = range[0] - (beforeCount ?? 0);
71✔
319
    const end = range[1] + (afterCount ?? 0);
71✔
320
    return this.text.slice(Math.max(0, start), Math.min(this.text.length, end));
71✔
321
  }
71✔
NEW
322

×
NEW
323
  public getNodeByRangeIndex(index: number): AST.JSONNode | null {
✔
324
    let node = find([this.ast]);
95✔
325
    if (!node) return null;
95✔
326
    while (true) {
95✔
327
      const child = find(this._getChildren(node));
493✔
328
      if (!child) return node;
493✔
329
      node = child;
493✔
330
    }
399✔
331

95✔
332
    /**
95✔
333
     * Finds a node that contains the given index.
95✔
334
     */
95✔
335
    function find(nodes: AST.JSONNode[]) {
95!
336
      for (const node of nodes) {
588✔
337
        if (node.range[0] <= index && index < node.range[1]) {
713✔
338
          return node;
493✔
339
        }
493✔
340
      }
713✔
341
      return null;
588✔
342
    }
588✔
343
  }
95✔
NEW
344

×
NEW
345
  /**
×
NEW
346
   * Gets the first token of the given node.
×
NEW
347
   */
×
NEW
348
  public getFirstToken(node: JSONCSyntaxElement): ESLintAST.Token;
×
NEW
349

×
NEW
350
  /**
×
NEW
351
   * Gets the first token of the given node with options.
×
NEW
352
   */
×
NEW
353
  public getFirstToken(
×
NEW
354
    node: JSONCSyntaxElement,
×
NEW
355
    options: CursorWithSkipOptionsWithoutFilter,
×
NEW
356
  ): ESLintAST.Token | null;
×
NEW
357

×
NEW
358
  /**
×
NEW
359
   * Gets the first token of the given node with filter options.
×
NEW
360
   */
×
NEW
361
  public getFirstToken<R extends ESLintAST.Token>(
×
NEW
362
    node: JSONCSyntaxElement,
×
NEW
363
    options: CursorWithSkipOptionsWithFilter<ESLintAST.Token, R>,
×
NEW
364
  ): R | null;
×
NEW
365

×
NEW
366
  /**
×
NEW
367
   * Gets the first token of the given node with comment options.
×
NEW
368
   */
×
NEW
369
  public getFirstToken<R extends ESLintAST.Token | JSONCComment>(
×
NEW
370
    node: JSONCSyntaxElement,
×
NEW
371
    options: CursorWithSkipOptionsWithComment<ESLintAST.Token, JSONCComment, R>,
×
NEW
372
  ): R | null;
×
NEW
373

×
NEW
374
  public getFirstToken(
✔
375
    node: JSONCSyntaxElement,
788✔
376
    options?:
788✔
377
      | CursorWithSkipOptionsWithoutFilter
788✔
378
      | CursorWithSkipOptionsWithFilter<ESLintAST.Token>
788✔
379
      | CursorWithSkipOptionsWithComment<ESLintAST.Token, JSONCComment>,
788✔
380
  ): ESLintAST.Token | JSONCComment | null {
788✔
381
    return this.tokenStore.getFirstToken(node as never, options as never);
788✔
382
  }
788✔
NEW
383

×
NEW
384
  /**
×
NEW
385
   * Gets the first tokens of the given node.
×
NEW
386
   */
×
NEW
387
  public getFirstTokens(
×
NEW
388
    node: JSONCSyntaxElement,
×
NEW
389
    options?: CursorWithCountOptionsWithoutFilter,
×
NEW
390
  ): ESLintAST.Token[];
×
NEW
391

×
NEW
392
  /**
×
NEW
393
   * Gets the first tokens of the given node with filter options.
×
NEW
394
   */
×
NEW
395
  public getFirstTokens<R extends ESLintAST.Token>(
×
NEW
396
    node: JSONCSyntaxElement,
×
NEW
397
    options: CursorWithCountOptionsWithFilter<ESLintAST.Token, R>,
×
NEW
398
  ): R[];
×
NEW
399

×
NEW
400
  /**
×
NEW
401
   * Gets the first tokens of the given node with comment options.
×
NEW
402
   */
×
NEW
403
  public getFirstTokens<R extends ESLintAST.Token | JSONCComment>(
×
NEW
404
    node: JSONCSyntaxElement,
×
NEW
405
    options: CursorWithCountOptionsWithComment<
×
NEW
406
      ESLintAST.Token,
×
NEW
407
      JSONCComment,
×
NEW
408
      R
×
NEW
409
    >,
×
NEW
410
  ): R[];
×
NEW
411

×
NEW
412
  public getFirstTokens(
✔
413
    node: JSONCSyntaxElement,
12✔
414
    options?:
12✔
415
      | CursorWithCountOptionsWithoutFilter
12✔
416
      | CursorWithCountOptionsWithFilter<ESLintAST.Token>
12✔
417
      | CursorWithCountOptionsWithComment<ESLintAST.Token, JSONCComment>,
12✔
418
  ): (ESLintAST.Token | JSONCComment)[] {
12✔
419
    return this.tokenStore.getFirstTokens(node as never, options as never);
12✔
420
  }
12✔
NEW
421

×
NEW
422
  /**
×
NEW
423
   * Gets the last token of the given node.
×
NEW
424
   */
×
NEW
425
  public getLastToken(node: JSONCSyntaxElement): ESLintAST.Token;
×
NEW
426

×
NEW
427
  /**
×
NEW
428
   * Gets the last token of the given node with options.
×
NEW
429
   */
×
NEW
430
  public getLastToken(
×
NEW
431
    node: JSONCSyntaxElement,
×
NEW
432
    options: CursorWithSkipOptionsWithoutFilter,
×
NEW
433
  ): ESLintAST.Token | null;
×
NEW
434

×
NEW
435
  /**
×
NEW
436
   * Gets the last token of the given node with filter options.
×
NEW
437
   */
×
NEW
438
  public getLastToken<R extends ESLintAST.Token>(
×
NEW
439
    node: JSONCSyntaxElement,
×
NEW
440
    options: CursorWithSkipOptionsWithFilter<ESLintAST.Token, R>,
×
NEW
441
  ): R | null;
×
NEW
442

×
NEW
443
  /**
×
NEW
444
   * Gets the last token of the given node with comment options.
×
NEW
445
   */
×
NEW
446
  public getLastToken<R extends ESLintAST.Token | JSONCComment>(
×
NEW
447
    node: JSONCSyntaxElement,
×
NEW
448
    options: CursorWithSkipOptionsWithComment<ESLintAST.Token, JSONCComment, R>,
×
NEW
449
  ): R | null;
×
NEW
450

×
NEW
451
  public getLastToken(
✔
452
    node: JSONCSyntaxElement,
600✔
453
    options?:
600✔
454
      | CursorWithSkipOptionsWithoutFilter
600✔
455
      | CursorWithSkipOptionsWithFilter<ESLintAST.Token>
600✔
456
      | CursorWithSkipOptionsWithComment<ESLintAST.Token, JSONCComment>,
600✔
457
  ): (ESLintAST.Token | JSONCComment) | null {
600✔
458
    return this.tokenStore.getLastToken(node as never, options as never);
600✔
459
  }
600✔
NEW
460

×
NEW
461
  /**
×
NEW
462
   * Get the last tokens of the given node.
×
NEW
463
   */
×
NEW
464
  public getLastTokens(
×
NEW
465
    node: JSONCSyntaxElement,
×
NEW
466
    options?: CursorWithCountOptionsWithoutFilter,
×
NEW
467
  ): ESLintAST.Token[];
×
NEW
468

×
NEW
469
  /**
×
NEW
470
   * Get the last tokens of the given node with filter options.
×
NEW
471
   */
×
NEW
472
  public getLastTokens<R extends ESLintAST.Token>(
×
NEW
473
    node: JSONCSyntaxElement,
×
NEW
474
    options: CursorWithCountOptionsWithFilter<ESLintAST.Token, R>,
×
NEW
475
  ): R[];
×
NEW
476

×
NEW
477
  /**
×
NEW
478
   * Get the last tokens of the given node with comment options.
×
NEW
479
   */
×
NEW
480
  public getLastTokens<R extends ESLintAST.Token | JSONCComment>(
×
NEW
481
    node: JSONCSyntaxElement,
×
NEW
482
    options: CursorWithCountOptionsWithComment<
×
NEW
483
      ESLintAST.Token,
×
NEW
484
      JSONCComment,
×
NEW
485
      R
×
NEW
486
    >,
×
NEW
487
  ): R[];
×
NEW
488

×
NEW
489
  public getLastTokens(
×
NEW
490
    node: JSONCSyntaxElement,
×
NEW
491
    options?:
×
NEW
492
      | CursorWithCountOptionsWithoutFilter
×
NEW
493
      | CursorWithCountOptionsWithFilter<ESLintAST.Token>
×
NEW
494
      | CursorWithCountOptionsWithComment<ESLintAST.Token, JSONCComment>,
×
NEW
495
  ): (ESLintAST.Token | JSONCComment)[] {
×
NEW
496
    return this.tokenStore.getLastTokens(node as never, options as never);
×
NEW
497
  }
×
NEW
498

×
NEW
499
  /**
×
NEW
500
   * Gets the token that precedes a given node or token.
×
NEW
501
   */
×
NEW
502
  public getTokenBefore(
×
NEW
503
    node: JSONCSyntaxElement,
×
NEW
504
    options?: CursorWithSkipOptionsWithoutFilter,
×
NEW
505
  ): ESLintAST.Token | null;
×
NEW
506

×
NEW
507
  /**
×
NEW
508
   * Gets the token that precedes a given node or token with filter options.
×
NEW
509
   */
×
NEW
510
  public getTokenBefore<R extends ESLintAST.Token>(
×
NEW
511
    node: JSONCSyntaxElement,
×
NEW
512
    options: CursorWithSkipOptionsWithFilter<ESLintAST.Token, R>,
×
NEW
513
  ): R | null;
×
NEW
514

×
NEW
515
  /**
×
NEW
516
   * Gets the token that precedes a given node or token with comment options.
×
NEW
517
   */
×
NEW
518
  public getTokenBefore<R extends ESLintAST.Token | JSONCComment>(
×
NEW
519
    node: JSONCSyntaxElement,
×
NEW
520
    options: CursorWithSkipOptionsWithComment<ESLintAST.Token, JSONCComment, R>,
×
NEW
521
  ): R | null;
×
NEW
522

×
NEW
523
  public getTokenBefore(
✔
524
    node: JSONCSyntaxElement,
837✔
525
    options?:
837✔
526
      | CursorWithSkipOptionsWithoutFilter
837✔
527
      | CursorWithSkipOptionsWithFilter<ESLintAST.Token>
837✔
528
      | CursorWithSkipOptionsWithComment<ESLintAST.Token, JSONCComment>,
837✔
529
  ): ESLintAST.Token | JSONCComment | null {
837✔
530
    return this.tokenStore.getTokenBefore(node as never, options as never);
837✔
531
  }
837✔
NEW
532

×
NEW
533
  /**
×
NEW
534
   * Gets the `count` tokens that precedes a given node or token.
×
NEW
535
   */
×
NEW
536
  public getTokensBefore(
×
NEW
537
    node: JSONCSyntaxElement,
×
NEW
538
    options?: CursorWithCountOptionsWithoutFilter,
×
NEW
539
  ): ESLintAST.Token[];
×
NEW
540

×
NEW
541
  /**
×
NEW
542
   * Gets the `count` tokens that precedes a given node or token with filter options.
×
NEW
543
   */
×
NEW
544
  public getTokensBefore<R extends ESLintAST.Token>(
×
NEW
545
    node: JSONCSyntaxElement,
×
NEW
546
    options: CursorWithCountOptionsWithFilter<ESLintAST.Token, R>,
×
NEW
547
  ): R[];
×
NEW
548

×
NEW
549
  /**
×
NEW
550
   * Gets the `count` tokens that precedes a given node or token with comment options.
×
NEW
551
   */
×
NEW
552
  public getTokensBefore<R extends ESLintAST.Token | JSONCComment>(
×
NEW
553
    node: JSONCSyntaxElement,
×
NEW
554
    options: CursorWithCountOptionsWithComment<
×
NEW
555
      ESLintAST.Token,
×
NEW
556
      JSONCComment,
×
NEW
557
      R
×
NEW
558
    >,
×
NEW
559
  ): R[];
×
NEW
560

×
NEW
561
  public getTokensBefore(
×
NEW
562
    node: JSONCSyntaxElement,
×
NEW
563
    options?:
×
NEW
564
      | CursorWithCountOptionsWithoutFilter
×
NEW
565
      | CursorWithCountOptionsWithFilter<ESLintAST.Token>
×
NEW
566
      | CursorWithCountOptionsWithComment<ESLintAST.Token, JSONCComment>,
×
NEW
567
  ): (ESLintAST.Token | JSONCComment)[] {
×
NEW
568
    return this.tokenStore.getTokensBefore(node as never, options as never);
×
NEW
569
  }
×
NEW
570

×
NEW
571
  /**
×
NEW
572
   * Gets the token that follows a given node or token.
×
NEW
573
   */
×
NEW
574
  public getTokenAfter(
×
NEW
575
    node: JSONCSyntaxElement,
×
NEW
576
    options?: CursorWithSkipOptionsWithoutFilter,
×
NEW
577
  ): ESLintAST.Token | null;
×
NEW
578

×
NEW
579
  /**
×
NEW
580
   * Gets the token that follows a given node or token with filter options.
×
NEW
581
   */
×
NEW
582
  public getTokenAfter<R extends ESLintAST.Token>(
×
NEW
583
    node: JSONCSyntaxElement,
×
NEW
584
    options: CursorWithSkipOptionsWithFilter<ESLintAST.Token, R>,
×
NEW
585
  ): R | null;
×
NEW
586

×
NEW
587
  /**
×
NEW
588
   * Gets the token that follows a given node or token with comment options.
×
NEW
589
   */
×
NEW
590
  public getTokenAfter<R extends ESLintAST.Token | JSONCComment>(
×
NEW
591
    node: JSONCSyntaxElement,
×
NEW
592
    options: CursorWithSkipOptionsWithComment<ESLintAST.Token, JSONCComment, R>,
×
NEW
593
  ): R | null;
×
NEW
594

×
NEW
595
  public getTokenAfter(
✔
596
    node: JSONCSyntaxElement,
1,448✔
597
    options?:
1,448✔
598
      | CursorWithSkipOptionsWithoutFilter
1,448✔
599
      | CursorWithSkipOptionsWithFilter<ESLintAST.Token>
1,448✔
600
      | CursorWithSkipOptionsWithComment<ESLintAST.Token, JSONCComment>,
1,448✔
601
  ): ESLintAST.Token | JSONCComment | null {
1,448✔
602
    return this.tokenStore.getTokenAfter(node as never, options as never);
1,448✔
603
  }
1,448✔
604

1,044✔
605
  /**
1,044✔
606
   * Gets the `count` tokens that follows a given node or token.
1,044✔
607
   */
1,044✔
608
  public getTokensAfter(
1,044✔
609
    node: JSONCSyntaxElement,
1,044✔
610
    options?: CursorWithCountOptionsWithoutFilter,
1,044✔
611
  ): ESLintAST.Token[];
1,044✔
612

1,044✔
613
  /**
1,044✔
614
   * Gets the `count` tokens that follows a given node or token with filter options.
1,044✔
615
   */
1,044✔
616
  public getTokensAfter<R extends ESLintAST.Token>(
1,044✔
617
    node: JSONCSyntaxElement,
1,044✔
618
    options: CursorWithCountOptionsWithFilter<ESLintAST.Token, R>,
1,044✔
619
  ): R[];
1,044✔
620

1,044✔
621
  /**
1,044✔
622
   * Gets the `count` tokens that follows a given node or token with comment options.
1,044✔
623
   */
1,044✔
624
  public getTokensAfter<R extends ESLintAST.Token | JSONCComment>(
1,044✔
625
    node: JSONCSyntaxElement,
1,044✔
626
    options: CursorWithCountOptionsWithComment<
1,044✔
627
      ESLintAST.Token,
1,044✔
628
      JSONCComment,
1,044✔
629
      R
1,044✔
630
    >,
1,044✔
631
  ): R[];
1,044✔
632

1,044✔
633
  public getTokensAfter(
1,044✔
NEW
634
    node: JSONCSyntaxElement,
×
NEW
635
    options?:
×
NEW
636
      | CursorWithCountOptionsWithoutFilter
×
NEW
637
      | CursorWithCountOptionsWithFilter<ESLintAST.Token>
×
NEW
638
      | CursorWithCountOptionsWithComment<ESLintAST.Token, JSONCComment>,
×
NEW
639
  ): (ESLintAST.Token | JSONCComment)[] {
×
NEW
640
    return this.tokenStore.getTokensAfter(node as never, options as never);
×
NEW
641
  }
×
NEW
642

×
NEW
643
  /**
×
NEW
644
   * Gets the first token between two non-overlapping nodes.
×
NEW
645
   */
×
NEW
646
  public getFirstTokenBetween(
×
NEW
647
    left: JSONCSyntaxElement,
×
NEW
648
    right: JSONCSyntaxElement,
×
NEW
649
    options?: CursorWithSkipOptionsWithoutFilter,
×
NEW
650
  ): ESLintAST.Token | null;
×
NEW
651

×
NEW
652
  /**
×
NEW
653
   * Gets the first token between two non-overlapping nodes with filter options.
×
NEW
654
   */
×
NEW
655
  public getFirstTokenBetween<R extends ESLintAST.Token>(
×
NEW
656
    left: JSONCSyntaxElement,
×
NEW
657
    right: JSONCSyntaxElement,
×
NEW
658
    options: CursorWithSkipOptionsWithFilter<ESLintAST.Token, R>,
×
NEW
659
  ): R | null;
×
NEW
660

×
NEW
661
  /**
×
NEW
662
   * Gets the first token between two non-overlapping nodes with comment options.
×
NEW
663
   */
×
NEW
664
  public getFirstTokenBetween<R extends ESLintAST.Token | JSONCComment>(
×
NEW
665
    left: JSONCSyntaxElement,
×
NEW
666
    right: JSONCSyntaxElement,
×
NEW
667
    options: CursorWithSkipOptionsWithComment<ESLintAST.Token, JSONCComment, R>,
×
NEW
668
  ): R | null;
×
NEW
669

×
NEW
670
  public getFirstTokenBetween(
✔
671
    left: JSONCSyntaxElement,
20✔
672
    right: JSONCSyntaxElement,
20✔
673
    options?:
20✔
674
      | CursorWithSkipOptionsWithoutFilter
20✔
675
      | CursorWithSkipOptionsWithFilter<ESLintAST.Token>
20✔
676
      | CursorWithSkipOptionsWithComment<ESLintAST.Token, JSONCComment>,
20✔
677
  ): ESLintAST.Token | JSONCComment | null {
20✔
678
    return this.tokenStore.getFirstTokenBetween(
20✔
679
      left as never,
20✔
680
      right as never,
20✔
681
      options as never,
20✔
682
    );
20✔
683
  }
20✔
NEW
684

×
NEW
685
  /**
×
NEW
686
   * Gets the first tokens between two non-overlapping nodes.
×
NEW
687
   */
×
NEW
688
  public getFirstTokensBetween(
×
NEW
689
    left: JSONCSyntaxElement,
×
NEW
690
    right: JSONCSyntaxElement,
×
NEW
691
    options?: CursorWithCountOptionsWithoutFilter,
×
NEW
692
  ): ESLintAST.Token[];
×
NEW
693

×
NEW
694
  /**
×
NEW
695
   * Gets the first tokens between two non-overlapping nodes with filter options.
×
NEW
696
   */
×
NEW
697
  public getFirstTokensBetween<R extends ESLintAST.Token>(
×
NEW
698
    left: JSONCSyntaxElement,
×
NEW
699
    right: JSONCSyntaxElement,
×
NEW
700
    options: CursorWithCountOptionsWithFilter<ESLintAST.Token, R>,
×
NEW
701
  ): R[];
×
NEW
702

×
NEW
703
  /**
×
NEW
704
   * Gets the first tokens between two non-overlapping nodes with comment options.
×
NEW
705
   */
×
NEW
706
  public getFirstTokensBetween<R extends ESLintAST.Token | JSONCComment>(
×
NEW
707
    left: JSONCSyntaxElement,
×
NEW
708
    right: JSONCSyntaxElement,
×
NEW
709
    options: CursorWithCountOptionsWithComment<
×
NEW
710
      ESLintAST.Token,
×
NEW
711
      JSONCComment,
×
NEW
712
      R
×
NEW
713
    >,
×
NEW
714
  ): R[];
×
NEW
715

×
NEW
716
  public getFirstTokensBetween(
×
NEW
717
    left: JSONCSyntaxElement,
×
NEW
718
    right: JSONCSyntaxElement,
×
NEW
719
    options?:
×
NEW
720
      | CursorWithCountOptionsWithoutFilter
×
NEW
721
      | CursorWithCountOptionsWithFilter<ESLintAST.Token>
×
NEW
722
      | CursorWithCountOptionsWithComment<ESLintAST.Token, JSONCComment>,
×
NEW
723
  ): (ESLintAST.Token | JSONCComment)[] {
×
NEW
724
    return this.tokenStore.getFirstTokensBetween(
×
NEW
725
      left as never,
×
NEW
726
      right as never,
×
NEW
727
      options as never,
×
NEW
728
    );
×
NEW
729
  }
×
NEW
730

×
NEW
731
  /**
×
NEW
732
   * Gets the last token between two non-overlapping nodes.
×
NEW
733
   */
×
NEW
734
  public getLastTokenBetween(
×
NEW
735
    left: JSONCSyntaxElement,
×
NEW
736
    right: JSONCSyntaxElement,
×
NEW
737
    options?: CursorWithSkipOptionsWithoutFilter,
×
NEW
738
  ): ESLintAST.Token | null;
×
NEW
739

×
NEW
740
  /**
×
NEW
741
   * Gets the last token between two non-overlapping nodes with filter options.
×
NEW
742
   */
×
NEW
743
  public getLastTokenBetween<R extends ESLintAST.Token>(
×
NEW
744
    left: JSONCSyntaxElement,
×
NEW
745
    right: JSONCSyntaxElement,
×
NEW
746
    options: CursorWithSkipOptionsWithFilter<ESLintAST.Token, R>,
×
NEW
747
  ): R | null;
×
NEW
748

×
NEW
749
  /**
×
NEW
750
   * Gets the last token between two non-overlapping nodes with comment options.
×
NEW
751
   */
×
NEW
752
  public getLastTokenBetween<R extends ESLintAST.Token | JSONCComment>(
×
NEW
753
    left: JSONCSyntaxElement,
×
NEW
754
    right: JSONCSyntaxElement,
×
NEW
755
    options: CursorWithSkipOptionsWithComment<ESLintAST.Token, JSONCComment, R>,
×
NEW
756
  ): R | null;
×
NEW
757

×
NEW
758
  public getLastTokenBetween(
×
NEW
759
    left: JSONCSyntaxElement,
×
NEW
760
    right: JSONCSyntaxElement,
×
NEW
761
    options?:
×
NEW
762
      | CursorWithSkipOptionsWithoutFilter
×
NEW
763
      | CursorWithSkipOptionsWithFilter<ESLintAST.Token>
×
NEW
764
      | CursorWithSkipOptionsWithComment<ESLintAST.Token, JSONCComment>,
×
NEW
765
  ): ESLintAST.Token | JSONCComment | null {
×
NEW
766
    return this.tokenStore.getLastTokenBetween(
×
NEW
767
      left as never,
×
NEW
768
      right as never,
×
NEW
769
      options as never,
×
NEW
770
    );
×
NEW
771
  }
×
NEW
772

×
NEW
773
  /**
×
NEW
774
   * Gets the last tokens between two non-overlapping nodes.
×
NEW
775
   */
×
NEW
776
  public getLastTokensBetween(
×
NEW
777
    left: JSONCSyntaxElement,
×
NEW
778
    right: JSONCSyntaxElement,
×
NEW
779
    options?: CursorWithCountOptionsWithoutFilter,
×
NEW
780
  ): ESLintAST.Token[];
×
NEW
781

×
NEW
782
  /**
×
NEW
783
   * Gets the last tokens between two non-overlapping nodes with filter options.
×
NEW
784
   */
×
NEW
785
  public getLastTokensBetween<R extends ESLintAST.Token>(
×
NEW
786
    left: JSONCSyntaxElement,
×
NEW
787
    right: JSONCSyntaxElement,
×
NEW
788
    options: CursorWithCountOptionsWithFilter<ESLintAST.Token, R>,
×
NEW
789
  ): R[];
×
NEW
790

×
NEW
791
  /**
×
NEW
792
   * Gets the last tokens between two non-overlapping nodes with comment options.
×
NEW
793
   */
×
NEW
794
  public getLastTokensBetween<R extends ESLintAST.Token | JSONCComment>(
×
NEW
795
    left: JSONCSyntaxElement,
×
NEW
796
    right: JSONCSyntaxElement,
×
NEW
797
    options: CursorWithCountOptionsWithComment<
×
NEW
798
      ESLintAST.Token,
×
NEW
799
      JSONCComment,
×
NEW
800
      R
×
NEW
801
    >,
×
NEW
802
  ): R[];
×
NEW
803

×
NEW
804
  public getLastTokensBetween(
×
NEW
805
    left: JSONCSyntaxElement,
×
NEW
806
    right: JSONCSyntaxElement,
×
NEW
807
    options?:
×
NEW
808
      | CursorWithCountOptionsWithoutFilter
×
NEW
809
      | CursorWithCountOptionsWithFilter<ESLintAST.Token>
×
NEW
810
      | CursorWithCountOptionsWithComment<ESLintAST.Token, JSONCComment>,
×
NEW
811
  ): (ESLintAST.Token | JSONCComment)[] {
×
NEW
812
    return this.tokenStore.getLastTokensBetween(
×
NEW
813
      left as never,
×
NEW
814
      right as never,
×
NEW
815
      options as never,
×
NEW
816
    );
×
NEW
817
  }
×
NEW
818

×
NEW
819
  /**
×
NEW
820
   * Gets all tokens that are related to the given node.
×
NEW
821
   */
×
NEW
822
  public getTokens(
×
NEW
823
    node: JSONCSyntaxElement,
×
NEW
824
    options?: CursorWithCountOptionsWithoutFilter,
×
NEW
825
  ): ESLintAST.Token[];
×
NEW
826

×
NEW
827
  /**
×
NEW
828
   * Gets all tokens that are related to the given node with filter options.
×
NEW
829
   */
×
NEW
830
  public getTokens<R extends ESLintAST.Token>(
×
NEW
831
    node: JSONCSyntaxElement,
×
NEW
832
    options: CursorWithCountOptionsWithFilter<ESLintAST.Token, R>,
×
NEW
833
  ): R[];
×
NEW
834

×
NEW
835
  /**
×
NEW
836
   * Gets all tokens that are related to the given node with comment options.
×
NEW
837
   */
×
NEW
838
  public getTokens<R extends ESLintAST.Token | JSONCComment>(
×
NEW
839
    node: JSONCSyntaxElement,
×
NEW
840
    options: CursorWithCountOptionsWithComment<
×
NEW
841
      ESLintAST.Token,
×
NEW
842
      JSONCComment,
×
NEW
843
      R
×
NEW
844
    >,
×
NEW
845
  ): R[];
×
NEW
846

×
NEW
847
  public getTokens(
✔
848
    node: JSONCSyntaxElement,
30✔
849
    options?:
30✔
850
      | CursorWithCountOptionsWithoutFilter
30✔
851
      | CursorWithCountOptionsWithFilter<ESLintAST.Token>
30✔
852
      | CursorWithCountOptionsWithComment<ESLintAST.Token, JSONCComment>,
30✔
853
  ): (ESLintAST.Token | JSONCComment)[] {
30✔
854
    return this.tokenStore.getTokens(node as never, options as never);
30✔
NEW
855
  }
×
NEW
856

×
NEW
857
  /**
×
NEW
858
   * Gets all of the tokens between two non-overlapping nodes.
×
NEW
859
   */
×
NEW
860
  public getTokensBetween(
×
NEW
861
    left: JSONCSyntaxElement,
×
NEW
862
    right: JSONCSyntaxElement,
×
NEW
863
    options?: CursorWithCountOptionsWithoutFilter,
×
NEW
864
  ): ESLintAST.Token[];
×
NEW
865

×
NEW
866
  /**
×
NEW
867
   * Gets all of the tokens between two non-overlapping nodes with filter options.
×
NEW
868
   */
×
NEW
869
  public getTokensBetween<R extends ESLintAST.Token>(
×
NEW
870
    left: JSONCSyntaxElement,
×
NEW
871
    right: JSONCSyntaxElement,
×
NEW
872
    options: CursorWithCountOptionsWithFilter<ESLintAST.Token, R>,
×
NEW
873
  ): R[];
×
NEW
874

×
NEW
875
  /**
×
NEW
876
   * Gets all of the tokens between two non-overlapping nodes with comment options.
×
NEW
877
   */
×
NEW
878
  public getTokensBetween<R extends ESLintAST.Token | JSONCComment>(
×
NEW
879
    left: JSONCSyntaxElement,
×
NEW
880
    right: JSONCSyntaxElement,
×
NEW
881
    options: CursorWithCountOptionsWithComment<
×
NEW
882
      ESLintAST.Token,
×
NEW
883
      JSONCComment,
×
NEW
884
      R
×
NEW
885
    >,
×
NEW
886
  ): R[];
×
NEW
887

×
NEW
888
  public getTokensBetween(
✔
889
    left: JSONCSyntaxElement,
70✔
890
    right: JSONCSyntaxElement,
70✔
891
    options?:
70✔
892
      | CursorWithCountOptionsWithoutFilter
70✔
893
      | CursorWithCountOptionsWithFilter<ESLintAST.Token>
70✔
894
      | CursorWithCountOptionsWithComment<ESLintAST.Token, JSONCComment>,
70✔
895
  ): (ESLintAST.Token | JSONCComment)[] {
70✔
896
    return this.tokenStore.getTokensBetween(
70✔
897
      left as never,
70✔
898
      right as never,
70✔
899
      options as never,
70✔
900
    );
70✔
901
  }
70✔
902

1,044✔
903
  public getCommentsInside(nodeOrToken: JSONCSyntaxElement): JSONCComment[] {
1,044✔
NEW
904
    return this.tokenStore.getCommentsInside(nodeOrToken as never);
×
NEW
905
  }
×
906

1,044✔
907
  public getCommentsBefore(nodeOrToken: JSONCSyntaxElement): JSONCComment[] {
1,044✔
908
    return this.tokenStore.getCommentsBefore(nodeOrToken as never);
2✔
909
  }
2✔
910

1,044✔
911
  public getCommentsAfter(nodeOrToken: JSONCSyntaxElement): JSONCComment[] {
1,044✔
NEW
912
    return this.tokenStore.getCommentsAfter(nodeOrToken as never);
×
NEW
913
  }
×
NEW
914

×
NEW
915
  public isSpaceBetween(
✔
916
    first: ESLintAST.Token | JSONCComment,
540✔
917
    second: ESLintAST.Token | JSONCComment,
540✔
918
  ): boolean {
540✔
919
    // Normalize order: ensure left comes before right
540✔
920
    const [left, right] =
540✔
921
      first.range[1] <= second.range[0] ? [first, second] : [second, first];
540✔
922
    return this.tokenStore.isSpaceBetween(left as never, right as never);
540✔
923
  }
540✔
NEW
924

×
NEW
925
  /**
×
NEW
926
   * Compatibility for ESLint's SourceCode API
×
NEW
927
   * @deprecated JSONC does not have scopes
×
NEW
928
   */
×
NEW
929
  public getScope(node?: AST.JSONNode): Scope.Scope | null {
✔
930
    if (node?.type !== "Program") {
39!
NEW
931
      return null;
×
NEW
932
    }
×
933
    return createFakeGlobalScope(this.ast);
39✔
934
  }
39✔
935

1,044✔
936
  /**
1,044✔
937
   * Compatibility for ESLint's SourceCode API
1,044✔
938
   * @deprecated JSONC does not have scopes
1,044✔
939
   */
1,044✔
940
  public get scopeManager(): Scope.ScopeManager | null {
1,044✔
NEW
941
    return {
×
NEW
942
      scopes: [],
×
NEW
943
      globalScope: createFakeGlobalScope(this.ast),
×
NEW
944
      acquire: (node) => {
×
NEW
945
        if (node.type === "Program") {
×
NEW
946
          return createFakeGlobalScope(this.ast);
×
NEW
947
        }
×
NEW
948
        return null;
×
NEW
949
      },
×
NEW
950
      getDeclaredVariables: () => [],
×
NEW
951
      addGlobals: () => {
×
NEW
952
        // noop
×
NEW
953
      },
×
NEW
954
    };
×
NEW
955
  }
×
956

1,044✔
957
  /**
1,044✔
958
   * Compatibility for ESLint's SourceCode API
1,044✔
959
   * @deprecated
1,044✔
960
   */
1,044✔
961
  public isSpaceBetweenTokens(first: JSONCToken, second: JSONCToken): boolean {
1,044✔
962
    return this.isSpaceBetween(first, second);
1✔
963
  }
1✔
964

1,044✔
965
  private _getChildren(node: AST.JSONNode) {
1,044✔
966
    const keys = this.visitorKeys[node.type] || [];
493!
967
    const children: AST.JSONNode[] = [];
493✔
968
    for (const key of keys) {
493✔
969
      const value = (node as unknown as Record<string, unknown>)[key];
533✔
970
      if (Array.isArray(value)) {
533✔
971
        for (const element of value) {
229✔
972
          if (isNode(element)) {
325✔
973
            children.push(element);
325✔
974
          }
325✔
975
        }
325✔
976
      } else if (isNode(value)) {
533✔
977
        children.push(value);
304✔
978
      }
304✔
979
    }
533✔
980
    return children;
493✔
981
  }
493✔
982
}
1,044✔
983

1✔
984
/**
1✔
985
 * Determines whether the given value is a JSONC AST node.
1✔
986
 */
1✔
987
function isNode(value: unknown): value is AST.JSONNode {
629✔
988
  return (
629✔
989
    typeof value === "object" &&
629✔
990
    value !== null &&
629✔
991
    typeof (value as Record<string, unknown>).type === "string" &&
629✔
992
    Array.isArray((value as Record<string, unknown>).range) &&
629✔
993
    Boolean((value as Record<string, unknown>).loc) &&
629✔
994
    typeof (value as Record<string, unknown>).loc === "object"
629✔
995
  );
629✔
996
}
629✔
997

1✔
998
/**
1✔
999
 * Creates a fake global scope for JSONC files.
1✔
1000
 * @deprecated JSONC does not have scopes
1✔
1001
 */
1✔
1002
function createFakeGlobalScope(node: AST.JSONProgram): Scope.Scope {
39✔
1003
  const fakeGlobalScope: Scope.Scope = {
39✔
1004
    type: "global",
39✔
1005
    block: node as never,
39✔
1006
    set: new Map(),
39✔
1007
    through: [],
39✔
1008
    childScopes: [],
39✔
1009
    variableScope: null as never,
39✔
1010
    variables: [],
39✔
1011
    references: [],
39✔
1012
    functionExpressionScope: false,
39✔
1013
    isStrict: false,
39✔
1014
    upper: null,
39✔
1015
    implicit: {
39✔
1016
      variables: [],
39✔
1017
      set: new Map(),
39✔
1018
    },
39✔
1019
  };
39✔
1020
  fakeGlobalScope.variableScope = fakeGlobalScope;
39✔
1021
  return fakeGlobalScope;
39✔
1022
}
39✔
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