@groma/scanner-vue 0.1.3 → 0.1.5

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.
Files changed (3) hide show
  1. package/README.md +149 -6
  2. package/dist/index.js +1658 -33
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -1,9 +1,9 @@
1
1
  # Vue scanner
2
2
 
3
3
  The Vue scanner adds single-file component (SFC) event bindings to Groma's
4
- TypeScript scanner evidence. Install the project's dependencies using its
5
- package manager and lockfile. The scanner reads each selected project's `tsconfig.json`;
6
- it does not install dependencies or execute application code.
4
+ TypeScript scanner evidence. Its bundled compiler tools read local source
5
+ without project dependencies. The scanner reads each selected project's
6
+ `tsconfig.json`; it does not execute application code.
7
7
 
8
8
  ```sh
9
9
  bun install --frozen-lockfile --ignore-scripts
@@ -32,6 +32,26 @@ supplied-callback evidence contract; it has no separate name or type resolver.
32
32
 
33
33
  ## Supported interaction
34
34
 
35
+ ### External source blocks
36
+
37
+ A `.vue` file can explicitly name local external script, template, and style
38
+ files with `src="./file"` or `src="../file"`, as described in the
39
+ [Vue SFC specification](https://vuejs.org/api/sfc-spec#src-imports).
40
+ The scanner reports those direct companions as one source unit. Core assigns
41
+ one component when ownership is unambiguous and preserves curated membership
42
+ on repeats. Code details expose the `.vue` file and every companion.
43
+ Imports from the script, global styles, transitive stylesheet imports, and
44
+ similarly named neighboring files do not extend that association.
45
+
46
+ Inline blocks create no extra files. External scripts cannot be combined with
47
+ `script setup`; Vue's [script setup restrictions](https://vuejs.org/api/sfc-script-setup#restrictions)
48
+ still apply. External block association does not add Options API or external
49
+ template event inference; the inline interaction rule below remains unchanged.
50
+ Edits to JavaScript, TypeScript, HTML, CSS, SCSS, Sass, Less, and Stylus companions
51
+ trigger the existing shared scanner refresh.
52
+
53
+ ### Inline event bindings
54
+
35
55
  The qualified example is Vue REPL's CodeMirror `change` event bound to the
36
56
  parent's `onChange` function. A static imported SFC must use a typed
37
57
  `defineEmits` declaration assigned to a constant. A call to that same symbol
@@ -51,7 +71,8 @@ Options API events, runtime `defineEmits` arrays, dynamic components, dynamic
51
71
  event names, handler expressions or modifiers, state stores, routing, server
52
72
  frameworks or arbitrary event mutation. Compiler syntax/template errors fail
53
73
  the scan and preserve the previous complete map. Readiness errors explain
54
- missing project dependencies or invalid configuration.
74
+ invalid configuration or source syntax. Typed event names are read from the
75
+ local `defineEmits` type literal; missing Vue types do not erase that evidence.
55
76
 
56
77
  Vue contributes `vue` Code provenance for configured source files. Shared core
57
78
  keeps one physical-file owner, interprets complementary and conflicting
@@ -63,9 +84,131 @@ is source evidence; it does not automatically define a C4 responsibility or
63
84
  add a containment level. Groma's existing ownership and relationship model
64
85
  owns that interpretation. No new architecture metadata is added.
65
86
 
66
- See [validation](validation.md) for the pinned project and executed release
87
+ See [fresh-checkout validation](../fresh-checkout-validation.md) for the pinned project and executed release
67
88
  checks. This prototype package name does not imply public publication.
68
89
 
90
+ ## Source outline
91
+
92
+ The scanner outlines every script it owns in a component's Code with the
93
+ TypeScript rules of the [source outline contract](../creating-a-plugin.md#source-outline):
94
+ top-level functions and types (classes, interfaces, enums), including namespace
95
+ contents, and each type's constructors and methods. Every declaration has its
96
+ line and visibility, and `entry` marks the names the Code links give. Templates
97
+ and stylesheets have no outline.
98
+
99
+ A single-file component is read with the Vue single-file component parser: the
100
+ `<script>` and `<script setup>` blocks are outlined in source order, each in the
101
+ dialect its `lang` attribute names, and every declaration reports the line it
102
+ occupies in the `.vue` file. A `<script setup>` block exports nothing, because
103
+ its top-level bindings are the component's own API for its template, so its
104
+ top-level declarations are private; members keep their TypeScript visibility.
105
+ The package's own TypeScript parses each block alone, without `tsconfig.json`,
106
+ dependencies or compilation.
107
+
108
+ Core outlines each file once. For a script that the TypeScript scanner also
109
+ owns, the scanner with the lowest id among the file's Code links outlines it,
110
+ here TypeScript, with the symbols of all those links.
111
+
112
+ ## HTTP endpoints and requests
113
+
114
+ The scanner reports [HTTP facts](../evidence.md#http-endpoints-and-requests) for
115
+ the clients it recognizes in the files it reads, single-file component scripts
116
+ included, and for the endpoints a Nuxt project declares by file location. A fact
117
+ from a `.vue` file names an operation in that file, at the line the call occupies
118
+ there.
119
+
120
+ | Construct | Reported |
121
+ | --- | --- |
122
+ | `fetch(url, options)`, `$fetch(url, options)`, `useFetch(url, options)` | Request; a literal `method` gives the method, no options means `GET`, and options the scanner cannot read leave it out |
123
+ | `$fetch` and `useFetch` with a `baseURL` option | Request whose path follows that base |
124
+ | `axios.get`, `.post`, `.put`, `.patch`, `.delete`, `.head`, `.options` | Request with that method |
125
+ | `axios(config)`, `axios.request(config)` | Request from the config's `url`; its `method`, else the client's, else `GET` |
126
+ | `axios.create(config)` instances | Request whose path follows the config's `baseURL`, and whose method defaults to the config's |
127
+ | `server/api/**` | Endpoint at `/api/...`, with the method its file name states |
128
+ | `server/routes/**` | Endpoint at the path after `server/routes`, with the method its file name states |
129
+
130
+ `fetch` counts when it is the runtime's or the default export of `node-fetch`,
131
+ as on the React page. `$fetch` and `useFetch` must resolve to a declaration
132
+ outside the project source, such as an installed package's types, so a project's
133
+ own `useFetch` composable, whose body decides the URL, is never read as Nuxt's;
134
+ a project scanned without its dependencies installed therefore reports no
135
+ `$fetch` or `useFetch` request. They read their `baseURL` option as axios reads
136
+ a request's own, except that, as ofetch does, they keep a URL whose text already
137
+ starts with a literal base followed by `/`, `?` or its end; where that boundary
138
+ falls on a computed part, the path starts unknown. Everything else, from the
139
+ axios clients and their `defaults` to the options, the `fetch` inputs and the
140
+ bases, follows the rules of the [React
141
+ scanner](../react/index.md#http-endpoints-and-requests).
142
+
143
+ The endpoints need the project to declare `nuxt`: another server that happens to
144
+ live in `server/` serves paths of its own, which these locations would misstate.
145
+
146
+ The [producer decisions](../evidence.md#producer-checklist) for this ecosystem:
147
+
148
+ 1. **Prefixes.** A server route under `server/api` serves below `/api`, which its
149
+ endpoint path states; one under `server/routes` serves from the root. On the
150
+ client side, only a `baseURL`, as the options and axios clients above state it,
151
+ precedes a path.
152
+ 2. **Endpoints.** Only the server route files above, and only in a project that
153
+ declares `nuxt`. `server/middleware/**`, `server/plugins/**`, a component, and
154
+ a page answer no request of their own. Nuxt serves every route file, so each
155
+ reports its endpoint, whatever its default export is.
156
+ 3. **Dynamic or unknown.** `` `/talks/${id}` `` fills one whole segment, so it is
157
+ dynamic. `` `/talks/${id}-latest` ``, a path built from a parameter, and an
158
+ unresolvable value are unknown. The query and fragment are dropped, computed or
159
+ not. A method the scanner cannot read leaves the fact without one, rather than
160
+ claiming `GET`.
161
+ 4. **Local helpers.** Not supported: the URL is read at the client call, so a
162
+ helper that forwards a path parameter reports unknown text, and its callers
163
+ report nothing. Author those rows.
164
+ 5. **Bases.** The [React
165
+ scanner's](../react/index.md#http-endpoints-and-requests) decision 5 holds
166
+ unchanged.
167
+ 6. **File-location routes.** A route file's path after `server/` is its served
168
+ path, read as Nitro names its routes: a route group directory such as
169
+ `(admin)` serves no segment, an environment suffix such as `.prod` and then a
170
+ `.get`, `.post`, `.put`, `.patch`, `.delete`, `.head`, `.options`, `.connect`
171
+ or `.trace` method suffix leave the path, a final `index` serves its
172
+ directory, and placeholders read as decision 7 describes. A file without a
173
+ method suffix answers every method. `.js`, `.mjs`, `.cjs`, `.ts`, `.mts`,
174
+ `.cts`, `.jsx` and `.tsx` route files count. The endpoint names the function
175
+ the default export designates: a default-exported function, or a function the
176
+ file declares, as a function or a variable holding one, that the default
177
+ export names or passes to a wrapper such as `defineEventHandler`. When it
178
+ designates no such function, the endpoint names the file's module operation.
179
+ A request in a file's own top-level code, which is what `<script setup>` runs
180
+ on setup, names that file's module operation, so the row starts at the
181
+ component.
182
+ 7. **Constrained segments.** Nitro constrains no segment, and segments follow
183
+ the names it registers. A segment that starts with a placeholder, such as
184
+ `[id]` or `[id]-latest`, is a parameter that accepts any text, named `*` when
185
+ no name can spell it. Text before a placeholder makes the whole segment
186
+ literal, so `hello-[name]` serves only `/hello-:name`. `[...]` and
187
+ `[...slug]`, whose name is word characters, are catch-alls, while
188
+ `[...file-path]` is a parameter. A segment the scanner cannot state, such as
189
+ a catch-all before the last segment, becomes a constrained optional catch-all
190
+ in place of itself and the rest of the path.
191
+ 8. **Registration order.** None: Nuxt prefers the most specific route, whatever
192
+ order its files are in.
193
+
194
+ ## Compared operations
195
+
196
+ `groma lint` and scan findings compare the functions in the `<script>` and
197
+ `<script setup>` blocks of a single-file component under the
198
+ [shared rule](../../architecture-findings.md#compared-operations). The Vue,
199
+ JavaScript and TypeScript scanners share one rule and one tokenizer, so the
200
+ operations the [TypeScript scanner](../typescript/index.md#compared-operations)
201
+ compares, those it does not compare yet, and the tokens it keeps apply here too,
202
+ and one body compares equal in a component script and in a module.
203
+
204
+ In a component, the source range is in the `.vue` file's own lines. The
205
+ functions a `<script setup>` block exposes to its template are compared.
206
+ `setup()` on the argument of `defineComponent({ ... })` is an anonymous callback,
207
+ while the methods under its `methods` property are compared. Top-level statements
208
+ of a block are initializer code, and template expressions are not operations.
209
+ Scripts the component keeps in a separate file are TypeScript modules, which the
210
+ TypeScript scanner compares.
211
+
69
212
  ## Nested projects
70
213
 
71
214
  Run Groma from the repository root. The scanner finds package declarations in
@@ -74,7 +217,7 @@ dev dependencies, peer dependencies and optional dependencies identify candidate
74
217
  A candidate also needs a tracked or unignored `tsconfig.json` and Vue source
75
218
  files belonging to that package, outside nested packages. Declaration files and
76
219
  inactive fixtures with a `.fixture` suffix do not qualify. Packages with only
77
- framework tooling dependencies are skipped. No matching project produces no evidence. Each compiler uses that project's configuration and installed dependencies;
220
+ framework tooling dependencies are skipped. No matching project produces no evidence. Each compiler uses that project's configuration and local source;
78
221
  imported source in sibling repository libraries keeps its original source path.
79
222
  Readiness checks all selected projects. An invalid selected project fails this scanner's observation; other scanners
80
223
  can still update the architecture.