gitnexus 1.6.9-rc.13 → 1.6.9-rc.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -576,13 +576,16 @@ export const JAVA_HTTP_PLUGIN = {
|
|
|
576
576
|
language: Java,
|
|
577
577
|
// routeCoverage intentionally LEFT at the default 'partial' (#2138 Part 2).
|
|
578
578
|
// The graph provider set is a strict *subset* of this scan()'s provider set —
|
|
579
|
-
// ingestion does NOT emit a Route node for (1)
|
|
580
|
-
//
|
|
581
|
-
//
|
|
582
|
-
//
|
|
583
|
-
//
|
|
584
|
-
//
|
|
585
|
-
//
|
|
579
|
+
// ingestion does NOT emit a Route node for (1) a method-level array route
|
|
580
|
+
// nested under a class-level array-form `@RequestMapping` (ingestion suppresses
|
|
581
|
+
// it rather than drop the prefix; bare/scalar-prefixed array methods ARE now
|
|
582
|
+
// emitted — see #2280), (2) interface-inherited Spring routes, or (3) the 2nd
|
|
583
|
+
// verb of a same-URL GET+POST pair (Route nodes are URL-keyed). Declaring
|
|
584
|
+
// 'complete' here would let the parse-skip drop those group-only providers.
|
|
585
|
+
// Java flips to 'complete' only once ingestion provider extraction matches this
|
|
586
|
+
// scan (a follow-up: class-level array-form prefix support + interface-
|
|
587
|
+
// inheritance emission + per-verb Route identity — tracked in #2280).
|
|
588
|
+
// `hasConsumerSignals` below is kept ready for that flip.
|
|
586
589
|
// Consumer signals this plugin's scan() can detect: RestTemplate / WebClient /
|
|
587
590
|
// OkHttp / Java-HttpClient / Apache-HttpClient call sites, OpenFeign
|
|
588
591
|
// (`@FeignClient` + `@RequestLine`) interfaces, and Spring 6 HTTP Interface
|
|
@@ -31,6 +31,18 @@ import { METHOD_ANNOTATION_TO_HTTP, isRouteMemberKey, findEnclosingClass, unquot
|
|
|
31
31
|
* @node → enclosing declaration (class_declaration | method_declaration)
|
|
32
32
|
* @value → the string-literal argument
|
|
33
33
|
* @key → the named-argument member key (absent for positional form)
|
|
34
|
+
*
|
|
35
|
+
* Method-level routes accept both the bare string form `@GetMapping("/x")` and
|
|
36
|
+
* the array form `@GetMapping({"/a","/b"})` (positional or `path =`/`value =`):
|
|
37
|
+
* a multi-element array yields one match per element, so the Phase 2 loop emits
|
|
38
|
+
* one route per path with no special-casing. This mirrors the group-layer
|
|
39
|
+
* `java.ts` query so the two Spring extractors stay in parity (#2138 follow-up;
|
|
40
|
+
* the divergence here was the root of the #2265 array-form gap). The class-level
|
|
41
|
+
* `@RequestMapping` branches also match the array form, but only to *detect* it:
|
|
42
|
+
* an array-form class prefix can't be resolved to a single string, so Phase 2
|
|
43
|
+
* suppresses that class's method-level array routes rather than emit them with a
|
|
44
|
+
* dropped prefix (a wrong route). Full class-array cross-product support is left
|
|
45
|
+
* to a follow-up (#2280).
|
|
34
46
|
*/
|
|
35
47
|
const ROUTE_ANNOTATION_QUERY = new Parser.Query(Java, `
|
|
36
48
|
[
|
|
@@ -38,7 +50,9 @@ const ROUTE_ANNOTATION_QUERY = new Parser.Query(Java, `
|
|
|
38
50
|
(modifiers
|
|
39
51
|
(annotation
|
|
40
52
|
name: (identifier) @ann
|
|
41
|
-
arguments: (annotation_argument_list
|
|
53
|
+
arguments: (annotation_argument_list
|
|
54
|
+
[(string_literal) @value
|
|
55
|
+
(element_value_array_initializer (string_literal) @value)])))) @node
|
|
42
56
|
(class_declaration
|
|
43
57
|
(modifiers
|
|
44
58
|
(annotation
|
|
@@ -46,12 +60,15 @@ const ROUTE_ANNOTATION_QUERY = new Parser.Query(Java, `
|
|
|
46
60
|
arguments: (annotation_argument_list
|
|
47
61
|
(element_value_pair
|
|
48
62
|
key: (identifier) @key
|
|
49
|
-
value: (string_literal) @value
|
|
63
|
+
value: [(string_literal) @value
|
|
64
|
+
(element_value_array_initializer (string_literal) @value)]))))) @node
|
|
50
65
|
(method_declaration
|
|
51
66
|
(modifiers
|
|
52
67
|
(annotation
|
|
53
68
|
name: (identifier) @ann
|
|
54
|
-
arguments: (annotation_argument_list
|
|
69
|
+
arguments: (annotation_argument_list
|
|
70
|
+
[(string_literal) @value
|
|
71
|
+
(element_value_array_initializer (string_literal) @value)])))) @node
|
|
55
72
|
(method_declaration
|
|
56
73
|
(modifiers
|
|
57
74
|
(annotation
|
|
@@ -59,7 +76,8 @@ const ROUTE_ANNOTATION_QUERY = new Parser.Query(Java, `
|
|
|
59
76
|
arguments: (annotation_argument_list
|
|
60
77
|
(element_value_pair
|
|
61
78
|
key: (identifier) @key
|
|
62
|
-
value: (string_literal) @value
|
|
79
|
+
value: [(string_literal) @value
|
|
80
|
+
(element_value_array_initializer (string_literal) @value)]))))) @node
|
|
63
81
|
]
|
|
64
82
|
`);
|
|
65
83
|
/**
|
|
@@ -76,8 +94,15 @@ const ROUTE_ANNOTATION_QUERY = new Parser.Query(Java, `
|
|
|
76
94
|
*/
|
|
77
95
|
export function extractSpringRoutes(tree, filePath, lineOffset = 0) {
|
|
78
96
|
const matches = ROUTE_ANNOTATION_QUERY.matches(tree.rootNode);
|
|
79
|
-
// Phase 1: collect class-level @RequestMapping prefixes keyed by node id
|
|
97
|
+
// Phase 1: collect class-level @RequestMapping prefixes keyed by node id.
|
|
98
|
+
// A scalar prefix (`@RequestMapping("/base")`) is stored in prefixByClassId.
|
|
99
|
+
// A class whose @RequestMapping uses the array form (`@RequestMapping({...})`)
|
|
100
|
+
// is instead recorded in classesWithArrayPrefix: there is no single prefix to
|
|
101
|
+
// store, and Phase 2 uses this to suppress that class's method-level array
|
|
102
|
+
// routes rather than emit them unprefixed (a wrong route — see #2280). Full
|
|
103
|
+
// class-array cross-product support is out of scope here.
|
|
80
104
|
const prefixByClassId = new Map();
|
|
105
|
+
const classesWithArrayPrefix = new Set();
|
|
81
106
|
for (const match of matches) {
|
|
82
107
|
const caps = {};
|
|
83
108
|
for (const { name, node } of match.captures) {
|
|
@@ -92,6 +117,10 @@ export function extractSpringRoutes(tree, filePath, lineOffset = 0) {
|
|
|
92
117
|
if (node.type === 'class_declaration' && annNode.text === 'RequestMapping') {
|
|
93
118
|
if (!isRouteMemberKey(keyNode))
|
|
94
119
|
continue;
|
|
120
|
+
if (valueNode.parent?.type === 'element_value_array_initializer') {
|
|
121
|
+
classesWithArrayPrefix.add(node.id);
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
95
124
|
const prefix = unquoteSpringLiteral(valueNode.text);
|
|
96
125
|
if (prefix !== null)
|
|
97
126
|
prefixByClassId.set(node.id, prefix);
|
|
@@ -122,6 +151,18 @@ export function extractSpringRoutes(tree, filePath, lineOffset = 0) {
|
|
|
122
151
|
if (routePath === null)
|
|
123
152
|
continue;
|
|
124
153
|
const enclosingClass = findEnclosingClass(node);
|
|
154
|
+
// Suppress a method-level *array-form* route nested under a class-level
|
|
155
|
+
// array-form @RequestMapping. The class prefix is one of several values that
|
|
156
|
+
// cannot be resolved to a single string here, so emitting the route would
|
|
157
|
+
// drop the prefix and yield a wrong unprefixed Route (a false signal, worse
|
|
158
|
+
// than a missing one). Skipping keeps ingestion a strict subset of the group
|
|
159
|
+
// scan — safe under routeCoverage:'partial'. Full class-array cross-product
|
|
160
|
+
// support is tracked in #2280. (Scalar method paths under an array class
|
|
161
|
+
// prefix are left unchanged: that pre-existing divergence is out of scope.)
|
|
162
|
+
const isArrayElement = valueNode.parent?.type === 'element_value_array_initializer';
|
|
163
|
+
if (isArrayElement && enclosingClass && classesWithArrayPrefix.has(enclosingClass.id)) {
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
125
166
|
const classPrefix = enclosingClass ? (prefixByClassId.get(enclosingClass.id) ?? '') : '';
|
|
126
167
|
// `node` is the annotated `method_declaration`; its name field is the
|
|
127
168
|
// handler method name (resolved to a symbol UID later by the routes phase).
|
package/package.json
CHANGED