@suss/recognize 0.11.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 +205 -0
- package/README.md +131 -0
- package/dist/ast.cjs +37 -0
- package/dist/ast.d.cts +32 -0
- package/dist/ast.d.ts +32 -0
- package/dist/ast.js +12 -0
- package/dist/chain-DTSij2Mn.d.cts +197 -0
- package/dist/chain-DTSij2Mn.d.ts +197 -0
- package/dist/index.cjs +266 -0
- package/dist/index.d.cts +127 -0
- package/dist/index.d.ts +127 -0
- package/dist/index.js +232 -0
- package/package.json +63 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
6
|
+
|
|
7
|
+
1. Definitions.
|
|
8
|
+
|
|
9
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
10
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
11
|
+
|
|
12
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
13
|
+
the copyright owner that is granting the License.
|
|
14
|
+
|
|
15
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
16
|
+
other entities that control, are controlled by, or are under common
|
|
17
|
+
control with that entity. For the purposes of this definition,
|
|
18
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
19
|
+
direction or management of such entity, whether by contract or
|
|
20
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
21
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
22
|
+
|
|
23
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
24
|
+
exercising permissions granted by this License.
|
|
25
|
+
|
|
26
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
27
|
+
including but not limited to software source code, documentation
|
|
28
|
+
source, and configuration files.
|
|
29
|
+
|
|
30
|
+
"Object" form shall mean any form resulting from mechanical
|
|
31
|
+
transformation or translation of a Source form, including but
|
|
32
|
+
not limited to compiled object code, generated documentation,
|
|
33
|
+
and conversions to other media types.
|
|
34
|
+
|
|
35
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
36
|
+
Object form, made available under the License, as indicated by a
|
|
37
|
+
copyright notice that is included in or attached to the work
|
|
38
|
+
(an example is provided in the Appendix below).
|
|
39
|
+
|
|
40
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
41
|
+
form, that is based on (or derived from) the Work and for which the
|
|
42
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
43
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
44
|
+
of this License, Derivative Works shall not include works that remain
|
|
45
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
46
|
+
the Work and Derivative Works thereof.
|
|
47
|
+
|
|
48
|
+
"Contribution" shall mean any work of authorship, including
|
|
49
|
+
the original version of the Work and any modifications or additions
|
|
50
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
51
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
52
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
53
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
54
|
+
means any form of electronic, verbal, or written communication sent
|
|
55
|
+
to the Licensor or its representatives, including but not limited to
|
|
56
|
+
communication on electronic mailing lists, source code control systems,
|
|
57
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
58
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
59
|
+
excluding communication that is conspicuously marked or otherwise
|
|
60
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
61
|
+
|
|
62
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
63
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
64
|
+
subsequently incorporated within the Work.
|
|
65
|
+
|
|
66
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
67
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
68
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
69
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
70
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
71
|
+
Work and such Derivative Works in Source or Object form.
|
|
72
|
+
|
|
73
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
74
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
75
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
76
|
+
(except as stated in this section) patent license to make, have made,
|
|
77
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
78
|
+
where such license applies only to those patent claims licensable by
|
|
79
|
+
such Contributor that are necessarily infringed by their
|
|
80
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
81
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
82
|
+
institute patent litigation against any entity (including a
|
|
83
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
84
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
85
|
+
or contributory patent infringement, then any patent licenses
|
|
86
|
+
granted to You under this License for that Work shall terminate
|
|
87
|
+
as of the date such litigation is filed.
|
|
88
|
+
|
|
89
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
90
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
91
|
+
modifications, and in Source or Object form, provided that You
|
|
92
|
+
meet the following conditions:
|
|
93
|
+
|
|
94
|
+
(a) You must give any other recipients of the Work or Derivative
|
|
95
|
+
Works a copy of this License; and
|
|
96
|
+
|
|
97
|
+
(b) You must cause any modified files to carry prominent notices
|
|
98
|
+
stating that You changed the files; and
|
|
99
|
+
|
|
100
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
101
|
+
that You distribute, all copyright, patent, trademark, and
|
|
102
|
+
attribution notices from the Source form of the Work,
|
|
103
|
+
excluding those notices that do not pertain to any part of
|
|
104
|
+
the Derivative Works; and
|
|
105
|
+
|
|
106
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
107
|
+
distribution, then any Derivative Works that You distribute must
|
|
108
|
+
include a readable copy of the attribution notices contained
|
|
109
|
+
within such NOTICE file, excluding those notices that do not
|
|
110
|
+
pertain to any part of the Derivative Works, in at least one
|
|
111
|
+
of the following places: within a NOTICE text file distributed
|
|
112
|
+
as part of the Derivative Works; within the Source form or
|
|
113
|
+
documentation, if provided along with the Derivative Works; or,
|
|
114
|
+
within a display generated by the Derivative Works, if and
|
|
115
|
+
wherever such third-party notices normally appear. The contents
|
|
116
|
+
of the NOTICE file are for informational purposes only and do not
|
|
117
|
+
modify the License. You may add Your own attribution notices
|
|
118
|
+
within Derivative Works that You distribute, alongside or as an
|
|
119
|
+
addendum to the NOTICE text from the Work, provided that such
|
|
120
|
+
additional attribution notices cannot be construed as modifying
|
|
121
|
+
the License.
|
|
122
|
+
|
|
123
|
+
You may add Your own copyright statement to Your modifications and
|
|
124
|
+
may provide additional or different license terms and conditions
|
|
125
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
126
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
127
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
128
|
+
the conditions stated in this License.
|
|
129
|
+
|
|
130
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
131
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
132
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
133
|
+
this License, without any additional terms or conditions.
|
|
134
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
135
|
+
the terms of any separate license agreement you may have executed
|
|
136
|
+
with Licensor regarding such Contributions.
|
|
137
|
+
|
|
138
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
139
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
140
|
+
except as required for reasonable and customary use in describing the
|
|
141
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
142
|
+
|
|
143
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
144
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
145
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
146
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
147
|
+
implied, including, without limitation, any warranties or conditions
|
|
148
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
149
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
150
|
+
appropriateness of using or redistributing the Work and assume any
|
|
151
|
+
risks associated with Your exercise of permissions under this License.
|
|
152
|
+
|
|
153
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
154
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
155
|
+
unless required by applicable law (such as deliberate and grossly
|
|
156
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
157
|
+
liable to You for damages, including any direct, indirect, special,
|
|
158
|
+
incidental, or consequential damages of any character arising as a
|
|
159
|
+
result of this License or out of the use or inability to use the
|
|
160
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
161
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
162
|
+
other commercial damages or losses), even if such Contributor has
|
|
163
|
+
been advised of the possibility of such damages.
|
|
164
|
+
|
|
165
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
166
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
167
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
168
|
+
or other liability obligations and/or rights consistent with this
|
|
169
|
+
License. However, in accepting such obligations, You may act only
|
|
170
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
171
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
172
|
+
defend, and hold each Contributor harmless for any liability
|
|
173
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
174
|
+
of your accepting any such warranty or additional liability.
|
|
175
|
+
|
|
176
|
+
END OF TERMS AND CONDITIONS
|
|
177
|
+
|
|
178
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
179
|
+
|
|
180
|
+
To apply the Apache License to your work, attach the following
|
|
181
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
182
|
+
replaced with your own identifying information. (Don't include
|
|
183
|
+
the brackets!) The text should be enclosed in the appropriate
|
|
184
|
+
comment syntax for the file format please. Also add information on
|
|
185
|
+
how to contact you by electronic and paper mail.
|
|
186
|
+
|
|
187
|
+
If the program does not interact with users remotely through a computer
|
|
188
|
+
network, then your name and employer's name (e.g., your institution)
|
|
189
|
+
is sufficient to fill in the "name of copyright owner" field. Feel
|
|
190
|
+
free to omit the "name of employer" line if you are in no way affiliated
|
|
191
|
+
with any institution.
|
|
192
|
+
|
|
193
|
+
Copyright 2026 Nimbus Cloud AI LLC
|
|
194
|
+
|
|
195
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
196
|
+
you may not use this file except in compliance with the License.
|
|
197
|
+
You may obtain a copy of the License at
|
|
198
|
+
|
|
199
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
200
|
+
|
|
201
|
+
Unless required by applicable law or agreed to in writing, software
|
|
202
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
203
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
204
|
+
See the License for the specific language governing permissions and
|
|
205
|
+
limitations under the License.
|
package/README.md
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# @suss/recognize
|
|
2
|
+
|
|
3
|
+
Write a pack as data. A pack states where a match starts, which methods
|
|
4
|
+
count, and what each one reads or writes; this package compiles that
|
|
5
|
+
into the recognizer hooks the adapters already call, and any adapter
|
|
6
|
+
that implements the executor ops can run it.
|
|
7
|
+
|
|
8
|
+
```ts
|
|
9
|
+
import { declaredBy, pack, storageCalls } from "@suss/recognize";
|
|
10
|
+
|
|
11
|
+
const COMMANDS = {
|
|
12
|
+
get: { kind: "read", selector: { at: 0 } },
|
|
13
|
+
hset: { kind: "write", selector: { at: 0 }, fields: { at: 1 } },
|
|
14
|
+
} as const;
|
|
15
|
+
|
|
16
|
+
const calls = storageCalls({
|
|
17
|
+
system: "redis",
|
|
18
|
+
client: declaredBy("ioredis", "redis", "iovalkey"),
|
|
19
|
+
})
|
|
20
|
+
.methods(COMMANDS, { ignoringCase: true })
|
|
21
|
+
.container(namespaceOf)
|
|
22
|
+
.example('redis.get("user_online:42")');
|
|
23
|
+
|
|
24
|
+
export default pack("redis", [calls], {
|
|
25
|
+
languages: ["typescript", "javascript"],
|
|
26
|
+
recognizedAs: "@suss/framework-redis",
|
|
27
|
+
});
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Nothing here imports a syntax tree, so the same declaration drives the
|
|
31
|
+
TypeScript adapter today and the Python and Ruby adapters once they
|
|
32
|
+
implement the ops.
|
|
33
|
+
|
|
34
|
+
## The spine
|
|
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
|
+
Only the effects ending is built. The other three are further members of
|
|
49
|
+
`Ending` with an entry in the compile table.
|
|
50
|
+
|
|
51
|
+
### Where a match starts
|
|
52
|
+
|
|
53
|
+
The start is its own axis, and a receiver is one value on it. Across the
|
|
54
|
+
29 shipped packs a match starts from at least thirteen places, and most
|
|
55
|
+
of them are not receivers at all: an exported name, a file path, a
|
|
56
|
+
decorator, a parameter's type, a template file beside the module, a
|
|
57
|
+
function's return type. `MatchStart` is where those arrive.
|
|
58
|
+
|
|
59
|
+
The receiver-shaped starts are their own union, `ReceiverOrigin`:
|
|
60
|
+
|
|
61
|
+
| origin | what it matches | built |
|
|
62
|
+
|---|---|---|
|
|
63
|
+
| `declaredBy` | a receiver whose method one of these modules declared | yes |
|
|
64
|
+
| `constructed` | a client made from one of these modules' exports | yes |
|
|
65
|
+
| `factoryMade` | `app = express()` | no |
|
|
66
|
+
| `imported` | a function the file imports | no |
|
|
67
|
+
| `anchored` | a chain read from its anchor call | no |
|
|
68
|
+
| `inherits` | a Ruby or Python receiver matched by ancestry | no |
|
|
69
|
+
| `global` | `process.env`, bare `fetch` | no |
|
|
70
|
+
|
|
71
|
+
`declaredBy` is what a pack wants when the source never spells the
|
|
72
|
+
client out: `const redis = await this.getClient()` says nothing about
|
|
73
|
+
ioredis, and the declaration behind `redis.get` says everything.
|
|
74
|
+
`constructed` asks the receiver itself, so it still works where the
|
|
75
|
+
method is untyped.
|
|
76
|
+
|
|
77
|
+
## The gradient
|
|
78
|
+
|
|
79
|
+
Expressiveness is bought link by link, and the price is printed.
|
|
80
|
+
|
|
81
|
+
1. A chain of data links. Serializable, inspectable, and it runs
|
|
82
|
+
wherever the ops do.
|
|
83
|
+
2. A link written as a function. That link is code, the rest stay data,
|
|
84
|
+
and pack health says which ones are opaque.
|
|
85
|
+
3. `astLink` from `@suss/recognize/ast`, which hands the function the
|
|
86
|
+
adapter's own node. Behind its own import, so reaching for it shows
|
|
87
|
+
up in the diff, and pack health reports it the way it reports a pack
|
|
88
|
+
that declares no version.
|
|
89
|
+
|
|
90
|
+
`packGradients` in `@suss/adapter-typescript` reads the counts off a
|
|
91
|
+
run, and three health checks fire on them: a link written as a function,
|
|
92
|
+
a link that reads the syntax tree, and a declaration with no example.
|
|
93
|
+
|
|
94
|
+
## The executor ops
|
|
95
|
+
|
|
96
|
+
`CallOps` is the whole of what a chain asks about one call site. An
|
|
97
|
+
adapter implements it once. Today `callOpsFor` in
|
|
98
|
+
`@suss/adapter-typescript` is the only implementation, and it puts the
|
|
99
|
+
result on the recognizer context under `ops`.
|
|
100
|
+
|
|
101
|
+
| op | what it gives back |
|
|
102
|
+
|---|---|
|
|
103
|
+
| `method()` | which method the call reaches for, as the source spells it |
|
|
104
|
+
| `receiverIsFrom(origin)` | whether the receiver came from where the origin says |
|
|
105
|
+
| `argumentCount()` | how many arguments the call passes |
|
|
106
|
+
| `nameAt(index, unsettled)` | the name that argument gives, with the hole policy applied |
|
|
107
|
+
| `calleeText()` | the callee, as the source writes it |
|
|
108
|
+
|
|
109
|
+
A chain running on an adapter with no ops matches nothing rather than
|
|
110
|
+
throwing, since a pack loaded into the wrong adapter is a configuration
|
|
111
|
+
mistake and not a crash.
|
|
112
|
+
|
|
113
|
+
## The example every declaration states
|
|
114
|
+
|
|
115
|
+
```ts
|
|
116
|
+
.example('redis.get("user_online:42")')
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
`runExamples(pack, run)` takes each declaration's example, hands it to
|
|
120
|
+
the compiler the caller supplied, and gives back what came out. A pack's
|
|
121
|
+
test asserts the stated effect, so the day the example stops matching
|
|
122
|
+
the pack fails rather than the documentation quietly lying.
|
|
123
|
+
`examplesMissing(pack)` lists the declarations that state none.
|
|
124
|
+
|
|
125
|
+
## Ordering
|
|
126
|
+
|
|
127
|
+
The links are guards, so the compiled hook checks the cheap one first:
|
|
128
|
+
looking a method up in a table costs nothing, while following a receiver
|
|
129
|
+
to the library that made it walks declarations. A link that changes what
|
|
130
|
+
the receiver is, the way Prisma's model property will, needs the
|
|
131
|
+
declared order back, and `compile.ts` is where that goes.
|
package/dist/ast.cjs
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/ast.ts
|
|
21
|
+
var ast_exports = {};
|
|
22
|
+
__export(ast_exports, {
|
|
23
|
+
astLink: () => astLink
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(ast_exports);
|
|
26
|
+
function astLink(read) {
|
|
27
|
+
const link = (...args) => {
|
|
28
|
+
const ops = args[args.length - 1];
|
|
29
|
+
const given = args.slice(0, -1);
|
|
30
|
+
return read(ops.ast(), ...given);
|
|
31
|
+
};
|
|
32
|
+
return Object.assign(link, { reachesAst: true });
|
|
33
|
+
}
|
|
34
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
35
|
+
0 && (module.exports = {
|
|
36
|
+
astLink
|
|
37
|
+
});
|
package/dist/ast.d.cts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { C as CallOps, L as LinkFunction } from './chain-DTSij2Mn.cjs';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The floor: a link that reads the adapter's own syntax tree.
|
|
5
|
+
*
|
|
6
|
+
* A pack that outgrows the ops still gets the tree, and this is the
|
|
7
|
+
* only door to it. Going through a separate import puts the decision in
|
|
8
|
+
* the diff, and `astLink` marks the link so the pack health report says
|
|
9
|
+
* which packs went through, the way it says which declare no version.
|
|
10
|
+
* Allowed, observable, and slightly inconvenient.
|
|
11
|
+
*
|
|
12
|
+
* The node comes back as `unknown` because this package does not read
|
|
13
|
+
* any one language. A pack casts it to the adapter it was written
|
|
14
|
+
* against, and that cast is how the pack says which adapter it needs.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* The ops an adapter implements when it can hand out its own nodes. The
|
|
19
|
+
* extra member is here rather than on `CallOps` so that a pack reaching
|
|
20
|
+
* for a node has to import this module first.
|
|
21
|
+
*/
|
|
22
|
+
interface AstCapableOps extends CallOps {
|
|
23
|
+
/** The adapter's own node for the call in hand. */
|
|
24
|
+
ast(): unknown;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* A link answered by reading the call's own node. `read` is handed the
|
|
28
|
+
* node and whatever the link would have been handed anyway.
|
|
29
|
+
*/
|
|
30
|
+
declare function astLink<A extends unknown[], R>(read: (node: unknown, ...given: A) => R): LinkFunction<[...A, CallOps], R>;
|
|
31
|
+
|
|
32
|
+
export { type AstCapableOps, astLink };
|
package/dist/ast.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { C as CallOps, L as LinkFunction } from './chain-DTSij2Mn.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The floor: a link that reads the adapter's own syntax tree.
|
|
5
|
+
*
|
|
6
|
+
* A pack that outgrows the ops still gets the tree, and this is the
|
|
7
|
+
* only door to it. Going through a separate import puts the decision in
|
|
8
|
+
* the diff, and `astLink` marks the link so the pack health report says
|
|
9
|
+
* which packs went through, the way it says which declare no version.
|
|
10
|
+
* Allowed, observable, and slightly inconvenient.
|
|
11
|
+
*
|
|
12
|
+
* The node comes back as `unknown` because this package does not read
|
|
13
|
+
* any one language. A pack casts it to the adapter it was written
|
|
14
|
+
* against, and that cast is how the pack says which adapter it needs.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* The ops an adapter implements when it can hand out its own nodes. The
|
|
19
|
+
* extra member is here rather than on `CallOps` so that a pack reaching
|
|
20
|
+
* for a node has to import this module first.
|
|
21
|
+
*/
|
|
22
|
+
interface AstCapableOps extends CallOps {
|
|
23
|
+
/** The adapter's own node for the call in hand. */
|
|
24
|
+
ast(): unknown;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* A link answered by reading the call's own node. `read` is handed the
|
|
28
|
+
* node and whatever the link would have been handed anyway.
|
|
29
|
+
*/
|
|
30
|
+
declare function astLink<A extends unknown[], R>(read: (node: unknown, ...given: A) => R): LinkFunction<[...A, CallOps], R>;
|
|
31
|
+
|
|
32
|
+
export { type AstCapableOps, astLink };
|
package/dist/ast.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// src/ast.ts
|
|
2
|
+
function astLink(read) {
|
|
3
|
+
const link = (...args) => {
|
|
4
|
+
const ops = args[args.length - 1];
|
|
5
|
+
const given = args.slice(0, -1);
|
|
6
|
+
return read(ops.ast(), ...given);
|
|
7
|
+
};
|
|
8
|
+
return Object.assign(link, { reachesAst: true });
|
|
9
|
+
}
|
|
10
|
+
export {
|
|
11
|
+
astLink
|
|
12
|
+
};
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The operations a chain performs at one call site, and what a language
|
|
3
|
+
* adapter has to be able to work out for it.
|
|
4
|
+
*
|
|
5
|
+
* A chain is data, so something has to turn "did this module declare
|
|
6
|
+
* the method" into a yes or no about a particular program. That is the
|
|
7
|
+
* adapter's job, and this interface is the whole of what a chain asks
|
|
8
|
+
* for. An adapter implements it once and every declared pack runs
|
|
9
|
+
* there, which is what lets one pack drive several languages.
|
|
10
|
+
*
|
|
11
|
+
* Nothing here mentions a syntax tree. A link that needs the tree goes
|
|
12
|
+
* through `@suss/recognize/ast`, a separate import so that reaching for
|
|
13
|
+
* it shows up in a diff and in the pack health report.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* How a pack pins down the receiver a call is on.
|
|
17
|
+
*
|
|
18
|
+
* The migration plan for #542 lists four more: `factoryMade` (`app =
|
|
19
|
+
* express()`), `imported`, `anchored` (a chain read from its anchor
|
|
20
|
+
* call), `inherits` (a Ruby or Python receiver matched by ancestry) and
|
|
21
|
+
* `global` (`process.env`, bare `fetch`). Each arrives as a member here
|
|
22
|
+
* with an entry in every adapter's dispatch table. The README beside
|
|
23
|
+
* this file says which starts are not receiver-shaped at all.
|
|
24
|
+
*/
|
|
25
|
+
type ReceiverOrigin = DeclaredBy | ConstructedFrom;
|
|
26
|
+
/**
|
|
27
|
+
* A receiver whose method one of these modules declared.
|
|
28
|
+
*
|
|
29
|
+
* This is the origin for a client the source never spells out. `const
|
|
30
|
+
* redis = await this.getClient()` says nothing about ioredis, and the
|
|
31
|
+
* declaration behind `redis.get` says everything.
|
|
32
|
+
*/
|
|
33
|
+
interface DeclaredBy {
|
|
34
|
+
readonly origin: "declaredBy";
|
|
35
|
+
/** The modules whose declarations settle the call. */
|
|
36
|
+
readonly importedFrom: readonly string[];
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* A client made from a module's export, however the program caches it.
|
|
40
|
+
* Asked of the receiver itself, so it still works where the method is untyped
|
|
41
|
+
* and `declaredBy` finds nothing to read.
|
|
42
|
+
*/
|
|
43
|
+
interface ConstructedFrom {
|
|
44
|
+
readonly origin: "constructed";
|
|
45
|
+
/** The modules whose export the client was made from. */
|
|
46
|
+
readonly importedFrom: readonly string[];
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* A receiver whose method one of these modules declared. Pass every
|
|
50
|
+
* module that ships the same client, the way three packages all speak
|
|
51
|
+
* one wire protocol.
|
|
52
|
+
*/
|
|
53
|
+
declare function declaredBy(...importedFrom: readonly string[]): DeclaredBy;
|
|
54
|
+
/** A client made from one of these modules' exports. */
|
|
55
|
+
declare function constructedFrom(...importedFrom: readonly string[]): ConstructedFrom;
|
|
56
|
+
/**
|
|
57
|
+
* What a reader gives back for a name nothing in the source settles.
|
|
58
|
+
* `"nothing"` gives null, `"reference"` gives the value to go and ask
|
|
59
|
+
* about instead.
|
|
60
|
+
*/
|
|
61
|
+
type UnsettledName = "nothing" | "reference";
|
|
62
|
+
/**
|
|
63
|
+
* One call site, as the questions a chain asks about it.
|
|
64
|
+
*
|
|
65
|
+
* An adapter builds one of these per call and hands it to the
|
|
66
|
+
* recognizer through its context. Every member is about the call in
|
|
67
|
+
* hand, so there is no node to pass around and no place for a pack to
|
|
68
|
+
* reach past what it declared.
|
|
69
|
+
*/
|
|
70
|
+
interface CallOps {
|
|
71
|
+
/** Which method the call reaches for, spelled as the source spells it. */
|
|
72
|
+
method(): string | null;
|
|
73
|
+
/** Whether the receiver came from where the origin says. */
|
|
74
|
+
receiverIsFrom(origin: ReceiverOrigin): boolean;
|
|
75
|
+
/** How many arguments the call passes. */
|
|
76
|
+
argumentCount(): number;
|
|
77
|
+
/** The name the argument in this position gives. */
|
|
78
|
+
nameAt(index: number, unsettled: UnsettledName): string | null;
|
|
79
|
+
/** The callee, as the source writes it. */
|
|
80
|
+
calleeText(): string;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* The property an adapter puts its ops on, in the context it hands a
|
|
84
|
+
* recognizer. A context without it belongs to an adapter that has not
|
|
85
|
+
* implemented the ops, and a declared pack matches nothing there.
|
|
86
|
+
*/
|
|
87
|
+
interface OpsCarrier {
|
|
88
|
+
ops?: CallOps;
|
|
89
|
+
}
|
|
90
|
+
/** The ops in a recognizer context, or null when the adapter has none. */
|
|
91
|
+
declare function opsIn(ctx: unknown): CallOps | null;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* The spine every pack shares, as a chain of links.
|
|
95
|
+
*
|
|
96
|
+
* A pack does four jobs, and all four start the same way: match the
|
|
97
|
+
* receiver, match the method, read the arguments, then yield. What
|
|
98
|
+
* differs is the ending. Recognition yields effects, discovery yields a
|
|
99
|
+
* unit, a terminal yields a response write, and a claimed callback
|
|
100
|
+
* yields a sub-unit. Only the effects ending is built; the others are
|
|
101
|
+
* further members of `Ending` with an entry in the compile table.
|
|
102
|
+
*
|
|
103
|
+
* A link's answer is data wherever it can be. A link given a function
|
|
104
|
+
* instead is code, that link alone, and pack health says which ones.
|
|
105
|
+
*/
|
|
106
|
+
|
|
107
|
+
/** A link whose answer a pack wrote as code rather than as data. */
|
|
108
|
+
interface LinkFunction<A extends unknown[], R> {
|
|
109
|
+
(...args: A): R;
|
|
110
|
+
/** Set when the function was built through `@suss/recognize/ast`. */
|
|
111
|
+
readonly reachesAst?: boolean;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* What a match starts from.
|
|
115
|
+
*
|
|
116
|
+
* Most of what the shipped packs match starts from a receiver, and none
|
|
117
|
+
* of what discovery matches does: an exported name, a file path, a
|
|
118
|
+
* decorator, a parameter's type, a template file beside the module and
|
|
119
|
+
* a function's return type each start somewhere else. So the start is
|
|
120
|
+
* its own axis, and a receiver origin is one value on it.
|
|
121
|
+
*/
|
|
122
|
+
type MatchStart = FromReceiver;
|
|
123
|
+
/** A match that starts from the receiver a call is on. */
|
|
124
|
+
interface FromReceiver {
|
|
125
|
+
readonly starts: "receiver";
|
|
126
|
+
readonly origin: ReceiverOrigin;
|
|
127
|
+
}
|
|
128
|
+
/** Where the match begins. */
|
|
129
|
+
interface StartLink {
|
|
130
|
+
readonly asks: "start";
|
|
131
|
+
readonly at: MatchStart;
|
|
132
|
+
}
|
|
133
|
+
/** Which methods count, and what each one does. */
|
|
134
|
+
interface MethodsLink<TMeaning> {
|
|
135
|
+
readonly asks: "methods";
|
|
136
|
+
readonly table: Readonly<Record<string, TMeaning>>;
|
|
137
|
+
/**
|
|
138
|
+
* Whether two spellings of one method name are the same method. One
|
|
139
|
+
* client library lower-cases where another camel-cases, and both are
|
|
140
|
+
* sending the same command.
|
|
141
|
+
*/
|
|
142
|
+
readonly ignoringCase: boolean;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Which container a call's selector belongs to.
|
|
146
|
+
*
|
|
147
|
+
* The call in hand comes second so that a rule written over the
|
|
148
|
+
* selector alone, which is most of them, ignores it. A rule that has to
|
|
149
|
+
* read the syntax tree goes through `astLink`, which is what puts the
|
|
150
|
+
* call to use.
|
|
151
|
+
*/
|
|
152
|
+
interface ContainerLink {
|
|
153
|
+
readonly asks: "container";
|
|
154
|
+
readonly from: LinkFunction<[readonly string[], CallOps], string | null>;
|
|
155
|
+
}
|
|
156
|
+
/** One question in a chain, and the answer the pack gave for it. */
|
|
157
|
+
type Link<TMeaning> = StartLink | MethodsLink<TMeaning> | ContainerLink;
|
|
158
|
+
/** Which argument or arguments say what a call reached. */
|
|
159
|
+
type ArgumentPick = {
|
|
160
|
+
readonly at: number;
|
|
161
|
+
} | {
|
|
162
|
+
readonly from: number;
|
|
163
|
+
};
|
|
164
|
+
/** What one method of a storage client does. */
|
|
165
|
+
interface StorageMethod {
|
|
166
|
+
readonly kind: "read" | "write";
|
|
167
|
+
/** Which argument or arguments say what the call reached. */
|
|
168
|
+
readonly selector?: ArgumentPick;
|
|
169
|
+
/** Which argument says which field inside it, when the method takes one. */
|
|
170
|
+
readonly fields?: ArgumentPick;
|
|
171
|
+
}
|
|
172
|
+
/** What a chain produces when every link matches. */
|
|
173
|
+
type Ending = StorageEnding;
|
|
174
|
+
/** A storage access: one call, one thing it read or wrote. */
|
|
175
|
+
interface StorageEnding {
|
|
176
|
+
readonly yields: "storageAccess";
|
|
177
|
+
/** The store, in the words OpenTelemetry's semantic conventions use. */
|
|
178
|
+
readonly system: string;
|
|
179
|
+
/** The wire, when it differs from the store's own name. */
|
|
180
|
+
readonly transport?: string;
|
|
181
|
+
/** Which of the store's namespaces the call reached. */
|
|
182
|
+
readonly scope: string;
|
|
183
|
+
/** What a reader gives back for a name nothing in the source settles. */
|
|
184
|
+
readonly unsettledName: "nothing" | "reference";
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* A pack's declaration for one kind of call: the links, the ending, and
|
|
188
|
+
* a line of code it matches.
|
|
189
|
+
*/
|
|
190
|
+
interface Chain<TMeaning = StorageMethod> {
|
|
191
|
+
readonly links: readonly Link<TMeaning>[];
|
|
192
|
+
readonly ending: Ending;
|
|
193
|
+
/** A line of code this matches, which the pack's tests run. */
|
|
194
|
+
readonly example: string | null;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
export { type ArgumentPick as A, type CallOps as C, type DeclaredBy as D, type Ending as E, type FromReceiver as F, type LinkFunction as L, type MatchStart as M, type OpsCarrier as O, type ReceiverOrigin as R, type StorageMethod as S, type UnsettledName as U, type Chain as a, type ConstructedFrom as b, type ContainerLink as c, type Link as d, type MethodsLink as e, type StartLink as f, type StorageEnding as g, constructedFrom as h, declaredBy as i, opsIn as o };
|