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

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

10 Nov 2025 08:57AM UTC coverage: 87.373% (+0.04%) from 87.33%
19226122443

push

github

web-flow
feat: normalize schemastore URLs to use `www.schemastore.org` (#424)

* feat: normalize schemastore URLs to use `www.schemastore.org`

* Create two-years-jam.md

373 of 456 branches covered (81.8%)

Branch coverage included in aggregate %.

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

3 existing lines in 1 file now uncovered.

914 of 1017 relevant lines covered (89.87%)

189.1 hits per line

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

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

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

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

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

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

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

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

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

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

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

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

UNCOV
164
  return scopeManager.scopes[0];
×
165
}
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