@groma/scanner-react 0.1.5 → 0.2.1

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/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # React scanner
2
2
 
3
- The React scanner connects a directly supplied JSX callback prop to calls on
4
- the component's destructured parameter. Enable it alongside the TypeScript scanner.
3
+ The React scanner connects a callback that a JSX element supplies as a prop to
4
+ the component's calls of that prop. Enable it alongside the TypeScript scanner.
5
5
  Core selects relationships from the combined evidence and keeps one owner per
6
6
  physical source file.
7
7
 
@@ -20,15 +20,27 @@ groma scanner check
20
20
  groma scan
21
21
  ```
22
22
 
23
- The private prototype package bundles TypeScript 6.0.3 and its standard-library
24
- declarations. the TypeScript scanner's 7.1 SDK is unchanged. No consumer build
23
+ The private prototype package bundles TypeScript 6.0 and its standard-library
24
+ declarations. The TypeScript scanner keeps its native TypeScript 7 SDK. No consumer build
25
25
  or installation script is required. Public naming and publication are separate
26
26
  release decisions.
27
27
 
28
- The scanner reads each selected project's `tsconfig.json` and owned TSX files
29
- using its bundled TypeScript compiler. Project dependencies and React types do
30
- not need to be installed. Invalid configuration and source syntax fail with a
31
- diagnostic; missing external types do not prevent local callback extraction.
28
+ The scanner reads each selected package's nearest `tsconfig.json` and owned TSX
29
+ files using its bundled TypeScript compiler. It reads only the files groma.md
30
+ hands it, never declaration files as sources, and a syntax error only fails the
31
+ scan in a file it reads. The package declares the default
32
+ [include and exclude lists](../index.md#selecting-source-files): it includes
33
+ `.ts` and `.tsx` sources, `tsconfig*.json` configs, and the `package.json`, HTML,
34
+ `project.json` and `nx.json` files the entry reader reads, and excludes `.test`
35
+ and `.spec` files, the root `test` folder, and `node_modules`, `dist`, `build`
36
+ and `coverage` folders. Project dependencies and
37
+ React types do not need to be installed. A solution `tsconfig.json` that names no source of its
38
+ own compiles through the first config it references that compiles one of its
39
+ components. An extended config a fresh
40
+ checkout lacks, such as an uninstalled package or a generated file, leaves the
41
+ config's own settings and reports a `react-missing-config-base` warning.
42
+ Invalid configuration and source syntax fail with a diagnostic; missing external
43
+ types do not prevent local callback extraction.
32
44
  The scanner does not run application code or require successful type checking.
33
45
 
34
46
  ## Evidence and tooling
@@ -36,17 +48,29 @@ The scanner does not run application code or require successful type checking.
36
48
  [React documents callback props](https://react.dev/learn/responding-to-events).
37
49
  [TypeScript owns JSX parsing and checking](https://www.typescriptlang.org/docs/handbook/jsx.html),
38
50
  project membership, imported component identities, and source symbols.
39
- The adapter uses the maintained JavaScript compiler API pinned to 6.0.3;
40
- [TypeScript 6.0](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-6-0.html)
41
- retains the established compiler API. The plugin does not recreate language
51
+ The adapter uses the classic compiler API of its bundled
52
+ [TypeScript 6.0](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-6-0.html),
53
+ the last release that retains it. The plugin does not recreate language
42
54
  name or type resolution.
43
55
 
44
- A component must resolve to a source function or a `const` arrow/function value
45
- in the inventoried TSX files. Its first parameter must directly destructure the
46
- callback prop. The JSX attribute must supply an identifier resolving directly
47
- to a source function or `const` arrow/function value. Calls are matched to the
48
- exact compiler symbol of that destructured parameter. Each concrete JSX
49
- attribute has a separate binding; nested calls belong to their nearest function.
56
+ A component, and a handler the JSX attribute names, must resolve to a source
57
+ function in the files the scanner reads, or to a `const` holding one. React's
58
+ `useCallback`, `memo` and `forwardRef` hand back the function they are given, so
59
+ a `const` holding such a call holds that function; they count only when imported
60
+ from `react`, by name or through its module object. A handler may also be a
61
+ function written in place, and a TypeScript module may hold it; that module then
62
+ joins the scanner's files. The component reads the callback prop from its first
63
+ parameter, by destructuring it, with or without a default, or as a property of
64
+ that parameter, such as `props.onSave()`. Calls are matched to the exact
65
+ compiler symbol of the destructured prop or the props parameter. Each concrete
66
+ JSX attribute has a separate binding; nested calls belong to their nearest
67
+ function, method or accessor.
68
+
69
+ In a project whose tsconfig sets `moduleSuffixes`, as React Native projects do,
70
+ the compiler resolves each import for one platform. A file named for a platform,
71
+ by one of those suffixes or `.web`, such as `Menu.web.tsx`, binds only to
72
+ components of its own platform, or to a shared file beside which its platform
73
+ has no file of its own.
50
74
 
51
75
  Operation, call, and attribute positions are original zero-based UTF-16 offsets;
52
76
  lines are one-based. The named prop supplies the existing `member` field.
@@ -81,22 +105,23 @@ here React, with the symbols of all those links.
81
105
  The scanner reports [HTTP facts](../evidence.md#http-endpoints-and-requests) for
82
106
  the clients it recognizes in the TSX files it reads, and for the endpoints a
83
107
  Next.js project declares by file location. In a project that declares `next`, it
84
- also reads `app/**/route.ts` and `.tsx` and `pages/api/**`, which another scanner
108
+ also reads `app/**/route.ts` and `.tsx` and `pages/api/**`, including route files
109
+ the tsconfig leaves out, such as a `.well-known` directory, which another scanner
85
110
  may read as well. Next.js reads each of `app` and `pages` from the project root,
86
111
  or from `src` only when the root has none, so a `src/app` beside a root `app`
87
112
  serves nothing.
88
113
 
89
114
  | Construct | Reported |
90
115
  | --- | --- |
91
- | `fetch(url, init)`, including a `node-fetch` default import | Request; a literal `method` gives the method, no options means `GET`, and options the scanner cannot read leave it out |
92
- | `axios.get`, `.post`, `.put`, `.patch`, `.delete`, `.head`, `.options` | Request with that method |
116
+ | `fetch(url, init)`, including a `node-fetch` default import or a named `undici` import | Request; a literal `method` gives the method, no options means `GET`, and options the scanner cannot read leave it out |
117
+ | `axios.get`, `.post`, `.put`, `.patch`, `.delete`, `.head`, `.options`, `.postForm`, `.putForm`, `.patchForm` | Request with that method; form helpers use their matching HTTP method |
93
118
  | `axios(config)`, `axios.request(config)` | Request from the config's `url`; its `method`, else the client's, else `GET` |
94
119
  | `axios.create(config)` instances | Request whose path follows the config's `baseURL`, and whose method defaults to the config's |
95
- | `app/**/route.ts` | Endpoint per exported `GET`, `POST`, `PUT`, `PATCH`, `DELETE`, `HEAD` or `OPTIONS` handler, at the route's directory path |
120
+ | `app/**/route.ts` | Endpoint per exported `GET`, `POST`, `PUT`, `PATCH`, `DELETE`, `HEAD` or `OPTIONS` handler, including names in an export list, at the route's directory path |
96
121
  | `pages/api/**` | Endpoint for the default export, which answers every method, so `*` |
97
122
 
98
123
  `fetch` counts when it is the runtime's, which the project neither declares nor
99
- imports, or the default export of `node-fetch`, so a `fetch` the project exports
124
+ imports, the default export of `node-fetch`, or a named `undici` import, so a `fetch` the project exports
100
125
  from its own module is that function. An `axios` client counts only when its
101
126
  name is the `axios` default import, or a variable the project never assigns
102
127
  again holding `require('axios')` or `axios.create(...)` called on it, so
@@ -130,9 +155,9 @@ The [producer decisions](../evidence.md#producer-checklist) for this ecosystem:
130
155
  declares `next`. A page, a layout, `middleware.ts`, and a component answer no
131
156
  request of their own, and `pages/api.tsx` is a page, not a route. A route file
132
157
  whose path holds a parallel route `@modal` or an intercepted route `(.)talks`
133
- reports nothing, because the served path is not the file path there. A Pages
134
- Router route whose default export is not a function in that file also reports
135
- nothing.
158
+ reports nothing, because the served path is not the file path there, and a
159
+ private folder such as `_lib` is not routed. An export whose value is a
160
+ literal, such as a configuration object, serves nothing.
136
161
  3. **Dynamic or unknown.** `` `/talks/${id}` `` fills one whole segment, so it is
137
162
  dynamic. `` `/talks/${id}-latest` ``, a path built from a parameter, and an
138
163
  unresolvable value are unknown. The query and fragment are dropped, computed
@@ -166,8 +191,11 @@ The [producer decisions](../evidence.md#producer-checklist) for this ecosystem:
166
191
  segment, so `app/api/(admin)/audit/route.ts` serves `/api/audit`. A Pages
167
192
  Router `index` file serves its directory, while a directory named `index` is an
168
193
  ordinary segment. An App Router endpoint names the exported handler for its
169
- method; a Pages Router endpoint names the function its default export
170
- designates. Every request names the function that runs the call.
194
+ method, and a Pages Router endpoint the function its default export
195
+ designates. A handler the file does not define as a function, such as a
196
+ wrapper's result or an imported handler, is served by the file's module code,
197
+ which the endpoint then names. Every request names the function that runs the
198
+ call, or the module code outside every function.
171
199
  7. **Constrained segments.** None: `[id]`, `[...rest]` and `[[...rest]]` accept
172
200
  any text.
173
201
  8. **Registration order.** None: Next.js prefers the most specific route,
@@ -175,27 +203,34 @@ The [producer decisions](../evidence.md#producer-checklist) for this ecosystem:
175
203
 
176
204
  ## Limits
177
205
 
178
- This revision qualifies the Backlog.md CleanupModal success callback. It does
179
- not analyze hooks, state stores, routing, server components, class components,
180
- component wrappers, callback forwarding, returned functions, mutable values,
181
- DOM dispatch, or arbitrary callback expressions. JSX spreads and unsupported
182
- direct bindings produce `unsupported-react-binding` diagnostics and no certain
183
- claim. Components that cannot resolve to a supported source function do not
206
+ The scanner does not analyze state stores, routing, server components, class
207
+ components, hooks other than `useCallback`, wrappers other than `memo` and
208
+ `forwardRef`, callback forwarding, returned functions, mutable values, DOM
209
+ dispatch, or callback expressions other than a function written in place. A prop the component calls
210
+ that receives anything other than a supported direct binding, and a JSX spread on
211
+ a component that calls a prop from its first parameter, produce `unsupported-react-binding`
212
+ diagnostics and no certain claim. A prop the component never calls is no
213
+ interaction of that component, and declared types, installed or not, decide
214
+ neither result. Components that cannot resolve to a supported source function do not
184
215
  establish a callback interaction.
185
216
 
186
- TSX and TypeScript edits use the existing watch lifecycle. Healthy scanners update the architecture while failed scanners keep their saved evidence. See [fresh-checkout validation](../fresh-checkout-validation.md) for
217
+ A change to a file the include list names triggers a rescan. Healthy scanners update the architecture while failed scanners keep their saved evidence. See [fresh-checkout validation](../fresh-checkout-validation.md) for
187
218
  the executed artifact checks and remaining release gates.
188
219
 
189
220
  ## Nested projects
190
221
 
191
- Run Groma from the repository root. The scanner finds package declarations in
192
- tracked and unignored files, including nested apps and libraries. Dependencies,
193
- dev dependencies, peer dependencies and optional dependencies identify candidates.
194
- A candidate also needs a tracked or unignored `tsconfig.json` and TSX source
195
- files belonging to that package, outside nested packages. Declaration files and
196
- inactive fixtures with a `.fixture` suffix do not qualify. Packages with only
197
- framework tooling dependencies are skipped. No matching project produces no evidence. Each compiler uses that project's configuration and local source;
198
- imported source in sibling repository libraries keeps its original source path.
222
+ Run groma.md from the repository root. The scanner finds package declarations
223
+ among its files, including nested apps and libraries. Dependencies, dev
224
+ dependencies, peer dependencies and optional dependencies identify candidates.
225
+ A candidate also needs a `tsconfig.json` among its files in its directory or a
226
+ repository ancestor, and TSX source files belonging to that package, outside
227
+ nested packages. Declaration files and inactive fixtures with a `.fixture` suffix
228
+ do not qualify. Packages with only framework tooling dependencies are skipped. No
229
+ matching project produces no evidence, and neither does a package whose config
230
+ compiles none of its components, such as one holding only excluded tests. Each compiler uses the nearest config of
231
+ its package; imported source in sibling repository libraries keeps its original
232
+ source path. A file belongs to the nearest React package that contains it, so a
233
+ package whose config also compiles a nested package leaves that package's files
234
+ to it, while components and handlers still resolve across both.
199
235
  Readiness checks all selected projects. An invalid selected project fails this scanner's observation; other scanners
200
236
  can still update the architecture.
201
- Source and nested package/configuration changes use the shared scanner watch flow.