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

ota-meshi / eslint-plugin-json-schema-validator / 21108009668

18 Jan 2026 07:22AM UTC coverage: 78.196% (-9.2%) from 87.363%
21108009668

Pull #452

github

web-flow
Merge dfb762a3b into bb8e97af5
Pull Request #452: Bundle using tsdown

717 of 872 branches covered (82.22%)

Branch coverage included in aggregate %.

30 of 51 new or added lines in 7 files covered. (58.82%)

574 existing lines in 11 files now uncovered.

2170 of 2820 relevant lines covered (76.95%)

55.12 hits per line

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

66.67
/src/utils/ast/js/utils.ts
1
import * as eslintUtils from "@eslint-community/eslint-utils";
1✔
2
import type { Variable } from "eslint-scope";
1✔
3
import type { AST } from "vue-eslint-parser";
1✔
4

1✔
5
import type { RuleContext } from "../../../types";
1✔
6
import { getSourceCode } from "../../compat";
1✔
7

1✔
8
/**
1✔
9
 * Gets the property name of a given node.
1✔
10
 */
1✔
11
export function getStaticPropertyName(
1✔
12
  node: AST.ESLintProperty | AST.ESLintMemberExpression,
79✔
13
  context: RuleContext,
79✔
14
): string | null {
79✔
15
  let key;
79✔
16
  if (node.type === "Property") {
79✔
17
    key = node.key;
68✔
18
    if (!node.computed) {
68✔
19
      if (key.type === "Identifier") {
68✔
20
        return key.name;
66✔
21
      }
66✔
22
    }
68✔
23
  } else if (node.type === "MemberExpression") {
79✔
24
    key = node.property;
11✔
25
    if (!node.computed) {
6✔
26
      if (key.type === "Identifier") {
6✔
27
        return key.name;
7✔
28
      }
7✔
29
      return null;
7!
30
    }
1✔
31
  } else {
1!
32
    return null;
1✔
33
  }
1✔
34
  if (key.type === "Literal" || key.type === "TemplateLiteral") {
1!
35
    return getStringLiteralValue(key);
6✔
36
  }
2✔
37
  if (key.type === "Identifier") {
2!
38
    const init = findInitNode(context, key);
2!
39
    if (init) {
2✔
40
      if (
2✔
41
        init.node.type === "Literal" ||
2✔
42
        init.node.type === "TemplateLiteral"
2✔
43
      ) {
43✔
44
        return getStringLiteralValue(init.node);
43✔
45
      }
236✔
46
    }
236✔
47
  }
236✔
48
  return null;
43✔
49
}
43✔
50

43✔
51
/**
43✔
52
 * Gets the string of a given node.
43✔
53
 */
43✔
54
export function getStringLiteralValue(
2✔
55
  node: AST.ESLintLiteral | AST.ESLintTemplateLiteral,
1✔
56
): string | null {
1✔
57
  if (node.type === "Literal") {
1✔
58
    if (node.value == null) {
1!
59
      if (node.bigint != null) {
1!
60
        return String(node.bigint);
1✔
61
      }
1✔
62
    }
1✔
63
    return String(node.value);
1!
UNCOV
64
  }
×
UNCOV
65
  if (node.type === "TemplateLiteral") {
×
UNCOV
66
    if (node.expressions.length === 0 && node.quasis.length === 1) {
✔
67
      return node.quasis[0].value.cooked;
1✔
68
    }
1✔
69
  }
1✔
70
  return null;
1✔
71
}
6✔
72

1✔
73
/**
1✔
74
 * Find the variable of a given name.
1✔
75
 */
1✔
76
function findVariable(
46✔
UNCOV
77
  context: RuleContext,
×
UNCOV
78
  node: AST.ESLintIdentifier,
×
UNCOV
79
): Variable | null {
×
UNCOV
80
  return eslintUtils.findVariable(
✔
UNCOV
81
    getScope(context, node),
×
UNCOV
82
    node,
×
UNCOV
83
  ) as Variable | null;
×
UNCOV
84
}
×
UNCOV
85

