@descryy/adapter-csharp 0.1.0 → 0.3.0
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.
- package/LICENSE +8 -0
- package/dist/adapter.d.ts +3 -8
- package/dist/adapter.d.ts.map +1 -1
- package/dist/adapter.js +57 -65
- package/dist/adapter.js.map +1 -1
- package/dist/aspnetcore.d.ts +53 -95
- package/dist/aspnetcore.d.ts.map +1 -1
- package/dist/aspnetcore.js +56 -101
- package/dist/aspnetcore.js.map +1 -1
- package/dist/client-base.d.ts +51 -88
- package/dist/client-base.d.ts.map +1 -1
- package/dist/client-base.js +46 -79
- package/dist/client-base.js.map +1 -1
- package/dist/client.d.ts +42 -106
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +83 -172
- package/dist/client.js.map +1 -1
- package/dist/efcore.d.ts +59 -113
- package/dist/efcore.d.ts.map +1 -1
- package/dist/efcore.js +119 -204
- package/dist/efcore.js.map +1 -1
- package/dist/extract.d.ts +27 -50
- package/dist/extract.d.ts.map +1 -1
- package/dist/extract.js +154 -248
- package/dist/extract.js.map +1 -1
- package/dist/nullability.d.ts +46 -78
- package/dist/nullability.d.ts.map +1 -1
- package/dist/nullability.js +47 -80
- package/dist/nullability.js.map +1 -1
- package/dist/parse.d.ts +62 -102
- package/dist/parse.d.ts.map +1 -1
- package/dist/parse.js +60 -101
- package/dist/parse.js.map +1 -1
- package/dist/projects.d.ts +24 -40
- package/dist/projects.d.ts.map +1 -1
- package/dist/projects.js +38 -65
- package/dist/projects.js.map +1 -1
- package/package.json +15 -6
package/dist/parse.d.ts
CHANGED
|
@@ -1,31 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* One C# file, read into the shape the resolver wants.
|
|
3
3
|
*
|
|
4
|
-
* Hand-written walk, as in Java
|
|
5
|
-
*
|
|
6
|
-
* discards it.
|
|
4
|
+
* Hand-written walk, as in Java/Go/Rust/PHP: containment is what a resolver
|
|
5
|
+
* needs, and a query's match set discards exactly that.
|
|
7
6
|
*
|
|
8
|
-
*
|
|
7
|
+
* What C# changes:
|
|
8
|
+
* - A type may be declared in several files (`partial class`) — DEC-083
|
|
9
|
+
* settles identity, this reader only collects the parts.
|
|
10
|
+
* - `using` imports a namespace, not one type (unlike PHP's `use`), so a bare
|
|
11
|
+
* name is resolved outward through enclosing namespaces then imports —
|
|
12
|
+
* found in two places is an ambiguity to disclose, not a tie to break.
|
|
13
|
+
* - The base list doesn't say which entry is the class. DEC-084: at most one
|
|
14
|
+
* base class, required first, so later entries are interfaces
|
|
15
|
+
* unconditionally and only the first ever needs resolving. `IFoo` isn't read.
|
|
9
16
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* - **A type may be declared in several files.** `partial class` is the first
|
|
14
|
-
* construct in this project whose declaration is legitimately multi-file and
|
|
15
|
-
* says so in the source. DEC-083 settles the identity question; this reader
|
|
16
|
-
* only has to collect the parts.
|
|
17
|
-
* - **`using` imports a namespace, not a type.** PHP's `use` names one class
|
|
18
|
-
* and resolves in one step. C#'s brings in every type in a namespace, so a
|
|
19
|
-
* bare name is resolved by searching the enclosing namespaces outward and
|
|
20
|
-
* then each import — which means a name may be found in two places, and
|
|
21
|
-
* that is an ambiguity to disclose rather than a tie to break.
|
|
22
|
-
* - **The base list does not say which entry is the class.** DEC-084 decides
|
|
23
|
-
* it: at most one base class, and the language requires it first, so entries
|
|
24
|
-
* after the first are interfaces unconditionally and only one entry per
|
|
25
|
-
* class declaration ever needs resolving. The `IFoo` convention is not read.
|
|
26
|
-
*
|
|
27
|
-
* Nested types are ordinary here in a way they are not in PHP, so a type carries
|
|
28
|
-
* its nesting path rather than a single name.
|
|
17
|
+
* Nested types are ordinary here (unlike PHP), so a type carries its nesting
|
|
18
|
+
* path, not a single name.
|
|
29
19
|
*/
|
|
30
20
|
import type { Node } from "@descryy/adapter-treesitter";
|
|
31
21
|
export interface CsRef {
|
|
@@ -51,31 +41,25 @@ export interface CsRef {
|
|
|
51
41
|
readonly name: string;
|
|
52
42
|
};
|
|
53
43
|
/**
|
|
54
|
-
* The name
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
* speculative reference that turns out to be a value is not an unresolved
|
|
59
|
-
* reference — it is not a type reference at all — so it is dropped silently
|
|
60
|
-
* instead of filling the ledger with entries no reader could act on.
|
|
44
|
+
* The name might be a type, might be a variable — `Status.Pending` and
|
|
45
|
+
* `order.Total` are the same node shape, only the resolver knows which.
|
|
46
|
+
* A speculative ref resolving to a value isn't unresolved, it's not a type
|
|
47
|
+
* reference at all, so it's dropped silently rather than ledgered.
|
|
61
48
|
*/
|
|
62
49
|
readonly speculative?: boolean;
|
|
63
50
|
readonly line: number;
|
|
64
51
|
readonly raw: string;
|
|
65
52
|
/**
|
|
66
|
-
* The call's first argument, only when
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
* value at run time. See {@link firstStringArgumentOf}.
|
|
53
|
+
* The call's first argument, only when a bare string literal — mirrors
|
|
54
|
+
* Java's `JavaRef.firstStringArgument`: a binary/interpolated expression
|
|
55
|
+
* returns `undefined`, since the written prefix isn't the runtime value.
|
|
56
|
+
* See {@link firstStringArgumentOf}.
|
|
71
57
|
*/
|
|
72
58
|
readonly firstStringArgument?: string;
|
|
73
59
|
/**
|
|
74
|
-
* The first argument's raw
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
* resolution when {@link firstStringArgument} is absent, not just that it
|
|
78
|
-
* was absent.
|
|
60
|
+
* The first argument's raw text regardless of shape — mirrors Java's
|
|
61
|
+
* `JavaRef.firstArgumentText`: DEC-242 needs to see what blocked resolution
|
|
62
|
+
* when {@link firstStringArgument} is absent, not just that it was.
|
|
79
63
|
*/
|
|
80
64
|
readonly firstArgumentText?: string;
|
|
81
65
|
}
|
|
@@ -88,23 +72,19 @@ export interface CsScope {
|
|
|
88
72
|
readonly locals: Map<string, string | null>;
|
|
89
73
|
readonly pending: Map<string, PendingType>;
|
|
90
74
|
/**
|
|
91
|
-
* Names
|
|
92
|
-
* {@link locals}'s keys
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
* state; a local variable might still be assigned from a constant.
|
|
75
|
+
* Names from the enclosing method's parameter list, a subset of
|
|
76
|
+
* {@link locals}'s keys kept separately: DEC-242's `varies-per-call` needs
|
|
77
|
+
* *parameter*, not *local* — a bare parameter name is caller-supplied with
|
|
78
|
+
* no fixed answer, a local might still be a constant.
|
|
96
79
|
*/
|
|
97
80
|
readonly parameterNames: Set<string>;
|
|
98
81
|
/**
|
|
99
|
-
* `X = expr;`
|
|
100
|
-
* `PendingType`'s
|
|
101
|
-
*
|
|
102
|
-
*
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
* its own to read the way a field does — the constructor body is the only
|
|
106
|
-
* place the assignment is written. Harmless elsewhere; nothing outside a
|
|
107
|
-
* `.ctor` walk reads this map.
|
|
82
|
+
* `X = expr;` / `this.X = expr;` where `expr` is a traceable invocation,
|
|
83
|
+
* reusing `PendingType`'s shape. Consulted only for a `.ctor`'s scope, by
|
|
84
|
+
* the client-base extractor (DEC-164): a property assigned in the
|
|
85
|
+
* constructor from `factory.CreateClient()` (eShopOnWeb's whole `USES_API`
|
|
86
|
+
* population) has no initialiser of its own — the ctor body is the only
|
|
87
|
+
* place the assignment is written.
|
|
108
88
|
*/
|
|
109
89
|
readonly propertyAssignments: Map<string, PendingType>;
|
|
110
90
|
}
|
|
@@ -124,19 +104,17 @@ export interface CsFunc {
|
|
|
124
104
|
readonly scope: CsScope;
|
|
125
105
|
}
|
|
126
106
|
/**
|
|
127
|
-
* A property declaration, kept alongside the `members` name
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
* — DEC-128 §3's definition of a persistent member — and the type **as written**.
|
|
107
|
+
* A property declaration, kept alongside the `members` name->type map, which
|
|
108
|
+
* answers "what type is this name" for receiver typing. EF Core needs four
|
|
109
|
+
* things the map can't carry: attributes (`[Key]`, `[Required]`, `[NotMapped]`),
|
|
110
|
+
* line, public-with-getter (DEC-128 §3's persistent-member test), and the
|
|
111
|
+
* type as written.
|
|
133
112
|
*
|
|
134
|
-
* `written` is
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
* `string?` 508 / `int?` 332 / `int` 218 in `jellyfin` alone.
|
|
113
|
+
* `written` is raw source text, not the base name: `string`/`string?` share a
|
|
114
|
+
* base name but opposite nullability, and `int?` is nullable regardless of
|
|
115
|
+
* NRT context while `string?` is meaningful only under it. Counted across
|
|
116
|
+
* corpora before choosing this shape: `string` 786 / `string?` 508 / `int?`
|
|
117
|
+
* 332 / `int` 218 in jellyfin alone.
|
|
140
118
|
*/
|
|
141
119
|
export interface CsProperty {
|
|
142
120
|
readonly name: string;
|
|
@@ -159,18 +137,11 @@ export interface CsType {
|
|
|
159
137
|
/** The base list **in written order**. DEC-084 reads position as evidence. */
|
|
160
138
|
readonly baseList: string[];
|
|
161
139
|
/**
|
|
162
|
-
* The same entries
|
|
163
|
-
*
|
|
164
|
-
*
|
|
165
|
-
*
|
|
166
|
-
*
|
|
167
|
-
* *is* the mapping declaration and `Order` is the whole fact, so the collapsed
|
|
168
|
-
* form is empty of the thing EF Core is stating.
|
|
169
|
-
*
|
|
170
|
-
* Both are right and both are kept. This is the second construct where a
|
|
171
|
-
* language-level normalisation and a framework-level reading want different
|
|
172
|
-
* halves of the same node — the first was a property's written type, where
|
|
173
|
-
* `string` and `string?` share a base name and have opposite nullability.
|
|
140
|
+
* The same entries as written, generic arguments intact. `baseList` drops
|
|
141
|
+
* generics via `typeName` (`List<Order>` -> `List`, identity for the
|
|
142
|
+
* resolver), but `IEntityTypeConfiguration<Order>`'s `Order` argument *is*
|
|
143
|
+
* the mapping fact a framework extractor needs — the collapsed form is
|
|
144
|
+
* empty of it. Both kept, same split as a property's written type.
|
|
174
145
|
*/
|
|
175
146
|
readonly baseListWritten: string[];
|
|
176
147
|
/** Property and field names -> declared type, `null` when ambiguous. */
|
|
@@ -184,13 +155,11 @@ export interface CsType {
|
|
|
184
155
|
readonly endLine: number;
|
|
185
156
|
readonly typeRefs: CsRef[];
|
|
186
157
|
/**
|
|
187
|
-
* A field's own inline initialiser
|
|
188
|
-
* `private readonly HttpClient _client = factory.CreateClient()
|
|
189
|
-
*
|
|
190
|
-
*
|
|
191
|
-
*
|
|
192
|
-
* from its `.ctor`'s body — two different places in the source for the
|
|
193
|
-
* same fact.
|
|
158
|
+
* A field's own inline initialiser when it's a traceable invocation
|
|
159
|
+
* (`private readonly HttpClient _client = factory.CreateClient();`). Same
|
|
160
|
+
* shape and reader as `CsScope.propertyAssignments`, kept separate because
|
|
161
|
+
* a field initialiser is read at the declaration, a property's from its
|
|
162
|
+
* `.ctor` body — different places in the source for the same fact.
|
|
194
163
|
*/
|
|
195
164
|
readonly memberProvenance: Map<string, PendingType>;
|
|
196
165
|
}
|
|
@@ -201,14 +170,10 @@ export interface CsUsing {
|
|
|
201
170
|
readonly alias: string | undefined;
|
|
202
171
|
readonly isStatic: boolean;
|
|
203
172
|
/**
|
|
204
|
-
* `global using …` — in force for
|
|
205
|
-
* this
|
|
206
|
-
*
|
|
207
|
-
*
|
|
208
|
-
* implicit global usings for every project, and an alias declared this way is
|
|
209
|
-
* the language's one construct that binds a name here to a type declared
|
|
210
|
-
* elsewhere without creating a second symbol. Treating it as file-local would
|
|
211
|
-
* make every name it introduces unresolvable everywhere else.
|
|
173
|
+
* `global using …` — in force for every file in the project, not just this
|
|
174
|
+
* one. Modern C# (.NET 6+ implicit global usings) leans on this heavily;
|
|
175
|
+
* treating it as file-local would make every name it introduces
|
|
176
|
+
* unresolvable elsewhere.
|
|
212
177
|
*/
|
|
213
178
|
readonly isGlobal: boolean;
|
|
214
179
|
readonly line: number;
|
|
@@ -225,15 +190,10 @@ export interface CsFile {
|
|
|
225
190
|
readonly assembly: string;
|
|
226
191
|
}
|
|
227
192
|
/**
|
|
228
|
-
* The type a type expression names.
|
|
229
|
-
*
|
|
230
|
-
* `
|
|
231
|
-
*
|
|
232
|
-
* `string` — the single type named, as written, generic arguments dropped.
|
|
233
|
-
*
|
|
234
|
-
* Generic arguments are dropped deliberately: `List<Order>` names `List`, and
|
|
235
|
-
* `Order` inside it is a separate reference the walker records on its own. A
|
|
236
|
-
* single collapsed name would attribute the collection's methods to its element.
|
|
193
|
+
* The type a type expression names. `undefined` = none (predefined/`var`/absent),
|
|
194
|
+
* `null` = named but ambiguous, `string` = the type, generics dropped
|
|
195
|
+
* (`List<Order>` -> `List`; `Order` is recorded as its own reference —
|
|
196
|
+
* collapsing both would attribute the collection's methods to its element).
|
|
237
197
|
*/
|
|
238
198
|
export declare function typeName(node: Node | null | undefined): string | null | undefined;
|
|
239
199
|
export declare function readFile(root: Node, file: string, hasError: boolean): CsFile;
|
package/dist/parse.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"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"}
|
package/dist/parse.js
CHANGED
|
@@ -1,31 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* One C# file, read into the shape the resolver wants.
|
|
3
3
|
*
|
|
4
|
-
* Hand-written walk, as in Java
|
|
5
|
-
*
|
|
6
|
-
* discards it.
|
|
4
|
+
* Hand-written walk, as in Java/Go/Rust/PHP: containment is what a resolver
|
|
5
|
+
* needs, and a query's match set discards exactly that.
|
|
7
6
|
*
|
|
8
|
-
*
|
|
7
|
+
* What C# changes:
|
|
8
|
+
* - A type may be declared in several files (`partial class`) — DEC-083
|
|
9
|
+
* settles identity, this reader only collects the parts.
|
|
10
|
+
* - `using` imports a namespace, not one type (unlike PHP's `use`), so a bare
|
|
11
|
+
* name is resolved outward through enclosing namespaces then imports —
|
|
12
|
+
* found in two places is an ambiguity to disclose, not a tie to break.
|
|
13
|
+
* - The base list doesn't say which entry is the class. DEC-084: at most one
|
|
14
|
+
* base class, required first, so later entries are interfaces
|
|
15
|
+
* unconditionally and only the first ever needs resolving. `IFoo` isn't read.
|
|
9
16
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* - **A type may be declared in several files.** `partial class` is the first
|
|
14
|
-
* construct in this project whose declaration is legitimately multi-file and
|
|
15
|
-
* says so in the source. DEC-083 settles the identity question; this reader
|
|
16
|
-
* only has to collect the parts.
|
|
17
|
-
* - **`using` imports a namespace, not a type.** PHP's `use` names one class
|
|
18
|
-
* and resolves in one step. C#'s brings in every type in a namespace, so a
|
|
19
|
-
* bare name is resolved by searching the enclosing namespaces outward and
|
|
20
|
-
* then each import — which means a name may be found in two places, and
|
|
21
|
-
* that is an ambiguity to disclose rather than a tie to break.
|
|
22
|
-
* - **The base list does not say which entry is the class.** DEC-084 decides
|
|
23
|
-
* it: at most one base class, and the language requires it first, so entries
|
|
24
|
-
* after the first are interfaces unconditionally and only one entry per
|
|
25
|
-
* class declaration ever needs resolving. The `IFoo` convention is not read.
|
|
26
|
-
*
|
|
27
|
-
* Nested types are ordinary here in a way they are not in PHP, so a type carries
|
|
28
|
-
* its nesting path rather than a single name.
|
|
17
|
+
* Nested types are ordinary here (unlike PHP), so a type carries its nesting
|
|
18
|
+
* path, not a single name.
|
|
29
19
|
*/
|
|
30
20
|
/** Keywords that name no user type. `var` is handled separately. */
|
|
31
21
|
const PREDEFINED = new Set([
|
|
@@ -34,15 +24,10 @@ const PREDEFINED = new Set([
|
|
|
34
24
|
"void", "dynamic", "nint", "nuint", "var",
|
|
35
25
|
]);
|
|
36
26
|
/**
|
|
37
|
-
* The type a type expression names.
|
|
38
|
-
*
|
|
39
|
-
* `
|
|
40
|
-
*
|
|
41
|
-
* `string` — the single type named, as written, generic arguments dropped.
|
|
42
|
-
*
|
|
43
|
-
* Generic arguments are dropped deliberately: `List<Order>` names `List`, and
|
|
44
|
-
* `Order` inside it is a separate reference the walker records on its own. A
|
|
45
|
-
* single collapsed name would attribute the collection's methods to its element.
|
|
27
|
+
* The type a type expression names. `undefined` = none (predefined/`var`/absent),
|
|
28
|
+
* `null` = named but ambiguous, `string` = the type, generics dropped
|
|
29
|
+
* (`List<Order>` -> `List`; `Order` is recorded as its own reference —
|
|
30
|
+
* collapsing both would attribute the collection's methods to its element).
|
|
46
31
|
*/
|
|
47
32
|
export function typeName(node) {
|
|
48
33
|
if (node === null || node === undefined)
|
|
@@ -93,18 +78,12 @@ function hasModifier(node, keyword) {
|
|
|
93
78
|
return false;
|
|
94
79
|
}
|
|
95
80
|
/**
|
|
96
|
-
* `[Fact]`, `[Theory]`, `[Xunit.Fact]` -> the last segment,
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
* That is the third instance of one shape in this adapter set — identity
|
|
103
|
-
* normalises, fidelity preserves, and both readings are correct for different
|
|
104
|
-
* consumers. The first two were a property's written type (`string` against
|
|
105
|
-
* `string?`) and a base list's generic argument
|
|
106
|
-
* (`IEntityTypeConfiguration<Order>`). Each collapse surfaced downstream as a
|
|
107
|
-
* clean zero rather than as an error, so both are carried side by side now.
|
|
81
|
+
* `[Fact]`, `[Theory]`, `[Xunit.Fact]` -> the last segment, and its arguments.
|
|
82
|
+
* Names alone were enough while `isTest` was the only consumer; a framework
|
|
83
|
+
* extractor needs the other half — `[Route("System/ActivityLog")]` collapses
|
|
84
|
+
* to `Route`, and the dropped argument *is* the route. Third instance of
|
|
85
|
+
* identity-normalises/fidelity-preserves in this adapter (after a property's
|
|
86
|
+
* written type and a base list's generic argument).
|
|
108
87
|
*/
|
|
109
88
|
function attributeArgumentsOf(node) {
|
|
110
89
|
const found = {};
|
|
@@ -178,11 +157,9 @@ function describeReceiver(node) {
|
|
|
178
157
|
return typeof named === "string" ? { written: undefined, type: named } : { written: undefined, opaque: true };
|
|
179
158
|
}
|
|
180
159
|
case "conditional_access_expression": {
|
|
181
|
-
// `x?.y.z()`
|
|
182
|
-
// chain
|
|
183
|
-
//
|
|
184
|
-
// machinery below do the work; falling through to `default` made every
|
|
185
|
-
// such receiver opaque, and before the flag above existed, implicit.
|
|
160
|
+
// `x?.y.z()` / `a?[0].F()`: null-conditional changes only whether the
|
|
161
|
+
// chain evaluates, not what it denotes (`x?.y` names what `x.y` names).
|
|
162
|
+
// Unwrapping here reuses the member-access machinery below.
|
|
186
163
|
const object = describeReceiver(node.namedChild(0));
|
|
187
164
|
const binding = node.namedChild(1);
|
|
188
165
|
if (binding?.type !== "member_binding_expression") {
|
|
@@ -199,11 +176,10 @@ function describeReceiver(node) {
|
|
|
199
176
|
};
|
|
200
177
|
}
|
|
201
178
|
case "member_access_expression": {
|
|
202
|
-
// `this._repository.FindById()`
|
|
203
|
-
//
|
|
204
|
-
//
|
|
205
|
-
//
|
|
206
|
-
// tries it as a qualified name first.
|
|
179
|
+
// `this._repository.FindById()` (type on the member decl) vs.
|
|
180
|
+
// `Shop.Orders.Money.Format()` (a namespace path) are both this node
|
|
181
|
+
// type — telling them apart needs the resolver, so the whole written
|
|
182
|
+
// path is handed over and tried as a qualified name first.
|
|
207
183
|
const object = describeReceiver(node.childForFieldName("expression"));
|
|
208
184
|
const member = node.childForFieldName("name");
|
|
209
185
|
if (member === null)
|
|
@@ -257,15 +233,10 @@ function callSignature(node) {
|
|
|
257
233
|
return undefined;
|
|
258
234
|
}
|
|
259
235
|
/**
|
|
260
|
-
* The first argument of an invocation, only when
|
|
261
|
-
*
|
|
262
|
-
*
|
|
263
|
-
*
|
|
264
|
-
* `string_literal` when the call site wrote one, an `identifier` or anything
|
|
265
|
-
* else otherwise. `"abc"` -> `abc`; a concatenation or interpolated string
|
|
266
|
-
* (`$"..."`, `interpolated_string_expression`) returns `undefined` rather than
|
|
267
|
-
* the fragment it can see, the same refusal-not-guess DEC-127 already applies
|
|
268
|
-
* to Java's read of the identical shape.
|
|
236
|
+
* The first argument of an invocation, only when a bare string literal.
|
|
237
|
+
* Mirrors Java's `firstStringArgumentOf`: `"abc"` -> `abc`; a concatenation
|
|
238
|
+
* or interpolated string (`$"..."`) returns `undefined` rather than a
|
|
239
|
+
* fragment — DEC-127's refusal-not-guess, same as Java's identical shape.
|
|
269
240
|
*/
|
|
270
241
|
function firstStringArgumentOf(invocation) {
|
|
271
242
|
const args = invocation.childForFieldName("arguments");
|
|
@@ -339,10 +310,9 @@ function pushInvocation(scope, node) {
|
|
|
339
310
|
...(receiver.call === undefined ? {} : { receiverCall: receiver.call }),
|
|
340
311
|
line: node.startPosition.row + 1,
|
|
341
312
|
raw: node.text.slice(0, 200),
|
|
342
|
-
// Spread
|
|
343
|
-
// absent from present-and-undefined
|
|
344
|
-
//
|
|
345
|
-
// would wrongly mean "a call whose first argument is nothing."
|
|
313
|
+
// Spread, not assigned: `exactOptionalPropertyTypes` distinguishes
|
|
314
|
+
// absent ("not worth reading further") from present-and-undefined
|
|
315
|
+
// ("a call whose first argument is nothing").
|
|
346
316
|
...(literal === undefined ? {} : { firstStringArgument: literal }),
|
|
347
317
|
...(argumentText === undefined ? {} : { firstArgumentText: argumentText }),
|
|
348
318
|
});
|
|
@@ -360,13 +330,10 @@ function pushInvocation(scope, node) {
|
|
|
360
330
|
});
|
|
361
331
|
}
|
|
362
332
|
/**
|
|
363
|
-
* A `variable_declarator`'s
|
|
364
|
-
*
|
|
365
|
-
*
|
|
366
|
-
*
|
|
367
|
-
* (DEC-164) even when the field's type is written explicitly, so this is a
|
|
368
|
-
* standalone reader rather than folded into `recordDeclarator`'s own `var`
|
|
369
|
-
* branch.
|
|
333
|
+
* A `variable_declarator`'s initialiser, whether or not its type was written
|
|
334
|
+
* explicitly. `recordDeclarator` only needs this for `var`, but a field's
|
|
335
|
+
* inline initialiser matters to the client-base extractor (DEC-164) even
|
|
336
|
+
* with an explicit type, hence a standalone reader.
|
|
370
337
|
*/
|
|
371
338
|
function initialiserOf(declarator) {
|
|
372
339
|
let initialiser;
|
|
@@ -454,12 +421,11 @@ function walkBody(node, scope) {
|
|
|
454
421
|
pushInvocation(scope, current);
|
|
455
422
|
break;
|
|
456
423
|
case "assignment_expression": {
|
|
457
|
-
// `Client = factory.CreateClient(...)`
|
|
458
|
-
//
|
|
459
|
-
//
|
|
460
|
-
//
|
|
461
|
-
//
|
|
462
|
-
// purely to remember *which name the result was bound to*.
|
|
424
|
+
// `Client = factory.CreateClient(...)` / `this.Client = ...`: only
|
|
425
|
+
// the client-base extractor (DEC-164) reads this, only from a
|
|
426
|
+
// `.ctor`'s scope. The invocation is walked normally regardless and
|
|
427
|
+
// produces its own `CsRef`; this exists only to remember which name
|
|
428
|
+
// the result was bound to.
|
|
463
429
|
const left = current.childForFieldName("left");
|
|
464
430
|
const right = current.childForFieldName("right");
|
|
465
431
|
if (left !== null && right !== null && right.type === "invocation_expression") {
|
|
@@ -493,12 +459,10 @@ function walkBody(node, scope) {
|
|
|
493
459
|
break;
|
|
494
460
|
}
|
|
495
461
|
case "declaration_pattern": {
|
|
496
|
-
// `if (item is Folder folder)`
|
|
497
|
-
//
|
|
498
|
-
//
|
|
499
|
-
//
|
|
500
|
-
// jellyfin's `MetadataService.GetChildrenForMetadataUpdates` is the
|
|
501
|
-
// canonical shape, and it is idiomatic modern C# rather than a corner.
|
|
462
|
+
// `if (item is Folder folder)` / `case Folder folder:` binds a local
|
|
463
|
+
// whose type is written right there — previously disclosed as an
|
|
464
|
+
// untyped receiver, honest but wasteful. Idiomatic modern C#
|
|
465
|
+
// (jellyfin's `MetadataService.GetChildrenForMetadataUpdates`), not a corner.
|
|
502
466
|
const declared = typeName(current.namedChild(0));
|
|
503
467
|
const bound = current.namedChild(1)?.text.trim();
|
|
504
468
|
if (bound !== undefined)
|
|
@@ -531,10 +495,9 @@ function walkBody(node, scope) {
|
|
|
531
495
|
break;
|
|
532
496
|
}
|
|
533
497
|
case "member_access_expression": {
|
|
534
|
-
// `Status.Pending`, `Order.Empty` — a type referenced as a value
|
|
535
|
-
//
|
|
536
|
-
// the resolver decides
|
|
537
|
-
// declines when it is neither.
|
|
498
|
+
// `Status.Pending`, `Order.Empty` — a type referenced as a value
|
|
499
|
+
// (golden pattern 13). Recorded only when the holder is a bare name;
|
|
500
|
+
// the resolver decides type vs. variable, declining if neither.
|
|
538
501
|
const holder = current.childForFieldName("expression");
|
|
539
502
|
if (holder !== null && (holder.type === "identifier" || holder.type === "qualified_name")) {
|
|
540
503
|
scope.refs.push({
|
|
@@ -748,10 +711,8 @@ export function readFile(root, file, hasError) {
|
|
|
748
711
|
const field = declarator.childForFieldName("name")?.text.trim();
|
|
749
712
|
if (field !== undefined)
|
|
750
713
|
members.set(field, declared ?? null);
|
|
751
|
-
//
|
|
752
|
-
//
|
|
753
|
-
// `CleanArchitecture`'s `private readonly HttpClient _client =
|
|
754
|
-
// factory.CreateClient();` is the measured shape.
|
|
714
|
+
// Client-base extractor (DEC-164): a field's inline initialiser
|
|
715
|
+
// when traceable — CleanArchitecture's measured shape.
|
|
755
716
|
if (field !== undefined) {
|
|
756
717
|
const initialiser = initialiserOf(declarator);
|
|
757
718
|
if (initialiser?.type === "invocation_expression") {
|
|
@@ -812,9 +773,8 @@ export function readFile(root, file, hasError) {
|
|
|
812
773
|
continue;
|
|
813
774
|
}
|
|
814
775
|
if (child.type === "file_scoped_namespace_declaration") {
|
|
815
|
-
// `namespace Shop.Orders;` — no body
|
|
816
|
-
//
|
|
817
|
-
// is the modern default and permits exactly one namespace per file.
|
|
776
|
+
// `namespace Shop.Orders;` — no body; remaining siblings are inside
|
|
777
|
+
// it. Modern default, permits exactly one namespace per file.
|
|
818
778
|
const name = child.childForFieldName("name")?.text.trim();
|
|
819
779
|
const nested = name === undefined ? enclosing : enclosing === "" ? name : `${enclosing}.${name}`;
|
|
820
780
|
if (namespaceName === "" && nested !== "")
|
|
@@ -832,10 +792,9 @@ export function readFile(root, file, hasError) {
|
|
|
832
792
|
return;
|
|
833
793
|
}
|
|
834
794
|
if (child.type === "namespace_declaration") {
|
|
835
|
-
// Block form. A file may legally declare several
|
|
836
|
-
// the
|
|
837
|
-
//
|
|
838
|
-
// namespace they do not have.
|
|
795
|
+
// Block form. A file may legally declare several; this reader takes
|
|
796
|
+
// the first (disclosed simplification) — types after a second block
|
|
797
|
+
// would be given a namespace they don't have.
|
|
839
798
|
const name = child.childForFieldName("name")?.text.trim();
|
|
840
799
|
const nested = name === undefined ? enclosing : enclosing === "" ? name : `${enclosing}.${name}`;
|
|
841
800
|
if (namespaceName === "" && nested !== "")
|