@suss/extractor 0.21.1 → 0.22.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/README.md +40 -0
- package/dist/index.cjs +990 -41
- package/dist/index.d.cts +644 -1
- package/dist/index.d.ts +644 -1
- package/dist/index.js +952 -34
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -105,6 +105,46 @@ The first test asks whether the branch contradicts the guard, not whether the br
|
|
|
105
105
|
|
|
106
106
|
Comparison is by the condition's polarity and the text it was written as, the same key a transition id is built from. An adapter therefore has to spell a guard on an effect the way it spells the same guard on a branch, or the two never meet and the guard is treated as silence.
|
|
107
107
|
|
|
108
|
+
## Extraction cache
|
|
109
|
+
|
|
110
|
+
A second run over an unchanged repository returns the first run's summaries from disk, and a run after an edit re-extracts only the files the edit can affect. The TypeScript adapter keeps the cache in `.suss/cache/` beside the tsconfig, and turns it off for a caller-supplied project; `--no-cache` skips it for one run. This section is the design.
|
|
111
|
+
|
|
112
|
+
The Python and Ruby adapters keep the same on-disk cache, rooted at `.suss/cache/` beside the project root. Neither has a config file of its own to guard an entry the way the TypeScript adapter's tsconfig does, so their key rests on the walked file list and the packs digest alone. Both write an entry with no per-file attribution, so a hit today is whole-run only: any file changing re-extracts the whole project, and per-file reuse for these two adapters is a later change.
|
|
113
|
+
|
|
114
|
+
### The key
|
|
115
|
+
|
|
116
|
+
An entry is only readable by a run that agrees with the one that wrote it on everything that changes what extraction produces. The entry directory's name hashes: the cache schema version, the adapter version plus a content hash of the loaded adapter and analysis bundles, each pack's name, declared version, code hash and config digest, the project files the packs read off disk, the extraction config (`includeReachable`, `gapHandling`), and the config path the adapter supplies (the TypeScript adapter's tsconfig).
|
|
117
|
+
|
|
118
|
+
A pack reads project files no walk ever sees: aws-lambda reads the SAM template that says which handlers exist, and a `packageExports` pattern reads the `package.json` whose `exports` map says which files are on a package's boundary. Editing one of those changes what the run produces while every source file hashes the same, so a pack lists them under `discoveryInputs` and the key takes their paths and their content. Which files they are depends on the files the run walks, so this part of the key is settled per run, after the file list is read and before the lookup. Inside the entry, the config path's own stamp and a stamp per project file guard the rest. A run built from source instead of a bundle has no code hash, and declines to cache at all.
|
|
119
|
+
|
|
120
|
+
### Whole reuse, then per-file reuse
|
|
121
|
+
|
|
122
|
+
The fast path compares stats alone: same mtime and size on the config path and every file means the previous summaries come back verbatim, with no parse and no hashing. When stats moved, the run hashes the moved files' content; a touch that changed nothing becomes a hit. When content did change, the per-file layer takes over: the manifest records, for every walked file, which summaries its walk produced (wherever those summaries' functions live), and which other files that walk read. A file whose own hash and whose recorded reads are all unchanged gets its summaries served from the manifest; everything else is re-extracted with the full project loaded, and the results merge.
|
|
123
|
+
|
|
124
|
+
### What "which other files" means
|
|
125
|
+
|
|
126
|
+
Cross-file reads are recorded from several directions at once:
|
|
127
|
+
|
|
128
|
+
- The files the walked file references directly, which covers the types and helpers it imports itself. The whole import closure was measured and rejected: on a repository with import cycles through its app module, one edited controller invalidated a third of the tree.
|
|
129
|
+
- Every file the resolution store walked while answering a question asked during the file's walk, hop by hop, which covers re-export chains the store followed and values wired up outside the import graph, an injected class constructed in another file among them.
|
|
130
|
+
- The files of every function the reachable closure entered from the file's units, plus one import hop past each, plus what the store answered during those scans.
|
|
131
|
+
- Export tables read and aliases resolved through the module-exports helpers, wherever the resolution landed.
|
|
132
|
+
- The file that claimed a unit this file's walk would otherwise have claimed, since the claim decided what this file's output leaves out.
|
|
133
|
+
- The mount prefixes the walk consumed, re-checked by id against the rebuilt index on every partial run, so a mount added or changed in a file the router never imports still invalidates its routes.
|
|
134
|
+
- The packs that applied to the file, re-checked against the fresh gate on every partial run, so a barrel that starts re-exporting a framework flips the file back to walked.
|
|
135
|
+
|
|
136
|
+
A file declines caching when one of its summaries takes part in a run-level GraphQL join: it has a document label (schema lifting moves SDL between summaries sharing one) or it is an operation (client stamping writes the project-wide sole client onto every one). A code-first resolver joins with nothing and stays cacheable. Summaries built by run-level passes (wrapper-caller expansion, library env-read markers, schema documents) belong to no file and are recomputed on every partial run. Units the cache serves are excluded from closure emission the way a cold run's seeds are, so a re-walked file reaching a cached unit never duplicates it.
|
|
137
|
+
|
|
138
|
+
### What stage one does not promise
|
|
139
|
+
|
|
140
|
+
A type read more than one import hop away, through a chain no recorded mechanism followed, can change a summary's printed types without invalidating it. The middle file of a deep re-export chain has the same hole when the compiler, not the store, resolved the chain. A dependency upgrade under `node_modules` invalidates nothing (the pack and adapter hashes account for library knowledge instead). Recording what each answer read, per answer, is stage two of #422 and closes these.
|
|
141
|
+
|
|
142
|
+
A re-extracted summary can also differ from a cache-free run in one representational way: type-shape expansion shares a per-run memo, so a run that walks five files can expand a shape to a different depth than a run that walks a thousand, and the shape digest moves with it. The summary was computed fresh either way; nothing served is stale.
|
|
143
|
+
|
|
144
|
+
### Invalidation, wholesale
|
|
145
|
+
|
|
146
|
+
The schema version is part of the entry directory's name, so a format change makes every old entry unreachable rather than misread, and the eviction pass deletes it in time. `MAX_ENTRIES` bounds a cache directory at two entries.
|
|
147
|
+
|
|
108
148
|
## Coverage
|
|
109
149
|
|
|
110
150
|

|