@alint-js/languages 0.3.2 → 0.5.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 +30 -0
- package/dist/index.d.mts +10 -7
- package/dist/index.mjs +12 -10
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -59,6 +59,36 @@ plugin_languages = "./node_modules/@alint-js/languages"
|
|
|
59
59
|
The directory lock records physical identity, so upgrading the package re-locks it. Re-run
|
|
60
60
|
`alint plugin install` when it says the target changed.
|
|
61
61
|
|
|
62
|
+
## Add a language
|
|
63
|
+
|
|
64
|
+
This package reads the prebuilt grammars in `tree-sitter-wasms`. That dependency supplies 36
|
|
65
|
+
grammars, and this package uses three of them (by the time this is written). A new language needs a query, not a grammar. The
|
|
66
|
+
query maps the node names of the grammar to the six captures that `extract.ts` reads.
|
|
67
|
+
|
|
68
|
+
To add a language, do these steps:
|
|
69
|
+
|
|
70
|
+
1. Add the file name of the grammar to `GRAMMAR` in `src/grammar.ts`.
|
|
71
|
+
2. Add the query to `QUERIES` in `src/queries.ts`.
|
|
72
|
+
3. Add a case to `isExported` in `src/extract.ts`.
|
|
73
|
+
4. Add a `LanguageDefinition` to `src/index.ts`.
|
|
74
|
+
5. Add the new language to `languagesPlugin` in the same file.
|
|
75
|
+
6. Add a test for the new language to `src/extract.test.ts`.
|
|
76
|
+
|
|
77
|
+
Note: `LanguageId` comes from the keys of `GRAMMAR`. After step 1, the code does not compile until
|
|
78
|
+
you complete step 2 and step 3. The compiler gives no error for step 4, step 5, or step 6.
|
|
79
|
+
|
|
80
|
+
To find the node names of a grammar, read the `grammar.js` file of that tree-sitter parser.
|
|
81
|
+
|
|
82
|
+
CAUTION: Make sure that the grammar uses these three node names. If the grammar uses other names,
|
|
83
|
+
the code still compiles and `FunctionInfo` is wrong:
|
|
84
|
+
|
|
85
|
+
- `block` is the node type of a branch or a loop (`holdsBlock` in `src/extract.ts`).
|
|
86
|
+
- `body` is the field name for the body of a function (`bodyStatements`).
|
|
87
|
+
- `name` is the field name for the name of a function (`withOwnName`).
|
|
88
|
+
|
|
89
|
+
Go, Python, and Rust use these three names. Other grammars use other names. For example, TypeScript
|
|
90
|
+
calls the block `statement_block`.
|
|
91
|
+
|
|
62
92
|
## When to use
|
|
63
93
|
|
|
64
94
|
- Your project has Go, Python or Rust files and you want rules to see functions in them rather than
|
package/dist/index.d.mts
CHANGED
|
@@ -747,7 +747,7 @@ interface Config<TIssue extends BaseIssue<unknown>> {
|
|
|
747
747
|
readonly abortPipeEarly?: boolean | undefined;
|
|
748
748
|
}
|
|
749
749
|
//#endregion
|
|
750
|
-
//#region ../core/dist/types-
|
|
750
|
+
//#region ../core/dist/types-BK5CADYK.d.mts
|
|
751
751
|
//#region src/config/types.d.ts
|
|
752
752
|
type ModelSize = 'large' | 'medium' | 'small';
|
|
753
753
|
interface RunnerCacheConfig {
|
|
@@ -974,8 +974,10 @@ interface RuleInferenceUsageRecord {
|
|
|
974
974
|
totalTokens?: number;
|
|
975
975
|
}
|
|
976
976
|
/**
|
|
977
|
-
* - `'any'` — every
|
|
978
|
-
*
|
|
977
|
+
* - `'any'` — every language except `plaintext`, and never a failure. Plain text is what a file
|
|
978
|
+
* falls back to when no language claims it, so a rule asking for any language is asking for a
|
|
979
|
+
* real one. Rules that work from `FunctionInfo` alone want this: install another language pack
|
|
980
|
+
* and they cover it too, unchanged.
|
|
979
981
|
* - A list of language ids — `LanguageDefinition.name` values such as `go` or `typescript`, never
|
|
980
982
|
* file extensions. The rule handles exactly these. Files of other languages are skipped
|
|
981
983
|
* rather than failed, so one plugin can carry rules for several languages behind one `files:`
|
|
@@ -1013,11 +1015,12 @@ type Target = DirectoryTarget | PlannedSourceTarget | ProjectTarget;
|
|
|
1013
1015
|
//#endregion
|
|
1014
1016
|
//#region src/extract.d.ts
|
|
1015
1017
|
/**
|
|
1016
|
-
* One file target
|
|
1017
|
-
* `FunctionInfo
|
|
1018
|
+
* One file target holding every call site, then one function target per function. Each function
|
|
1019
|
+
* target carries a `FunctionInfo`, so a consumer can fingerprint or classify it without parsing
|
|
1020
|
+
* anything itself.
|
|
1018
1021
|
*
|
|
1019
|
-
* The language
|
|
1020
|
-
* same file
|
|
1022
|
+
* The language is read off the file rather than passed in as an argument. Every target carries that
|
|
1023
|
+
* same file, so an argument could only ever contradict it. Stamp the file with `withLanguage` first.
|
|
1021
1024
|
*/
|
|
1022
1025
|
declare function extractTargets(file: SourceFile): Promise<SourceTarget[]>;
|
|
1023
1026
|
//#endregion
|
package/dist/index.mjs
CHANGED
|
@@ -93,11 +93,12 @@ const QUERIES = {
|
|
|
93
93
|
//#region src/extract.ts
|
|
94
94
|
const queries = /* @__PURE__ */ new Map();
|
|
95
95
|
/**
|
|
96
|
-
* One file target
|
|
97
|
-
* `FunctionInfo
|
|
96
|
+
* One file target holding every call site, then one function target per function. Each function
|
|
97
|
+
* target carries a `FunctionInfo`, so a consumer can fingerprint or classify it without parsing
|
|
98
|
+
* anything itself.
|
|
98
99
|
*
|
|
99
|
-
* The language
|
|
100
|
-
* same file
|
|
100
|
+
* The language is read off the file rather than passed in as an argument. Every target carries that
|
|
101
|
+
* same file, so an argument could only ever contradict it. Stamp the file with `withLanguage` first.
|
|
101
102
|
*/
|
|
102
103
|
async function extractTargets(file) {
|
|
103
104
|
if (!isLanguageId(file.language)) throw new Error(`Language "${file.language}" is not provided by @alint-js/languages.`);
|
|
@@ -216,7 +217,7 @@ function holdsBlock(node) {
|
|
|
216
217
|
}
|
|
217
218
|
return false;
|
|
218
219
|
}
|
|
219
|
-
/** Reachable from outside its file
|
|
220
|
+
/** Reachable from outside its file: a capital in Go, no leading underscore in Python, `pub` in Rust. */
|
|
220
221
|
function isExported(node, language, name) {
|
|
221
222
|
switch (language) {
|
|
222
223
|
case "go": return /^[A-Z]/.test(name);
|
|
@@ -231,7 +232,7 @@ function rangeOf(node) {
|
|
|
231
232
|
start: node.startIndex
|
|
232
233
|
};
|
|
233
234
|
}
|
|
234
|
-
/**
|
|
235
|
+
/** Turns absolute file offsets into offsets within the function's own `text`, as `FunctionInfo` documents. */
|
|
235
236
|
function rangesInside(ranges, outer) {
|
|
236
237
|
return ranges.filter((range) => range.start >= outer.start && range.end <= outer.end).map((range) => ({
|
|
237
238
|
end: range.end - outer.start,
|
|
@@ -241,10 +242,11 @@ function rangesInside(ranges, outer) {
|
|
|
241
242
|
/**
|
|
242
243
|
* Adds the function's own name to its renameable identifiers.
|
|
243
244
|
*
|
|
244
|
-
*
|
|
245
|
-
*
|
|
246
|
-
*
|
|
247
|
-
* already an `@identifier`, so the dedupe by start offset drops
|
|
245
|
+
* In practice this only matters for Go methods, whose name is a `field_identifier`. The Go query
|
|
246
|
+
* skips `field_identifier` on purpose: a consumer that replaces renameable names would otherwise
|
|
247
|
+
* make `entry.name` and `entry.size` look identical. A method's own name is safe to replace. Every
|
|
248
|
+
* other name the queries capture is already an `@identifier`, so the dedupe by start offset drops
|
|
249
|
+
* the duplicate.
|
|
248
250
|
*/
|
|
249
251
|
function withOwnName(ranges, nameNode, outer) {
|
|
250
252
|
if (nameNode === null) return ranges;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alint-js/languages",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.5.0",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
7
7
|
"types": "./dist/index.d.mts",
|
|
@@ -13,15 +13,15 @@
|
|
|
13
13
|
"dist"
|
|
14
14
|
],
|
|
15
15
|
"peerDependencies": {
|
|
16
|
-
"@alint-js/core": "0.
|
|
16
|
+
"@alint-js/core": "0.5.0"
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
19
|
"tree-sitter-wasms": "^0.1.13",
|
|
20
20
|
"web-tree-sitter": "^0.24.7"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
|
-
"@alint-js/core": "0.
|
|
24
|
-
"@alint-js/plugin": "0.
|
|
23
|
+
"@alint-js/core": "0.5.0",
|
|
24
|
+
"@alint-js/plugin": "0.5.0"
|
|
25
25
|
},
|
|
26
26
|
"scripts": {
|
|
27
27
|
"build": "tsdown",
|