@suss/recognize 0.22.4 → 0.24.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 +10 -398
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# @suss/recognize
|
|
2
2
|
|
|
3
|
+
Part of [suss](https://github.com/nimbuscloud-ai/suss), which reads both sides of every call in a repository and says where the two disagree.
|
|
4
|
+
|
|
3
5
|
Write a pack as data. A pack states where a match starts, which methods
|
|
4
6
|
count, and what each one reads or writes; this package compiles that
|
|
5
7
|
into the recognizer hooks the adapters already call, and any adapter
|
|
@@ -31,404 +33,14 @@ Nothing here imports a syntax tree, so the same declaration drives the
|
|
|
31
33
|
TypeScript adapter today and the Python and Ruby adapters once they
|
|
32
34
|
implement the ops.
|
|
33
35
|
|
|
34
|
-
##
|
|
35
|
-
|
|
36
|
-
A pack does four jobs: it discovers units, it recognizes calls inside
|
|
37
|
-
them, it declares terminals, and it claims sub-units. They share one
|
|
38
|
-
spine and differ in what the ending yields.
|
|
39
|
-
|
|
40
|
-
```
|
|
41
|
-
where the match starts -> which method -> read the arguments -> yield
|
|
42
|
-
effects
|
|
43
|
-
a unit
|
|
44
|
-
a terminal
|
|
45
|
-
a sub-unit
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
Two endings are built, and both of them yield effects: one asks the
|
|
49
|
-
call what it reached, and one reads the statement the call was handed.
|
|
50
|
-
Discovery, terminals and sub-units are further members of `Ending` with
|
|
51
|
-
an entry in the compile table.
|
|
52
|
-
|
|
53
|
-
### Where a match starts
|
|
54
|
-
|
|
55
|
-
The start is its own axis, and a receiver is one value on it. Across the
|
|
56
|
-
29 shipped packs a match starts from at least thirteen places, and most
|
|
57
|
-
of them are not receivers at all: an exported name, a file path, a
|
|
58
|
-
decorator, a parameter's type, a template file beside the module, a
|
|
59
|
-
function's return type. `MatchStart` is where those arrive.
|
|
60
|
-
|
|
61
|
-
The receiver-shaped starts are their own union, `ReceiverOrigin`:
|
|
62
|
-
|
|
63
|
-
| origin | what it matches | built |
|
|
64
|
-
|---|---|---|
|
|
65
|
-
| `declaredBy` | a receiver whose method one of these modules declared | yes |
|
|
66
|
-
| `constructed` | a client made from one of these modules' exports | yes |
|
|
67
|
-
| `factoryMade` | `app = express()` | no |
|
|
68
|
-
| `imported` | a function the file imports | no |
|
|
69
|
-
| `anchored` | a chain read from its anchor call | no |
|
|
70
|
-
| `inherits` | a Ruby or Python receiver matched by ancestry | no |
|
|
71
|
-
| `global` | `process.env`, bare `fetch` | no |
|
|
72
|
-
|
|
73
|
-
`declaredBy` is what a pack wants when the source never spells the
|
|
74
|
-
client out: `const redis = await this.getClient()` says nothing about
|
|
75
|
-
ioredis, and the declaration behind `redis.get` says everything.
|
|
76
|
-
`constructed` asks the receiver itself, so it still works where the
|
|
77
|
-
method is untyped.
|
|
78
|
-
|
|
79
|
-
A chain can also match a bare call of the tracked value itself, with
|
|
80
|
-
`.calls(meaning)` beside its methods table. A store hook is the case:
|
|
81
|
-
`useAppStore((s) => s.bears)` reaches for no method, so there is no
|
|
82
|
-
name for the table to list; the call matches when its callee is a
|
|
83
|
-
bound name whose written value came from the chain's origin. The
|
|
84
|
-
fields such a call reads are usually stated in a selector lambda, and
|
|
85
|
-
`fields: { selectorParam: 0 }` picks them off the lambda's parameter,
|
|
86
|
-
one per distinct first segment.
|
|
87
|
-
|
|
88
|
-
## The gradient
|
|
89
|
-
|
|
90
|
-
Expressiveness is bought link by link, and the price is printed.
|
|
91
|
-
|
|
92
|
-
1. A chain of data links. Serializable, inspectable, and it runs
|
|
93
|
-
wherever the ops do.
|
|
94
|
-
2. A link written as a function. That link is code, the rest stay data,
|
|
95
|
-
and pack health says which ones are opaque.
|
|
96
|
-
3. `astLink` from `@suss/recognize/ast`, which hands the function the
|
|
97
|
-
adapter's own node. Behind its own import, so reaching for it shows
|
|
98
|
-
up in the diff, and pack health reports it the way it reports a pack
|
|
99
|
-
that declares no version.
|
|
100
|
-
|
|
101
|
-
`packGradients` in `@suss/adapter-typescript` reads the counts off a
|
|
102
|
-
run, and three health checks fire on them: a link written as a function,
|
|
103
|
-
a link that reads the syntax tree, and a declaration with no example.
|
|
104
|
-
|
|
105
|
-
## The executor ops
|
|
106
|
-
|
|
107
|
-
`CallOps` is the whole of what a chain asks about one call site. An
|
|
108
|
-
adapter implements it once. Today `callOpsFor` in
|
|
109
|
-
`@suss/adapter-typescript` is the only implementation, and it puts the
|
|
110
|
-
result on the recognizer context under `ops`.
|
|
111
|
-
|
|
112
|
-
| op | what it gives back |
|
|
113
|
-
|---|---|
|
|
114
|
-
| `method()` | which method the call reaches for, as the source spells it |
|
|
115
|
-
| `receiverIsFrom(origin)` | whether the receiver came from where the origin says |
|
|
116
|
-
| `isFrom(origin)` | whether the call itself came from where the origin says |
|
|
117
|
-
| `argumentCount()` | how many arguments the call passes |
|
|
118
|
-
| `nameAt(index, unsettled)` | the name that argument gives, with the hole policy applied |
|
|
119
|
-
| `calleeText()` | the callee, as the source writes it |
|
|
120
|
-
| `receiver()` | the call the receiver is, as ops of its own |
|
|
121
|
-
| `argument(index)` | the call that argument is, as ops of its own |
|
|
122
|
-
| `callee()` | the call the callee itself was written as |
|
|
123
|
-
| `namedCallee()` | whether the call goes to a name the program bound (optional) |
|
|
124
|
-
| `parameterReadsAt(index)` | the fields a selector lambda in that position reads off its parameter (optional) |
|
|
125
|
-
| `propertyAt(index, property, unsettled)` | what a named property of that argument says |
|
|
126
|
-
| `valueAt(index)` | the value that argument states, as `ValueOps` |
|
|
127
|
-
|
|
128
|
-
`receiver()`, `argument(index)` and `callee()` read a call next to the
|
|
129
|
-
one in hand: each gives back another `CallOps`, so every question above
|
|
130
|
-
works one step along. `callee()` is the one for a class a factory made, where the
|
|
131
|
-
source writes `new User({ name })` and what `User` is comes from the
|
|
132
|
-
`model("User", schema)` call it was declared as.
|
|
133
|
-
|
|
134
|
-
The last two reach a value rather than a call. `propertyAt` pulls one
|
|
135
|
-
name out of a property bag, which is what a pack that wants a bucket or
|
|
136
|
-
a table wants. `valueAt` hands the value over whole, for a pack whose
|
|
137
|
-
rule has to walk it:
|
|
138
|
-
|
|
139
|
-
| op | what it gives back |
|
|
140
|
-
|---|---|
|
|
141
|
-
| `text()` | the string the source wrote, or null for anything else |
|
|
142
|
-
| `flag()` | the yes or no the source wrote, taking a number the way it takes a boolean |
|
|
143
|
-
| `entries(unsettled)` | what an object states, as key and value per entry |
|
|
144
|
-
| `items()` | what a list states, item by item |
|
|
145
|
-
| `property(name)` | what one named property states, as a value of its own |
|
|
146
|
-
| `parts()` | the pieces of text the source wrote, with the holes left out |
|
|
147
|
-
| `holes()` | what the source interpolated between those pieces, each as the call it was written as |
|
|
148
|
-
|
|
149
|
-
A key the source computes, `{ [this.tableName]: [...] }`, is read the
|
|
150
|
-
way any other name is, so an entry's key comes back settled where the
|
|
151
|
-
source settles it.
|
|
152
|
-
|
|
153
|
-
A chain running on an adapter with no ops matches nothing rather than
|
|
154
|
-
throwing, since a pack loaded into the wrong adapter is a configuration
|
|
155
|
-
mistake and not a crash.
|
|
156
|
-
|
|
157
|
-
## Reaching a call next to this one
|
|
158
|
-
|
|
159
|
-
Two of the three storage shapes put what a pack needs somewhere other
|
|
160
|
-
than the call the adapter is standing on.
|
|
161
|
-
|
|
162
|
-
```ts
|
|
163
|
-
s3.send(new GetObjectCommand({ Bucket: "photos", Key: "a.jpg" }));
|
|
164
|
-
storage.bucket("photos").file("a.jpg").download();
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
The first says `send` at every call site in the codebase and puts the
|
|
168
|
-
operation, the bucket and the key in the command. The second puts the
|
|
169
|
-
bucket two hops back up the receivers and the object one hop back.
|
|
170
|
-
Neither needs a question of its own: both are the questions above,
|
|
171
|
-
asked of a different call.
|
|
172
|
-
|
|
173
|
-
A pack says which call with `about`, and a pick says which call with
|
|
174
|
-
`of`. Both take steps, and a step is data:
|
|
175
|
-
|
|
176
|
-
| step | what it reaches |
|
|
177
|
-
|---|---|
|
|
178
|
-
| `{ to: "receiver" }` | the call the receiver is |
|
|
179
|
-
| `{ to: "receiver", method: "bucket" }` | the first call to `bucket` up the receivers |
|
|
180
|
-
| `{ to: "argument", at: 0 }` | the call the first argument is |
|
|
181
|
-
| `{ to: "argument", at: { from: 0 } }` | every argument that is a call, first one that matches wins |
|
|
182
|
-
| `{ to: "argument", at: { from: 0 }, origin }` | the same, keeping only the ones the origin pins down |
|
|
183
|
-
|
|
184
|
-
```ts
|
|
185
|
-
storageCalls({ system: "s3", client: constructedFrom("@aws-sdk/client-s3") })
|
|
186
|
-
.about({ to: "argument", at: { from: 0 } })
|
|
187
|
-
.methods({ GetObjectCommand: { kind: "read", selector: KEY } })
|
|
188
|
-
.container({ at: 0, property: ["Bucket"] });
|
|
189
|
-
```
|
|
190
|
-
|
|
191
|
-
With a subject, every other link is asked of the call the steps reach:
|
|
192
|
-
the operation is that call's own name, the origin check is about that
|
|
193
|
-
call, and a pick with no `of` reads that call's arguments. The effect
|
|
194
|
-
still records the call in hand as its callee, since that is where a
|
|
195
|
-
reader would go and look.
|
|
196
|
-
|
|
197
|
-
A step follows what the source wrote a name as, so `const side = await
|
|
198
|
-
deck.side("a")` reaches `deck.side("a")` rather than stopping at the
|
|
199
|
-
await.
|
|
200
|
-
|
|
201
|
-
A step that says which method is searched for rather than counted to,
|
|
202
|
-
because `bucket(b).file(p).download()` and `bucket(b).getFiles()` put
|
|
203
|
-
the bucket a different distance back. The search is bounded at eight
|
|
204
|
-
receivers: a receiver chain can come back round to itself through a
|
|
205
|
-
variable, and a pack that meant more than eight hops has written
|
|
206
|
-
something else by mistake.
|
|
207
|
-
|
|
208
|
-
A step to an argument can say where that argument had to have come
|
|
209
|
-
from, which is `isFrom` asked of each candidate in turn. `send(command)`
|
|
210
|
-
takes one argument and a presigner takes two, and the one that matters
|
|
211
|
-
is the command the SDK declares, so the step says so rather than
|
|
212
|
-
reading whatever it lands on. The modules it says go into the pack's
|
|
213
|
-
import gate the way a start link's do.
|
|
214
|
-
|
|
215
|
-
A pick reads the argument itself, or a property of the object the
|
|
216
|
-
argument states. The properties are tried in order, so `property:
|
|
217
|
-
["Key", "Prefix"]` is "the key, or the prefix a listing asked for
|
|
218
|
-
instead". A construction is unwrapped first, since that is where a
|
|
219
|
-
command puts its inputs.
|
|
220
|
-
|
|
221
|
-
## A call that states one request object
|
|
222
|
-
|
|
223
|
-
An AWS SDK command puts everything the call is doing inside one object,
|
|
224
|
-
and four of the things a storage effect records come out of it. Each is
|
|
225
|
-
a link of its own.
|
|
226
|
-
|
|
227
|
-
```ts
|
|
228
|
-
storageCalls({ system: "aws.dynamodb" })
|
|
229
|
-
.about({ to: "argument", at: { from: 0 }, origin: constructedFrom(...MODULES) })
|
|
230
|
-
.methods(COMMANDS)
|
|
231
|
-
.input({ at: 0 })
|
|
232
|
-
.container({ at: 0, property: ["TableName"] })
|
|
233
|
-
.accessPath({ at: 0, property: ["IndexName"] })
|
|
234
|
-
.containersIn({ at: 0, property: ["RequestItems"] });
|
|
235
|
-
```
|
|
236
|
-
|
|
237
|
-
`input` says where the call states its inputs. A call that states none
|
|
238
|
-
is not one of these calls, so the chain stops there, and a rule the pack
|
|
239
|
-
wrote over the inputs is handed the object rather than a position to go
|
|
240
|
-
looking in.
|
|
241
|
-
|
|
242
|
-
`accessPath` is the way in the call took, which pairs against a
|
|
243
|
-
declared index rather than against the container itself.
|
|
244
|
-
|
|
245
|
-
`containersIn` is for a call that reaches several containers at once. A
|
|
246
|
-
batch states them as a map, one entry per container, and the chain then
|
|
247
|
-
yields one effect per entry: the entry's key is what the container is
|
|
248
|
-
called, and the entry's value is what the call did there. A chain
|
|
249
|
-
without it yields the single effect its container link addresses.
|
|
250
|
-
|
|
251
|
-
A rule the pack writes for `selector` or `fields` is handed the input,
|
|
252
|
-
that entry when there is one, and whether the call reads or writes:
|
|
253
|
-
|
|
254
|
-
```ts
|
|
255
|
-
fields: ({ input, entry, kind }) =>
|
|
256
|
-
(entry ?? input).property("ProjectionExpression")?.text()?.split(",") ?? [],
|
|
257
|
-
```
|
|
258
|
-
|
|
259
|
-
A method table with a rule inside it is still a table, so the link
|
|
260
|
-
stays counted as data and pack health prices the rule beside it.
|
|
261
|
-
|
|
262
|
-
## A rule that says which value it reads
|
|
263
|
-
|
|
264
|
-
`input` suits a library that puts everything one call is doing in one
|
|
265
|
-
object. Mongoose spreads it over two arguments instead:
|
|
266
|
-
|
|
267
|
-
```ts
|
|
268
|
-
User.find({ email }, { name: 1, email: 1 });
|
|
269
|
-
// ^ selector ^ fields
|
|
270
|
-
```
|
|
271
|
-
|
|
272
|
-
Both are rules, since a pick gives back names and neither of these
|
|
273
|
-
states one. So a rule can say where it reads, the way a pick already
|
|
274
|
-
says which call it reads with `of`:
|
|
275
|
-
|
|
276
|
-
```ts
|
|
277
|
-
find: {
|
|
278
|
-
kind: "read",
|
|
279
|
-
selector: { of: { at: 0 }, by: filterKeys },
|
|
280
|
-
fields: { of: { at: 1 }, by: projected },
|
|
281
|
-
}
|
|
282
|
-
```
|
|
283
|
-
|
|
284
|
-
`of` is the same `OneArgument` a pick takes, steps and all, so a rule
|
|
285
|
-
can read a value on another call of the chain rather than another
|
|
286
|
-
argument of this one.
|
|
287
|
-
|
|
288
|
-
A rule pointed at an argument the call left out still runs, and what it
|
|
289
|
-
is handed states nothing. Only the pack knows what leaving it out
|
|
290
|
-
means: a Mongoose read with no projection reads every field there is,
|
|
291
|
-
where a call with no request object is not one of these calls at all.
|
|
292
|
-
That guard stays with `input`, which is where it belongs.
|
|
293
|
-
|
|
294
|
-
A method whose own name settles the answer states it as a plain list:
|
|
295
|
-
|
|
296
|
-
```ts
|
|
297
|
-
findById: { kind: "read", selector: ["_id"], fields: projection(1) },
|
|
298
|
-
deleteOne: { kind: "write", selector: filter(0), fields: ["*"] },
|
|
299
|
-
```
|
|
300
|
-
|
|
301
|
-
## An operation the call says rather than the name it goes to
|
|
302
|
-
|
|
303
|
-
A project that wraps a whole API behind one helper puts the operation in
|
|
304
|
-
an argument. `operation` says which one, and a `kind` written with no
|
|
305
|
-
`otherwise` says that an answer the table does not list is not one of
|
|
306
|
-
these calls at all:
|
|
307
|
-
|
|
308
|
-
```ts
|
|
309
|
-
{
|
|
310
|
-
operation: { at: 2 },
|
|
311
|
-
kind: { asks: { at: 2 }, means: { Query: "read", PutItem: "write" } },
|
|
312
|
-
}
|
|
313
|
-
```
|
|
314
|
-
|
|
315
|
-
A pack matching a helper the project rather than a library wrote leaves
|
|
316
|
-
`client` out of `storageCalls`, since the name that project gave is the
|
|
317
|
-
whole of what it has, and passes `requiresImport` to `pack()` for the
|
|
318
|
-
modules that make a file worth reading.
|
|
319
|
-
|
|
320
|
-
## A method the caller says which way round it goes
|
|
321
|
-
|
|
322
|
-
Most methods read or write whatever the call site looks like, and a few
|
|
323
|
-
are told. A signed URL is the one in the shipped packs: the same call
|
|
324
|
-
hands back a URL for reading or for writing depending on what it was
|
|
325
|
-
asked to sign for.
|
|
326
|
-
|
|
327
|
-
```ts
|
|
328
|
-
kind: {
|
|
329
|
-
asks: { at: 0, property: ["action"] },
|
|
330
|
-
means: { read: "read", write: "write" },
|
|
331
|
-
otherwise: "read",
|
|
332
|
-
}
|
|
333
|
-
```
|
|
334
|
-
|
|
335
|
-
`otherwise` is what the call comes to when it says nothing, which is
|
|
336
|
-
the library's own default rather than a guess.
|
|
337
|
-
|
|
338
|
-
## A statement written as SQL
|
|
339
|
-
|
|
340
|
-
A raw query says what it reached in its text rather than in its
|
|
341
|
-
arguments. So the chain hands the text to `@suss/sql`, and the parse
|
|
342
|
-
settles the container, the kind, the fields and the selector of every
|
|
343
|
-
table the statement touches:
|
|
344
|
-
|
|
345
|
-
```ts
|
|
346
|
-
sqlStatements({
|
|
347
|
-
system: "postgresql",
|
|
348
|
-
dialect: "postgresql",
|
|
349
|
-
client: declaredBy("@prisma/client", ".prisma/client"),
|
|
350
|
-
})
|
|
351
|
-
.methods({ $queryRaw: { statement: { at: 0 } } })
|
|
352
|
-
.example('prisma.$queryRawUnsafe("SELECT id, email FROM users")');
|
|
353
|
-
```
|
|
354
|
-
|
|
355
|
-
One call comes out as one effect per table, each with its own kind. A
|
|
356
|
-
statement that writes one table while reading another says both, which
|
|
357
|
-
is the thing the storage ending cannot do: that one settles the kind
|
|
358
|
-
once for the whole call.
|
|
359
|
-
|
|
360
|
-
`dialect` is which SQL the statements are written in, and a pack always
|
|
361
|
-
states it. Wherever the store is the database it is the store's own name
|
|
362
|
-
again, which is what Prisma writes above. A Cloudflare D1 database is a
|
|
363
|
-
store of its own whose statements are SQLite, so a pack for it says
|
|
364
|
-
`system: "d1", dialect: "sqlite"`. Nothing defaults, because a reader
|
|
365
|
-
that guessed Postgres for a MySQL project would report the wrong tables
|
|
366
|
-
rather than none: backtick-quoted identifiers parse as something else
|
|
367
|
-
entirely.
|
|
368
|
-
|
|
369
|
-
A tagged template is a call the source wrote without parentheses: the
|
|
370
|
-
tag is the callee and the template is the one argument. All three of
|
|
371
|
-
these state their statement at position 0:
|
|
372
|
-
|
|
373
|
-
```ts
|
|
374
|
-
prisma.$queryRaw`SELECT id FROM users WHERE id = ${id}`;
|
|
375
|
-
prisma.$queryRawUnsafe("SELECT id FROM users");
|
|
376
|
-
db.execute(sql`SELECT id FROM users`);
|
|
377
|
-
```
|
|
378
|
-
|
|
379
|
-
The third is a tagged template handed to an ordinary call, and a pick at
|
|
380
|
-
position 0 reads it because the text of a value comes back through the
|
|
381
|
-
tag. So a pack whose client takes its statement either way writes one
|
|
382
|
-
method table rather than two declarations.
|
|
383
|
-
|
|
384
|
-
The invocation walk never reaches a tagged template, so `pack` puts a
|
|
385
|
-
chain with this ending on the access walk instead. That walk visits
|
|
386
|
-
calls as well, which is what catches the unsafe form.
|
|
387
|
-
|
|
388
|
-
### A hole that is a table rather than a value
|
|
389
|
-
|
|
390
|
-
`parts()` gives the text either side of each hole, and by default what
|
|
391
|
-
the query interpolated reaches the statement as a parameter, which is
|
|
392
|
-
what it would have been anyway. Drizzle breaks that: a query says which
|
|
393
|
-
table it reached by handing over the schema object.
|
|
394
|
-
|
|
395
|
-
```ts
|
|
396
|
-
db.execute(sql`UPDATE ${users} SET name = ${name} WHERE id = ${id}`);
|
|
397
|
-
```
|
|
398
|
-
|
|
399
|
-
Written as `UPDATE $1 SET name = $2 WHERE id = $3` that does not parse,
|
|
400
|
-
and the query goes unread. Only the pack knows the first hole is a table
|
|
401
|
-
and the other two are values, so the pack says so:
|
|
402
|
-
|
|
403
|
-
```ts
|
|
404
|
-
sqlStatements({ system: "postgresql", dialect: "postgresql", client })
|
|
405
|
-
.methods({ execute: { statement: { at: 0 } } })
|
|
406
|
-
.interpolating({ from: constructedFrom("drizzle-orm"), named: { at: 0 } });
|
|
407
|
-
```
|
|
408
|
-
|
|
409
|
-
`holes()` gives each hole as the call the source wrote it as, so
|
|
410
|
-
`${users}` comes back as the `pgTable("users", {...})` its schema file
|
|
411
|
-
declares and `named` reads the name off it the way any other pick reads
|
|
412
|
-
an argument. `from` keeps the pack from reading a hole the library did
|
|
413
|
-
not make; a hole that is not a call, or that came from somewhere else,
|
|
414
|
-
stays the parameter it was.
|
|
415
|
-
|
|
416
|
-
## The example every declaration states
|
|
417
|
-
|
|
418
|
-
```ts
|
|
419
|
-
.example('redis.get("user_online:42")')
|
|
420
|
-
```
|
|
36
|
+
## More
|
|
421
37
|
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
38
|
+
- [Write a pack](https://nimbuscloud-ai.github.io/suss/guides/writing-a-pack)
|
|
39
|
+
- [How packs work](https://nimbuscloud-ai.github.io/suss/packs)
|
|
40
|
+
- [What a declaration compiles to](./DESIGN.md)
|
|
41
|
+
- [Documentation](https://nimbuscloud-ai.github.io/suss/)
|
|
42
|
+
- [Source and issues](https://github.com/nimbuscloud-ai/suss)
|
|
427
43
|
|
|
428
|
-
|
|
44
|
+

|
|
429
45
|
|
|
430
|
-
|
|
431
|
-
looking a method up in a table costs nothing, while following a receiver
|
|
432
|
-
to the library that made it walks declarations. A link that changes what
|
|
433
|
-
the receiver is, the way Prisma's model property will, needs the
|
|
434
|
-
declared order back, and `compile.ts` is where that goes.
|
|
46
|
+
Apache 2.0. See [LICENSE](../../LICENSE).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@suss/recognize",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.24.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Teach suss to read a library you use, by writing a pack as data rather than code, which any language adapter can run.",
|
|
6
6
|
"keywords": [
|
|
@@ -51,9 +51,9 @@
|
|
|
51
51
|
"typecheck": "tsc --noEmit"
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
|
-
"@suss/behavioral-ir": "0.
|
|
55
|
-
"@suss/extractor": "0.
|
|
56
|
-
"@suss/sql": "0.
|
|
54
|
+
"@suss/behavioral-ir": "0.24.0",
|
|
55
|
+
"@suss/extractor": "0.24.0",
|
|
56
|
+
"@suss/sql": "0.24.0"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
59
|
"tsup": "*",
|