@alint-js/languages 0.4.0 → 0.6.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 +20 -7
- package/dist/index.mjs +12 -10
- package/package.json +19 -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-Cm5Z7Fll.d.mts
|
|
751
751
|
//#region src/config/types.d.ts
|
|
752
752
|
type ModelSize = 'large' | 'medium' | 'small';
|
|
753
753
|
interface RunnerCacheConfig {
|
|
@@ -827,6 +827,7 @@ interface AlintConfigItem {
|
|
|
827
827
|
files?: readonly (readonly string[] | string)[];
|
|
828
828
|
ignore?: IgnoreConfig;
|
|
829
829
|
ignores?: readonly string[];
|
|
830
|
+
integrations?: IntegrationsConfig;
|
|
830
831
|
language?: string;
|
|
831
832
|
languageOptions?: Record<string, unknown>;
|
|
832
833
|
linterOptions?: AlintLinterOptions;
|
|
@@ -871,6 +872,9 @@ interface DirectoryTarget {
|
|
|
871
872
|
interface IgnoreConfig {
|
|
872
873
|
gitignore?: boolean;
|
|
873
874
|
}
|
|
875
|
+
interface IntegrationsConfig {
|
|
876
|
+
stopGate?: StopGateConfig;
|
|
877
|
+
}
|
|
874
878
|
interface LanguageDefinition {
|
|
875
879
|
extensions?: readonly string[];
|
|
876
880
|
extract: (file: SourceFile$1, context: LanguageContext) => Awaitable<SourceTarget$1[]>;
|
|
@@ -974,8 +978,10 @@ interface RuleInferenceUsageRecord {
|
|
|
974
978
|
totalTokens?: number;
|
|
975
979
|
}
|
|
976
980
|
/**
|
|
977
|
-
* - `'any'` — every
|
|
978
|
-
*
|
|
981
|
+
* - `'any'` — every language except `plaintext`, and never a failure. Plain text is what a file
|
|
982
|
+
* falls back to when no language claims it, so a rule asking for any language is asking for a
|
|
983
|
+
* real one. Rules that work from `FunctionInfo` alone want this: install another language pack
|
|
984
|
+
* and they cover it too, unchanged.
|
|
979
985
|
* - A list of language ids — `LanguageDefinition.name` values such as `go` or `typescript`, never
|
|
980
986
|
* file extensions. The rule handles exactly these. Files of other languages are skipped
|
|
981
987
|
* rather than failed, so one plugin can carry rules for several languages behind one `files:`
|
|
@@ -1009,15 +1015,22 @@ interface RuleWithHandler {
|
|
|
1009
1015
|
onTargetProject?: never;
|
|
1010
1016
|
onTargetWith: (target: Target) => Awaitable<void>;
|
|
1011
1017
|
}
|
|
1018
|
+
interface StopGateConfig {
|
|
1019
|
+
enabled?: boolean;
|
|
1020
|
+
target?: StopGateTarget;
|
|
1021
|
+
timeoutMs?: number;
|
|
1022
|
+
}
|
|
1023
|
+
type StopGateTarget = 'all' | 'dirty-files';
|
|
1012
1024
|
type Target = DirectoryTarget | PlannedSourceTarget | ProjectTarget;
|
|
1013
1025
|
//#endregion
|
|
1014
1026
|
//#region src/extract.d.ts
|
|
1015
1027
|
/**
|
|
1016
|
-
* One file target
|
|
1017
|
-
* `FunctionInfo
|
|
1028
|
+
* One file target holding every call site, then one function target per function. Each function
|
|
1029
|
+
* target carries a `FunctionInfo`, so a consumer can fingerprint or classify it without parsing
|
|
1030
|
+
* anything itself.
|
|
1018
1031
|
*
|
|
1019
|
-
* The language
|
|
1020
|
-
* same file
|
|
1032
|
+
* The language is read off the file rather than passed in as an argument. Every target carries that
|
|
1033
|
+
* same file, so an argument could only ever contradict it. Stamp the file with `withLanguage` first.
|
|
1021
1034
|
*/
|
|
1022
1035
|
declare function extractTargets(file: SourceFile): Promise<SourceTarget[]>;
|
|
1023
1036
|
//#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,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alint-js/languages",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.6.0",
|
|
5
|
+
"description": "First-party Go, Python, and Rust language support for alint",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/moeru-ai/alint.git",
|
|
10
|
+
"directory": "packages/languages"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"alint",
|
|
14
|
+
"lint",
|
|
15
|
+
"tree-sitter",
|
|
16
|
+
"go",
|
|
17
|
+
"python",
|
|
18
|
+
"rust"
|
|
19
|
+
],
|
|
5
20
|
"exports": {
|
|
6
21
|
".": {
|
|
7
22
|
"types": "./dist/index.d.mts",
|
|
@@ -13,15 +28,15 @@
|
|
|
13
28
|
"dist"
|
|
14
29
|
],
|
|
15
30
|
"peerDependencies": {
|
|
16
|
-
"@alint-js/core": "0.
|
|
31
|
+
"@alint-js/core": "0.6.0"
|
|
17
32
|
},
|
|
18
33
|
"dependencies": {
|
|
19
34
|
"tree-sitter-wasms": "^0.1.13",
|
|
20
35
|
"web-tree-sitter": "^0.24.7"
|
|
21
36
|
},
|
|
22
37
|
"devDependencies": {
|
|
23
|
-
"@alint-js/
|
|
24
|
-
"@alint-js/
|
|
38
|
+
"@alint-js/plugin": "0.6.0",
|
|
39
|
+
"@alint-js/core": "0.6.0"
|
|
25
40
|
},
|
|
26
41
|
"scripts": {
|
|
27
42
|
"build": "tsdown",
|