@alint-js/plugin 0.1.3 → 0.1.5

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.
Files changed (3) hide show
  1. package/LICENSE +21 -0
  2. package/dist/index.d.mts +154 -18
  3. package/package.json +2 -2
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Alint contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/dist/index.d.mts CHANGED
@@ -1,8 +1,62 @@
1
- //#region ../core/dist/types-DSvXUVZ7.d.mts
1
+ //#region ../core/dist/types-DM4idR4w.d.mts
2
2
  //#region src/core/source/types.d.ts
3
- type ClassTarget = SourceTargetOfKind<'class'>;
4
- type FileTarget = SourceTargetOfKind<'file'>;
5
- type FunctionTarget = SourceTargetOfKind<'function'>;
3
+ interface BaseSourceFile {
4
+ contentHash: string;
5
+ language: string;
6
+ path: string;
7
+ }
8
+ /**
9
+ * Carried on a file target under `metadata.calls`, in source order.
10
+ *
11
+ * Every call in the file, including those outside any function: a consumer counting how often a
12
+ * name is used has to see the uses, not just the definitions.
13
+ */
14
+ interface CallSite extends SourceMetadataObject {
15
+ /** The last segment only: `a.b.helper()` and `helper()` both yield `helper`. */
16
+ name: string;
17
+ /** Absolute, into the file's text. */
18
+ range: SourceRange;
19
+ }
20
+ type ClassTarget = PlannedSourceTargetOfKind<'class'>;
21
+ type FileTarget = PlannedSourceTargetOfKind<'file'>;
22
+ /**
23
+ * Carried under `metadata.function`, so a consumer can fingerprint, count and classify a function
24
+ * without reaching for a parser of its own.
25
+ *
26
+ * Every producer of function targets should fill it in; a consumer still validates the expected
27
+ * domain fields when reading the recursive JSON metadata contract.
28
+ *
29
+ * Ranges are relative to the target's own `text`, not to the file, so a consumer can slice that
30
+ * text directly and never has to rebase.
31
+ */
32
+ interface FunctionInfo extends SourceMetadataObject {
33
+ /**
34
+ * Stricter than one statement: a body that is one `if` and its two returns is one statement and
35
+ * not one expression.
36
+ */
37
+ bodyIsSingleExpression: boolean;
38
+ /** Statements in the body, not counting comments. */
39
+ bodyStatements: number;
40
+ commentRanges: readonly SourceRange[];
41
+ /**
42
+ * The names the function declares: its own name, its parameters and its locals.
43
+ *
44
+ * A copy can rename what it declares and stay a copy, so this is the set an α-renaming
45
+ * fingerprint may replace. Everything else — callees, globals, types, properties — stays
46
+ * verbatim and is what tells two same-shaped functions apart.
47
+ */
48
+ declaredNames: readonly string[];
49
+ /** Reachable from outside its file, however the language spells it. */
50
+ exported: boolean;
51
+ /**
52
+ * Identifiers that MAY be renamed away, which is narrower than "every identifier token".
53
+ *
54
+ * Property, field and type names must not be here: replacing them collapses `entry.name` and
55
+ * `entry.size` into the same fingerprint, which is the mistake this set exists to avoid.
56
+ */
57
+ identifierRanges: readonly SourceRange[];
58
+ }
59
+ type FunctionTarget = PlannedSourceTargetOfKind<'function'>;
6
60
  interface LanguageContext {
7
61
  cwd: string;
8
62
  languageOptions: Record<string, unknown>;
@@ -12,6 +66,20 @@ interface LineRange {
12
66
  endLine: number;
13
67
  startLine: number;
14
68
  }
69
+ interface PlannedSourceTarget {
70
+ file: BaseSourceFile;
71
+ identity: string;
72
+ kind: SourceTargetKind;
73
+ language: string;
74
+ loc?: SourceLocation;
75
+ metadata?: SourceTargetMetadata;
76
+ name?: string;
77
+ origin?: SourceTargetOrigin;
78
+ range?: SourceRange;
79
+ }
80
+ type PlannedSourceTargetOfKind<Kind extends SourceTargetKind> = Omit<PlannedSourceTarget, 'kind'> & {
81
+ kind: Kind;
82
+ };
15
83
  interface ProcessedSource {
16
84
  identity: string;
17
85
  language?: string;
@@ -33,16 +101,26 @@ interface ProcessorPostprocessContext extends ProcessorContext {
33
101
  file: SourceFile;
34
102
  processedSources: ProcessedSource[];
35
103
  }
36
- interface SourceFile {
37
- language: string;
104
+ interface SourceExtractOptions {
105
+ /**
106
+ * Overrides the file's configured `language:` pin.
107
+ *
108
+ * For a caller walking a mixed tree, where the file's own config cannot know what each file is.
109
+ */
110
+ language?: string;
111
+ }
112
+ interface SourceFile extends BaseSourceFile {
38
113
  lines: string[];
39
- path: string;
40
114
  text: string;
41
115
  }
42
116
  interface SourceLocation {
43
117
  end: SourcePosition;
44
118
  start: SourcePosition;
45
119
  }
120
+ interface SourceMetadataObject {
121
+ readonly [key: string]: SourceMetadataValue;
122
+ }
123
+ type SourceMetadataValue = boolean | null | number | readonly SourceMetadataValue[] | SourceMetadataObject | SourceRange | string;
46
124
  interface SourcePosition {
47
125
  column: number;
48
126
  line: number;
@@ -52,8 +130,22 @@ interface SourceRange {
52
130
  start: number;
53
131
  }
54
132
  interface SourceRuntime {
55
- getText: (target: SourceFile | SourceTarget) => string;
56
- readFile: (filePath: string) => Promise<SourceFile>;
133
+ /**
134
+ * Targets for any file, linted or not.
135
+ *
136
+ * Resolves the file's own config the way linting does, resolves its language from that config,
137
+ * and runs that language's extract. A rule handed `ProjectTarget.files`, or an index builder
138
+ * sweeping files outside the lint set, has no other way to parse them.
139
+ *
140
+ * An ignored file extracts to `[]` rather than throwing: sweeping broadly and skipping what the
141
+ * config excluded is the normal case, not an error.
142
+ *
143
+ * Only wired inside a run. A runtime built by `createSourceRuntime()` with no extractor throws,
144
+ * because there is no config to resolve the file against.
145
+ */
146
+ extract: (filePath: string, options?: SourceExtractOptions) => Promise<SourceTarget[]>;
147
+ getText: (file: SourceFile) => string;
148
+ readFile: (file: BaseSourceFile | string) => Promise<SourceFile>;
57
149
  sliceLines: (file: SourceFile, range: LineRange) => SourceText;
58
150
  sliceRange: (file: SourceFile, range: SourceRange) => SourceText;
59
151
  }
@@ -63,13 +155,14 @@ interface SourceTarget {
63
155
  kind: SourceTargetKind;
64
156
  language: string;
65
157
  loc?: SourceLocation;
66
- metadata?: Record<string, unknown>;
158
+ metadata?: SourceTargetMetadata;
67
159
  name?: string;
68
160
  origin?: SourceTargetOrigin;
69
161
  range?: SourceRange;
70
162
  text: string;
71
163
  }
72
164
  type SourceTargetKind = 'class' | 'file' | 'fragment' | 'function' | 'symbol' | (string & {});
165
+ type SourceTargetMetadata = Readonly<Record<string, SourceMetadataValue>>;
73
166
  type SourceTargetOfKind<Kind extends SourceTargetKind> = Omit<SourceTarget, 'kind'> & {
74
167
  kind: Kind;
75
168
  };
@@ -710,7 +803,7 @@ interface Config<TIssue extends BaseIssue<unknown>> {
710
803
  readonly abortPipeEarly?: boolean | undefined;
711
804
  }
712
805
  //#endregion
713
- //#region ../core/dist/types-DKylUrAn.d.mts
806
+ //#region ../core/dist/types-deBCDA4_.d.mts
714
807
  //#region src/config/types.d.ts
715
808
  type ModelSize = 'large' | 'medium' | 'small';
716
809
  interface RunnerCacheConfig {
@@ -805,6 +898,12 @@ interface AlintConfigItem {
805
898
  }
806
899
  interface AlintLinterOptions {
807
900
  noInlineConfig?: boolean;
901
+ /**
902
+ * How the run reports files it lints that no language claimed, so they were handled as plain
903
+ * text. Defaults to `'warn'`. An explicit `language: 'plaintext'` pin means plain text was the
904
+ * intent, so pinned files are never reported.
905
+ */
906
+ reportUnregisteredLanguages?: RuleSeverity;
808
907
  reportUnusedDisableDirectives?: RuleSeverity;
809
908
  }
810
909
  type Awaitable<T> = Promise<T> | T;
@@ -841,6 +940,20 @@ interface IgnoreConfig {
841
940
  interface LanguageDefinition {
842
941
  extensions?: readonly string[];
843
942
  extract: (file: SourceFile, context: LanguageContext) => Awaitable<SourceTarget[]>;
943
+ /**
944
+ * The language's id: what a config pins through `language:`, what a rule's `languages` lists, and
945
+ * what every target it extracts reports. The registry is keyed by it, so two packs cannot claim
946
+ * the same one.
947
+ *
948
+ * Use the identifier editors already use — `go`, `python`, `rust`, `typescript`, `plaintext` —
949
+ * rather than inventing a spelling. Anyone can register a language, so the set is open by
950
+ * definition and only a shared convention keeps one language from arriving under three names.
951
+ *
952
+ * NOTICE: the list is VS Code's. The Language Server Protocol shares it for the languages it
953
+ * covers, but its table has no entry for plain text, so `plaintext` comes from VS Code alone.
954
+ * https://code.visualstudio.com/docs/languages/identifiers
955
+ * https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocumentItem
956
+ */
844
957
  name: string;
845
958
  }
846
959
  interface PluginDefinition<Rules extends Record<string, RuleDefinition<any>> = Record<string, RuleDefinition<any>>> {
@@ -853,10 +966,7 @@ interface ProcessorDefinition {
853
966
  postprocess?: (diagnostics: DiagnosticDescriptor[], context: ProcessorPostprocessContext) => Awaitable<DiagnosticDescriptor[]>;
854
967
  preprocess: (file: SourceFile, context: ProcessorContext) => Awaitable<ProcessedSource[]>;
855
968
  }
856
- interface ProjectFileEntry {
857
- contentHash: string;
858
- language: string;
859
- path: string;
969
+ interface ProjectFileEntry extends BaseSourceFile {
860
970
  targetCount: number;
861
971
  }
862
972
  interface ProjectTarget {
@@ -906,6 +1016,15 @@ interface RuleDefinition<OptionsSchema extends RuleOptionsSchema = []> {
906
1016
  /** Additional stable rule inputs, such as imported prompts, that invalidate cached results when changed. */
907
1017
  cacheKey?: unknown;
908
1018
  create: (context: RuleContext<RuleOptionsOutput<OptionsSchema>>) => RuleHandlers;
1019
+ /**
1020
+ * Which languages this rule reads. Omitting it opts out of extraction: the rule still receives
1021
+ * file targets, but never the function and class targets a language produces.
1022
+ *
1023
+ * It does not choose how a file is parsed. A config's `language:` pin, or the extension, settles
1024
+ * that before any rule is consulted. Directory and project targets ignore it too: they index a
1025
+ * tree rather than come from a language.
1026
+ */
1027
+ languages?: RuleLanguages;
909
1028
  model?: ModelRequirement;
910
1029
  options?: OptionsSchema;
911
1030
  }
@@ -920,6 +1039,23 @@ interface RuleInferenceUsageRecord {
920
1039
  ruleId?: string;
921
1040
  totalTokens?: number;
922
1041
  }
1042
+ /**
1043
+ * - `'any'` — every registered language, and never a failure. A rule that works from `FunctionInfo`
1044
+ * alone wants this: a language pack the user installs later is covered without a new release.
1045
+ * - A list of language ids — `LanguageDefinition.name` values such as `go` or `typescript`, never
1046
+ * file extensions. The rule handles exactly these. Files of other languages are skipped
1047
+ * rather than failed, so one plugin can carry rules for several languages behind one `files:`
1048
+ * glob. If a listed language is not registered at all the run fails, because a rule scoped to a
1049
+ * language nothing provides would otherwise skip every file in silence.
1050
+ * - `{ ids: string[], skipMissing?: boolean }` — the same scoping, but an unregistered id can be
1051
+ * skipped instead of failing. For a plugin whose rules span languages a given user may not have installed.
1052
+ */
1053
+ type RuleLanguages = 'any' | readonly string[] | {
1054
+ /** Language ids this rule applies to. */
1055
+ ids: readonly string[];
1056
+ /** Whether to skip unregistered languages instead of failing. */
1057
+ skipMissing?: boolean;
1058
+ };
923
1059
  type RuleOptionsInput<OptionsSchema extends RuleOptionsSchema> = { readonly [Index in keyof OptionsSchema]: InferInput<OptionsSchema[Index]>; };
924
1060
  type RuleOptionsOutput<OptionsSchema extends RuleOptionsSchema> = { readonly [Index in keyof OptionsSchema]: InferOutput<OptionsSchema[Index]>; };
925
1061
  type RuleOptionsSchema = readonly GenericSchema[];
@@ -944,9 +1080,9 @@ interface RuleWithHandler {
944
1080
  onTargetProject?: never;
945
1081
  onTargetWith: (target: Target) => Awaitable<void>;
946
1082
  }
947
- type Target = DirectoryTarget | ProjectTarget | SourceTarget;
1083
+ type Target = DirectoryTarget | PlannedSourceTarget | ProjectTarget;
948
1084
  //#endregion
949
- //#region ../core/dist/define-8BzWDcPs.d.mts
1085
+ //#region ../core/dist/define-CJ2QJPZ8.d.mts
950
1086
  //#region src/dsl/define.d.ts
951
1087
  type AnyRuleDefinition = RuleDefinition<any>;
952
1088
  type ConfigItemWithPluginRules<Plugins, Rules> = Omit<AlintConfigItem, 'plugins' | 'rules'> & {
@@ -991,4 +1127,4 @@ declare function isRetryableAgentError(error: unknown): error is RetryableAgentE
991
1127
  declare function defineTool(tool: AgentTool): AgentTool;
992
1128
  declare function requireAgent(context: Pick<RuleContext, 'agent' | 'id' | 'signal'>): AgentAdapter;
993
1129
  //#endregion
994
- export { type AgentAdapter, type AgentRequest, type AgentResult, type AgentTool, type AgentUsage, type AlintConfig, type AlintConfigExtends, type AlintConfigInput, type AlintConfigItem, type AlintLinterOptions, type Awaitable, type ClassTarget, type DiagnosticDescriptor, type DiagnosticLocation, type DirectoryTarget, type EnabledRule, type FileTarget, type FunctionTarget, type IgnoreConfig, type LanguageContext, type LanguageDefinition, type LineRange, type ModelRequirement, type PluginDefinition, type ProcessedSource, type ProcessedSourceOrigin, type ProcessorContext, type ProcessorDefinition, type ProcessorPostprocessContext, type ProjectFileEntry, type ProjectTarget, type ProjectTargetEntry, type ResolvedModel, type ResolvedProvider, RetryableAgentError, type RuleCacheConfig, type RuleConfigEntry, type RuleContext, type RuleDefinition, type RuleHandlers, type RuleInferenceUsageRecord, type RuleRegistry, type RuleSeverity, type RuleSpecializedHandlers, type RuleWithHandler, type SourceFile, type SourceLocation, type SourcePosition, type SourceRange, type SourceRuntime, type SourceTarget, type SourceTargetKind, type SourceTargetOfKind, type SourceTargetOrigin, type SourceText, type Target, defineConfig, definePlugin, defineRule, defineTool, isRetryableAgentError, requireAgent };
1130
+ export { type AgentAdapter, type AgentRequest, type AgentResult, type AgentTool, type AgentUsage, type AlintConfig, type AlintConfigExtends, type AlintConfigInput, type AlintConfigItem, type AlintLinterOptions, type Awaitable, type BaseSourceFile, type CallSite, type ClassTarget, type DiagnosticDescriptor, type DiagnosticLocation, type DirectoryTarget, type EnabledRule, type FileTarget, type FunctionInfo, type FunctionTarget, type IgnoreConfig, type LanguageContext, type LanguageDefinition, type LineRange, type ModelRequirement, type PlannedSourceTarget, type PlannedSourceTargetOfKind, type PluginDefinition, type ProcessedSource, type ProcessedSourceOrigin, type ProcessorContext, type ProcessorDefinition, type ProcessorPostprocessContext, type ProjectFileEntry, type ProjectTarget, type ProjectTargetEntry, type ResolvedModel, type ResolvedProvider, RetryableAgentError, type RuleCacheConfig, type RuleConfigEntry, type RuleContext, type RuleDefinition, type RuleHandlers, type RuleInferenceUsageRecord, type RuleRegistry, type RuleSeverity, type RuleSpecializedHandlers, type RuleWithHandler, type SourceFile, type SourceLocation, type SourceMetadataObject, type SourceMetadataValue, type SourcePosition, type SourceRange, type SourceRuntime, type SourceTarget, type SourceTargetKind, type SourceTargetMetadata, type SourceTargetOfKind, type SourceTargetOrigin, type SourceText, type Target, defineConfig, definePlugin, defineRule, defineTool, isRetryableAgentError, requireAgent };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@alint-js/plugin",
3
3
  "type": "module",
4
- "version": "0.1.3",
4
+ "version": "0.1.5",
5
5
  "exports": {
6
6
  ".": {
7
7
  "types": "./dist/index.d.mts",
@@ -14,7 +14,7 @@
14
14
  ],
15
15
  "devDependencies": {
16
16
  "valibot": "^1.4.2",
17
- "@alint-js/core": "0.1.3"
17
+ "@alint-js/core": "0.1.5"
18
18
  },
19
19
  "scripts": {
20
20
  "build": "tsdown",