×
UNCOV
86
/**
×
UNCOV
87
 * Get the value of a given node if it's a static value.
×
UNCOV
88
 */
×
UNCOV
89
export function getStaticValue(
✔
90
  context: RuleContext,
14✔
91
  node: AST.ESLintNode,
14✔
92
): { value?: unknown; optional?: boolean } | null {
14✔
93
  return eslintUtils.getStaticValue(
14✔
94
    // @ts-expect-error -- `eslintUtils` is typed now but incompatible with Vue AST typings
14✔
95
    node,
14✔
96
    getScope(context, node),
14✔
97
  );
14✔
98
}
14✔
99

1✔
100
/**
1✔
101
 * Find the node that initial value.
1✔
102
 */
1✔
103
export function findInitNode(
1!
UNCOV
104
  context: RuleContext,
×
UNCOV
105
  node: AST.ESLintIdentifier,
✔
UNCOV
106
): { node: AST.ESLintExpression; reads: AST.ESLintIdentifier[] } | null {
×
UNCOV
107
  const variable = findVariable(context, node);
×
UNCOV
108
  if (!variable) {
×
109
    return null;
×
UNCOV
110
  }
×
UNCOV
111
  if (variable.defs.length === 1) {
✔
UNCOV
112
    const def = variable.defs[0];
✔
UNCOV
113
    if (
×
UNCOV
114
      def.type === "Variable" &&
✔
UNCOV
115
      def.parent.kind === "const" &&
✔
UNCOV
116
      def.node.init
×
UNCOV
117
    ) {
✔
UNCOV
118
      let init = def.node.init as AST.ESLintExpression;
×
UNCOV
119
      const reads = variable.references
×
UNCOV
120
        .filter((ref) => ref.isRead())
✔
UNCOV
121
        .map((ref) => ref.identifier as AST.ESLintIdentifier);
×
UNCOV
122
      if (init.type === "Identifier") {
×
UNCOV
123
        const data = findInitNode(context, init);
✔
UNCOV
124
        if (!data) {
×
UNCOV
125
          return null;
×
UNCOV
126
        }
×
UNCOV
127
        init = data.node;
✔
UNCOV
128
        reads.push(...data.reads);
×
UNCOV
129
      }
×
UNCOV
130

×
UNCOV
131
      return {
×
UNCOV
132
        node: init,
×
UNCOV
133
        reads,
×
UNCOV
134
      };
×
UNCOV
135
    }
×
UNCOV
136
  }
×
UNCOV
137
  return null;
✔
UNCOV
138
}
×
UNCOV
139

×
UNCOV
140
/**
×
UNCOV
141
 * Gets the scope for the current node
×
UNCOV
142
 */
×
143
function getScope(context: RuleContext, currentNode: AST.ESLintNode) {
66!
144
  // On Program node, get the outermost scope to avoid return Node.js special function scope or ES modules scope.
66✔
145
  const inner = currentNode.type !== "Program";
66✔
146
  const scopeManager = getSourceCode(context).scopeManager;
66✔
147

66✔
148
  let node: AST.Node | null = currentNode;
66✔
149
  for (; node; node = node.parent || null) {
66!
150
    const scope = scopeManager.acquire(
345✔
151
      // @ts-expect-error -- incompatible with Vue AST typings
68✔
152
      node,
68✔
153
      inner,
1✔
154
    );
1✔
155

1✔
156
    if (scope) {
1✔
157
      if (scope.type === "function-expression-name") {
68!
158
        return scope.childScopes[0];
×
UNCOV
159
      }
×
160
      return scope;
66✔
161
    }
66✔
162
  }
345✔
163

66✔
164
  return scopeManager.scopes[0];
66!
165
}
66✔
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