@alint-js/core 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 +62 -1
- package/dist/agent.d.mts +1 -1
- package/dist/{define-CJ2QJPZ8.d.mts → define-DO36VJ4W.d.mts} +1 -1
- package/dist/dsl.d.mts +3 -3
- package/dist/{extract-DoHeLdG1.mjs → extract-DhLFgRej.mjs} +5 -5
- package/dist/index.d.mts +24 -7
- package/dist/index.mjs +417 -99
- package/dist/languages-js.mjs +1 -1
- package/dist/structured-output.d.mts +1 -1
- package/dist/structured-output.mjs +16 -4
- package/dist/{types-deBCDA4_.d.mts → types-Cm5Z7Fll.d.mts} +15 -3
- package/package.json +24 -6
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ This package provides the core SDK and run engine APIs used by plugins, rules, l
|
|
|
10
10
|
- `runAlint`
|
|
11
11
|
- rule registry and flat config normalization
|
|
12
12
|
- source runtime helpers
|
|
13
|
-
- built-in JavaScript source extraction
|
|
13
|
+
- built-in JavaScript source extraction, with additional language support for others
|
|
14
14
|
- model resolution by size and capability
|
|
15
15
|
- diagnostics and progress payload types
|
|
16
16
|
- framework-neutral agent contracts under `@alint-js/core/agent`
|
|
@@ -105,6 +105,60 @@ description defaults to the schema's valibot `description(...)`. `toolParameters
|
|
|
105
105
|
that build their own tools or prompts. Use `ctx.agent` instead when the model needs to
|
|
106
106
|
explore with tools before answering, because a forced tool call is a single shot, not a loop.
|
|
107
107
|
|
|
108
|
+
### Languages
|
|
109
|
+
|
|
110
|
+
Core parses JavaScript and TypeScript. Everything else is registered by a plugin, so a rule says
|
|
111
|
+
which languages it can read and core decides what to hand it:
|
|
112
|
+
|
|
113
|
+
```ts
|
|
114
|
+
defineRule({
|
|
115
|
+
create: () => ({ onTargetFunction: (target) => { /* ... */ } }),
|
|
116
|
+
languages: 'any',
|
|
117
|
+
})
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
| `languages` | the rule receives | a named language nothing registered |
|
|
121
|
+
| --- | --- | --- |
|
|
122
|
+
| omitted | file targets only, never functions or classes | not applicable |
|
|
123
|
+
| `'any'` | every language except `plaintext` | never fails |
|
|
124
|
+
| `['go', 'rust']` | those languages only | run fails, `alint/missing-language` |
|
|
125
|
+
| `{ ids: ['go'], skipMissing: true }` | those languages only | skipped quietly |
|
|
126
|
+
|
|
127
|
+
`'any'` excludes `plaintext` on purpose. Plain text is what a file falls back to when no language
|
|
128
|
+
claims its extension, so a rule that asked for a language would otherwise be handed unparsed text.
|
|
129
|
+
When that happens the run reports `alint/unregistered-language` once per extension — a warning by
|
|
130
|
+
default, configurable through `linterOptions.reportUnregisteredLanguages`.
|
|
131
|
+
|
|
132
|
+
Declaring a list is the stricter choice. It fails the run when the user has not installed a pack
|
|
133
|
+
that provides one of them, rather than letting the rule match nothing and look like a pass.
|
|
134
|
+
|
|
135
|
+
A plugin registers a language by describing how to turn a file into targets:
|
|
136
|
+
|
|
137
|
+
```ts
|
|
138
|
+
definePlugin({
|
|
139
|
+
languages: {
|
|
140
|
+
zig: {
|
|
141
|
+
extensions: ['.zig'],
|
|
142
|
+
extract: file => [/* SourceTarget[] */],
|
|
143
|
+
name: 'zig',
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
})
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Ids are the identifiers editors use — `go`, `python`, `typescript`, `plaintext`. Registering fails
|
|
150
|
+
on a duplicate name or extension, so two plugins can never claim the same language.
|
|
151
|
+
|
|
152
|
+
Put a `FunctionInfo` under `metadata.function` on each function target, and the file's call sites
|
|
153
|
+
under `metadata.calls` on the file target. Those two keys are what let a rule read any language
|
|
154
|
+
without a parser of its own.
|
|
155
|
+
|
|
156
|
+
`@alint-js/languages` provides Go, Python and Rust this way.
|
|
157
|
+
|
|
158
|
+
To parse a file the run was not asked to lint, such as when building a workspace-wide index, use
|
|
159
|
+
`ctx.src.extract(path)`. It resolves that file's own config and language, and returns nothing for a
|
|
160
|
+
file the config ignores rather than throwing.
|
|
161
|
+
|
|
108
162
|
## When to use
|
|
109
163
|
|
|
110
164
|
- You are writing an `alint` plugin or rule package.
|
|
@@ -128,3 +182,10 @@ source files retained by plugin code after `ctx.src.readFile()` returns.
|
|
|
128
182
|
|
|
129
183
|
A valid cache written by the same `alint` version is still read from one monolithic JSON document.
|
|
130
184
|
An extremely large cache may therefore exhaust available memory.
|
|
185
|
+
|
|
186
|
+
After each cacheable rule job completes, `alint` writes a cache checkpoint before releasing its
|
|
187
|
+
scheduler slot. Each checkpoint atomically replaces the monolithic cache file. An interrupted run
|
|
188
|
+
can therefore reuse every result that had already become durable, but large caches can cause
|
|
189
|
+
substantial disk writes during runs with many cache misses. Cache hits, skipped jobs, failed jobs,
|
|
190
|
+
and rules that opt out of caching do not add checkpoint writes. A checkpoint or final cache write
|
|
191
|
+
error is fatal and causes the run to fail.
|
package/dist/agent.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { F as
|
|
1
|
+
import { F as AgentAdapter, I as AgentRequest, L as AgentResult, R as AgentTool, x as RuleContext, z as AgentUsage } from "./types-Cm5Z7Fll.mjs";
|
|
2
2
|
//#region src/agent/retry.d.ts
|
|
3
3
|
/**
|
|
4
4
|
* Declares that the complete adapter invocation can be safely replayed.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { D as RuleOptionsSchema, S as RuleDefinition, T as RuleOptionsInput, b as RuleConfigEntry, i as AlintConfigItem, m as PluginDefinition, t as AlintConfig } from "./types-Cm5Z7Fll.mjs";
|
|
2
2
|
//#region src/dsl/define.d.ts
|
|
3
3
|
type AnyRuleDefinition = RuleDefinition<any>;
|
|
4
4
|
type ConfigItemWithPluginRules<Plugins, Rules> = Omit<AlintConfigItem, 'plugins' | 'rules'> & {
|
package/dist/dsl.d.mts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { A as
|
|
2
|
-
import { n as definePlugin, r as defineRule, t as defineConfig } from "./define-
|
|
3
|
-
export { type AlintConfig, type AlintConfigExtends, type AlintConfigInput, type AlintConfigItem, type AlintLinterOptions, type Awaitable, type DiagnosticDescriptor, type DiagnosticLocation, type DirectoryTarget, type EnabledRule, type IgnoreConfig, type LanguageDefinition, type PluginDefinition, type ProcessorDefinition, type ProjectFileEntry, type ProjectTarget, type ProjectTargetEntry, type RuleCacheConfig, type RuleConfigEntry, type RuleContext, type RuleDefinition, type RuleHandlers, type RuleInferenceUsageRecord, type RuleOptionsInput, type RuleOptionsOutput, type RuleOptionsSchema, type RuleRegistry, type RuleSeverity, type RuleSpecializedHandlers, type RuleWithHandler, type Target, defineConfig, definePlugin, defineRule };
|
|
1
|
+
import { A as RuleSpecializedHandlers, C as RuleHandlers, D as RuleOptionsSchema, E as RuleOptionsOutput, M as StopGateConfig, N as StopGateTarget, O as RuleRegistry, P as Target, S as RuleDefinition, T as RuleOptionsInput, _ as ProjectTarget, a as AlintLinterOptions, b as RuleConfigEntry, c as DiagnosticLocation, d as IgnoreConfig, f as IntegrationsConfig, g as ProjectFileEntry, h as ProcessorDefinition, i as AlintConfigItem, j as RuleWithHandler, k as RuleSeverity, l as DirectoryTarget, m as PluginDefinition, n as AlintConfigExtends, o as Awaitable, p as LanguageDefinition, r as AlintConfigInput, s as DiagnosticDescriptor, t as AlintConfig, u as EnabledRule, v as ProjectTargetEntry, w as RuleInferenceUsageRecord, x as RuleContext, y as RuleCacheConfig } from "./types-Cm5Z7Fll.mjs";
|
|
2
|
+
import { n as definePlugin, r as defineRule, t as defineConfig } from "./define-DO36VJ4W.mjs";
|
|
3
|
+
export { type AlintConfig, type AlintConfigExtends, type AlintConfigInput, type AlintConfigItem, type AlintLinterOptions, type Awaitable, type DiagnosticDescriptor, type DiagnosticLocation, type DirectoryTarget, type EnabledRule, type IgnoreConfig, type IntegrationsConfig, type LanguageDefinition, type PluginDefinition, type ProcessorDefinition, type ProjectFileEntry, type ProjectTarget, type ProjectTargetEntry, type RuleCacheConfig, type RuleConfigEntry, type RuleContext, type RuleDefinition, type RuleHandlers, type RuleInferenceUsageRecord, type RuleOptionsInput, type RuleOptionsOutput, type RuleOptionsSchema, type RuleRegistry, type RuleSeverity, type RuleSpecializedHandlers, type RuleWithHandler, type StopGateConfig, type StopGateTarget, type Target, defineConfig, definePlugin, defineRule };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
1
2
|
import { readFile } from "node:fs/promises";
|
|
2
3
|
import { extname } from "node:path";
|
|
3
4
|
import { clamp } from "es-toolkit";
|
|
4
|
-
import { createHash } from "node:crypto";
|
|
5
5
|
import { parseSync } from "oxc-parser";
|
|
6
6
|
//#region src/core/hash.ts
|
|
7
7
|
function createStableHasher() {
|
|
@@ -173,11 +173,11 @@ function targetIdentity(kind, name, range) {
|
|
|
173
173
|
/**
|
|
174
174
|
* Swaps a target's positional identity for its name, where that name is unique among these targets.
|
|
175
175
|
*
|
|
176
|
-
*
|
|
177
|
-
* sharing a name cannot be told apart
|
|
176
|
+
* Caches are keyed by identity, so a function that only moved should keep the identity it had. Two
|
|
177
|
+
* targets sharing a name cannot be told apart by name, so those keep the positional form.
|
|
178
178
|
*
|
|
179
|
-
* Run every function and class target through this.
|
|
180
|
-
*
|
|
179
|
+
* Run every function and class target through this. Miss it in one language and the same function
|
|
180
|
+
* gets a different identity depending on which language read it.
|
|
181
181
|
*/
|
|
182
182
|
function withStableIdentities(targets) {
|
|
183
183
|
const nameCounts = /* @__PURE__ */ new Map();
|
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { A as
|
|
1
|
+
import { A as RuleSpecializedHandlers, B as ModelRequirement, C as RuleHandlers, G as ProviderDefinition, H as ResolvedModel, J as RunnerStatsConfig, K as ProviderType, M as StopGateConfig, N as StopGateTarget, O as RuleRegistry, P as Target, S as RuleDefinition, U as ResolvedProvider, V as ResolveModelOptions, W as ModelSize, X as SetupModelDefinition, Y as SetupConfig, _ as ProjectTarget, a as AlintLinterOptions, b as RuleConfigEntry, c as DiagnosticLocation, d as IgnoreConfig, f as IntegrationsConfig, g as ProjectFileEntry, h as ProcessorDefinition, i as AlintConfigItem, j as RuleWithHandler, k as RuleSeverity, l as DirectoryTarget, m as PluginDefinition, n as AlintConfigExtends, o as Awaitable, p as LanguageDefinition, q as RunnerConfig, r as AlintConfigInput, s as DiagnosticDescriptor, t as AlintConfig, u as EnabledRule, v as ProjectTargetEntry, w as RuleInferenceUsageRecord, x as RuleContext, y as RuleCacheConfig } from "./types-Cm5Z7Fll.mjs";
|
|
2
2
|
import { C as SourceTarget, D as SourceTargetOrigin, E as SourceTargetOfKind, O as SourceText, S as SourceRuntime, T as SourceTargetMetadata, _ as SourceLocation, a as FunctionInfo, b as SourcePosition, c as LineRange, d as ProcessedSource, f as ProcessedSourceOrigin, g as SourceFile, h as SourceExtractOptions, i as FileTarget, l as PlannedSourceTarget, m as ProcessorPostprocessContext, n as CallSite, o as FunctionTarget, p as ProcessorContext, r as ClassTarget, s as LanguageContext, t as BaseSourceFile, u as PlannedSourceTargetOfKind, v as SourceMetadataObject, w as SourceTargetKind, x as SourceRange, y as SourceMetadataValue } from "./types-DM4idR4w.mjs";
|
|
3
|
-
import { n as definePlugin, r as defineRule, t as defineConfig } from "./define-
|
|
3
|
+
import { n as definePlugin, r as defineRule, t as defineConfig } from "./define-DO36VJ4W.mjs";
|
|
4
4
|
//#region src/config/config-array.d.ts
|
|
5
5
|
interface EffectiveAlintConfig {
|
|
6
6
|
agent?: AlintConfigItem['agent'];
|
|
@@ -32,6 +32,19 @@ declare function resolveConfigForDirectory(directoryPath: string, input: AlintCo
|
|
|
32
32
|
declare function resolveConfigForFile(filePath: string, input: AlintConfig, options: ResolveConfigOptions): ResolveConfigResult;
|
|
33
33
|
declare function resolveConfigForProject(projectPath: string, input: AlintConfig, options: ResolveConfigOptions): ResolveConfigResult;
|
|
34
34
|
//#endregion
|
|
35
|
+
//#region src/config/stop-gate.d.ts
|
|
36
|
+
interface ResolvedStopGateConfig {
|
|
37
|
+
enabled: boolean;
|
|
38
|
+
target: StopGateTarget;
|
|
39
|
+
timeoutMs: number;
|
|
40
|
+
}
|
|
41
|
+
declare const maximumStopGateTimeoutMs: number;
|
|
42
|
+
declare const defaultStopGateConfig: Readonly<ResolvedStopGateConfig>;
|
|
43
|
+
declare function resolveStopGateConfig(config: AlintConfig, cwd: string): ResolvedStopGateConfig;
|
|
44
|
+
//#endregion
|
|
45
|
+
//#region src/core/hash.d.ts
|
|
46
|
+
declare function stableHash(value: unknown): string;
|
|
47
|
+
//#endregion
|
|
35
48
|
//#region src/core/languages/registry.d.ts
|
|
36
49
|
interface LanguageRegistry {
|
|
37
50
|
byExtension: Map<string, string>;
|
|
@@ -270,6 +283,10 @@ declare class AlintAbortError extends AlintRunCancelledError {
|
|
|
270
283
|
cause?: unknown;
|
|
271
284
|
});
|
|
272
285
|
}
|
|
286
|
+
declare class AlintCachePersistenceError extends Error {
|
|
287
|
+
readonly result: RunResult;
|
|
288
|
+
constructor(result: RunResult, cause: unknown);
|
|
289
|
+
}
|
|
273
290
|
declare class AlintRunError extends Error {
|
|
274
291
|
readonly failures: AlintRunFailure[];
|
|
275
292
|
readonly result: RunResult;
|
|
@@ -286,11 +303,11 @@ declare function targetIdentity(kind: SourceTargetKind, name: string | undefined
|
|
|
286
303
|
/**
|
|
287
304
|
* Swaps a target's positional identity for its name, where that name is unique among these targets.
|
|
288
305
|
*
|
|
289
|
-
*
|
|
290
|
-
* sharing a name cannot be told apart
|
|
306
|
+
* Caches are keyed by identity, so a function that only moved should keep the identity it had. Two
|
|
307
|
+
* targets sharing a name cannot be told apart by name, so those keep the positional form.
|
|
291
308
|
*
|
|
292
|
-
* Run every function and class target through this.
|
|
293
|
-
*
|
|
309
|
+
* Run every function and class target through this. Miss it in one language and the same function
|
|
310
|
+
* gets a different identity depending on which language read it.
|
|
294
311
|
*/
|
|
295
312
|
declare function withStableIdentities(targets: readonly SourceTarget[]): SourceTarget[];
|
|
296
313
|
//#endregion
|
|
@@ -380,4 +397,4 @@ declare function benchmarkModels(config: SetupConfig, options?: BenchmarkModelsO
|
|
|
380
397
|
//#region src/models/resolve.d.ts
|
|
381
398
|
declare function resolveModel(registry: SetupConfig, options?: ResolveModelOptions): ResolvedModel;
|
|
382
399
|
//#endregion
|
|
383
|
-
export { AlintAbortError, type AlintConfig, type AlintConfigExtends, type AlintConfigInput, type AlintConfigItem, type AlintFailureCause, type AlintFileFailure, type AlintLinterOptions, type AlintRuleFailure, AlintRunCancelledError, AlintRunError, type AlintRunFailure, type Awaitable, type BaseSourceFile, type BenchmarkModelsOptions, type CallSite, type ClassTarget, type Diagnostic, type DiagnosticDescriptor, type DiagnosticLocation, type DiagnosticProgressPayload, type DirectoryTarget, type EffectiveAlintConfig, type EnabledRule, type ExecutionCounts, type ExecutionProgressPayload, type FileReadyPayload, type FileTarget, type FunctionInfo, type FunctionTarget, type IgnoreConfig, type InferenceUsageRecord, type JobEndPayload, type JobQueuedPayload, type JobRetryPayload, type JobStartPayload, type LanguageContext, type LanguageDefinition, type LanguageRegistry, type LineRange, type ModelBenchmarkActive, type ModelBenchmarkMeasurement, type ModelBenchmarkProgress, type ModelBenchmarkRequest, type ModelBenchmarkResult, type ModelRequirement, type ModelSize, type PlannedSourceTarget, type PlannedSourceTargetOfKind, type PluginDefinition, type PrepareEndPayload, type PrepareStartPayload, type ProcessedSource, type ProcessedSourceOrigin, type ProcessorContext, type ProcessorDefinition, type ProcessorPostprocessContext, type ProgressJobRef, type ProgressReporter, type ProgressSnapshot, type ProgressTargetKind, type ProjectFileEntry, type ProjectTarget, type ProjectTargetEntry, type ProviderDefinition, type ProviderType, type ResolveConfigResult, type ResolveLanguageOptions, type ResolveModelOptions, type ResolvedModel, type ResolvedProvider, type RuleCacheConfig, type RuleConfigEntry, type RuleContext, type RuleDefinition, type RuleHandlers, type RuleInferenceUsageRecord, type RuleRegistry, type RuleSeverity, type RuleSpecializedHandlers, type RuleWithHandler, type RunEndPayload, type RunExecution, type RunOptions, type RunResult, type RunUsage, type RunUsageTotals, type RunnerConfig, type RunnerStatsConfig, type SetupConfig, type SetupModelDefinition, type SourceExtractOptions, type SourceFile, type SourceLocation, type SourceMetadataObject, type SourceMetadataValue, type SourcePosition, type SourceRange, type SourceRuntime, type SourceRuntimeOptions, type SourceTarget, type SourceTargetKind, type SourceTargetMetadata, type SourceTargetOfKind, type SourceTargetOrigin, type SourceText, type Target, type UsageProgressPayload, benchmarkModels, buildRuleRegistry, createBuiltInLanguageRegistry, createSourceExtractor, createSourceFile, createSourceRuntime, defineConfig, definePlugin, defineRule, hasDiscoveryFilePatterns, matchesDiscoveryFile, normalizeConfig, registerLanguage, resolveConfigForDirectory, resolveConfigForFile, resolveConfigForProject, resolveLanguage, resolveModel, runAlint, sliceLines, sliceRange, targetIdentity, withLanguage, withStableIdentities };
|
|
400
|
+
export { AlintAbortError, AlintCachePersistenceError, type AlintConfig, type AlintConfigExtends, type AlintConfigInput, type AlintConfigItem, type AlintFailureCause, type AlintFileFailure, type AlintLinterOptions, type AlintRuleFailure, AlintRunCancelledError, AlintRunError, type AlintRunFailure, type Awaitable, type BaseSourceFile, type BenchmarkModelsOptions, type CallSite, type ClassTarget, type Diagnostic, type DiagnosticDescriptor, type DiagnosticLocation, type DiagnosticProgressPayload, type DirectoryTarget, type EffectiveAlintConfig, type EnabledRule, type ExecutionCounts, type ExecutionProgressPayload, type FileReadyPayload, type FileTarget, type FunctionInfo, type FunctionTarget, type IgnoreConfig, type InferenceUsageRecord, type IntegrationsConfig, type JobEndPayload, type JobQueuedPayload, type JobRetryPayload, type JobStartPayload, type LanguageContext, type LanguageDefinition, type LanguageRegistry, type LineRange, type ModelBenchmarkActive, type ModelBenchmarkMeasurement, type ModelBenchmarkProgress, type ModelBenchmarkRequest, type ModelBenchmarkResult, type ModelRequirement, type ModelSize, type PlannedSourceTarget, type PlannedSourceTargetOfKind, type PluginDefinition, type PrepareEndPayload, type PrepareStartPayload, type ProcessedSource, type ProcessedSourceOrigin, type ProcessorContext, type ProcessorDefinition, type ProcessorPostprocessContext, type ProgressJobRef, type ProgressReporter, type ProgressSnapshot, type ProgressTargetKind, type ProjectFileEntry, type ProjectTarget, type ProjectTargetEntry, type ProviderDefinition, type ProviderType, type ResolveConfigResult, type ResolveLanguageOptions, type ResolveModelOptions, type ResolvedModel, type ResolvedProvider, type ResolvedStopGateConfig, type RuleCacheConfig, type RuleConfigEntry, type RuleContext, type RuleDefinition, type RuleHandlers, type RuleInferenceUsageRecord, type RuleRegistry, type RuleSeverity, type RuleSpecializedHandlers, type RuleWithHandler, type RunEndPayload, type RunExecution, type RunOptions, type RunResult, type RunUsage, type RunUsageTotals, type RunnerConfig, type RunnerStatsConfig, type SetupConfig, type SetupModelDefinition, type SourceExtractOptions, type SourceFile, type SourceLocation, type SourceMetadataObject, type SourceMetadataValue, type SourcePosition, type SourceRange, type SourceRuntime, type SourceRuntimeOptions, type SourceTarget, type SourceTargetKind, type SourceTargetMetadata, type SourceTargetOfKind, type SourceTargetOrigin, type SourceText, type StopGateConfig, type StopGateTarget, type Target, type UsageProgressPayload, benchmarkModels, buildRuleRegistry, createBuiltInLanguageRegistry, createSourceExtractor, createSourceFile, createSourceRuntime, defaultStopGateConfig, defineConfig, definePlugin, defineRule, hasDiscoveryFilePatterns, matchesDiscoveryFile, maximumStopGateTimeoutMs, normalizeConfig, registerLanguage, resolveConfigForDirectory, resolveConfigForFile, resolveConfigForProject, resolveLanguage, resolveModel, resolveStopGateConfig, runAlint, sliceLines, sliceRange, stableHash, targetIdentity, withLanguage, withStableIdentities };
|
package/dist/index.mjs
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import { o as withAgentRetry, t as combineAbortSignals } from "./agent-B6GG68NX.mjs";
|
|
2
2
|
import { n as definePlugin, r as defineRule, t as defineConfig } from "./define-Da342Fcx.mjs";
|
|
3
|
-
import { a as createSourceFile, c as sliceRange, d as stableHash, i as SourceChangedError, l as withLanguage, n as targetIdentity, o as createSourceRuntime, r as withStableIdentities, s as sliceLines, t as extractJsSourceTargets, u as createStableHasher } from "./extract-
|
|
3
|
+
import { a as createSourceFile, c as sliceRange, d as stableHash, i as SourceChangedError, l as withLanguage, n as targetIdentity, o as createSourceRuntime, r as withStableIdentities, s as sliceLines, t as extractJsSourceTargets, u as createStableHasher } from "./extract-DhLFgRej.mjs";
|
|
4
4
|
import { minimatch } from "minimatch";
|
|
5
5
|
import { basename, extname, isAbsolute, relative, resolve } from "pathe";
|
|
6
|
-
import {
|
|
7
|
-
import { basename as basename$1, dirname, extname as extname$1, isAbsolute as isAbsolute$1, join, relative as relative$1, resolve as resolve$1, sep } from "node:path";
|
|
6
|
+
import { array, boolean, check, custom, finite, getDotPath, integer, literal, looseObject, maxValue, minValue, number, object, optional, parse, picklist, pipe, record, safeParse, string, union, unknown } from "valibot";
|
|
8
7
|
import { randomUUID } from "node:crypto";
|
|
8
|
+
import { access, appendFile, mkdir, open, readFile, rename, rm, writeFile } from "node:fs/promises";
|
|
9
|
+
import { basename as basename$1, dirname, extname as extname$1, isAbsolute as isAbsolute$1, join, relative as relative$1, resolve as resolve$1, sep } from "node:path";
|
|
9
10
|
import process, { cwd } from "node:process";
|
|
10
|
-
import { array, boolean, check, custom, finite, getDotPath, literal, number, object, optional, parse, pipe, record, safeParse, string, union, unknown } from "valibot";
|
|
11
11
|
import { Buffer } from "node:buffer";
|
|
12
12
|
import { statSync } from "node:fs";
|
|
13
|
+
import lockfile from "proper-lockfile";
|
|
14
|
+
import { isNodeErrorCode } from "@alint-js/utils/node";
|
|
13
15
|
import { errorMessageFrom } from "@moeru/std/error";
|
|
14
16
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
15
17
|
import { streamText } from "@xsai/stream-text";
|
|
@@ -236,6 +238,37 @@ function withExpansionMetadata(item, inheritedMatcherScopes, effectiveBasePath)
|
|
|
236
238
|
return item;
|
|
237
239
|
}
|
|
238
240
|
//#endregion
|
|
241
|
+
//#region src/config/stop-gate.ts
|
|
242
|
+
const maximumStopGateTimeoutMs = 861e5;
|
|
243
|
+
const defaultStopGateConfig = {
|
|
244
|
+
enabled: false,
|
|
245
|
+
target: "dirty-files",
|
|
246
|
+
timeoutMs: 9e5
|
|
247
|
+
};
|
|
248
|
+
const stopGateConfigSchema = looseObject({
|
|
249
|
+
enabled: optional(boolean("integrations.stopGate.enabled must be a boolean.")),
|
|
250
|
+
target: optional(picklist(["all", "dirty-files"], "integrations.stopGate.target must be \"all\" or \"dirty-files\".")),
|
|
251
|
+
timeoutMs: optional(pipe(number(`integrations.stopGate.timeoutMs must be an integer from 1 to ${maximumStopGateTimeoutMs}.`), integer(`integrations.stopGate.timeoutMs must be an integer from 1 to ${maximumStopGateTimeoutMs}.`), minValue(1, `integrations.stopGate.timeoutMs must be an integer from 1 to ${maximumStopGateTimeoutMs}.`), maxValue(maximumStopGateTimeoutMs, `integrations.stopGate.timeoutMs must be an integer from 1 to ${maximumStopGateTimeoutMs}.`)))
|
|
252
|
+
}, "integrations.stopGate must be an object.");
|
|
253
|
+
function resolveStopGateConfig(config, cwd) {
|
|
254
|
+
const project = resolveConfigForProject(cwd, config, { cwd });
|
|
255
|
+
for (const skipped of project.skipped) if (skipped.item.integrations?.stopGate !== void 0) throw new Error("integrations.stopGate must be declared in a global config item without files, directories, or ignores.");
|
|
256
|
+
return project.matched.reduce((resolved, item) => mergeStopGateConfig(resolved, item), { ...defaultStopGateConfig });
|
|
257
|
+
}
|
|
258
|
+
function assertStopGateConfig(value) {
|
|
259
|
+
parse(stopGateConfigSchema, value);
|
|
260
|
+
}
|
|
261
|
+
function mergeStopGateConfig(resolved, item) {
|
|
262
|
+
const stopGate = item.integrations?.stopGate;
|
|
263
|
+
if (stopGate === void 0) return resolved;
|
|
264
|
+
assertStopGateConfig(stopGate);
|
|
265
|
+
return {
|
|
266
|
+
enabled: stopGate.enabled ?? resolved.enabled,
|
|
267
|
+
target: stopGate.target ?? resolved.target,
|
|
268
|
+
timeoutMs: stopGate.timeoutMs ?? resolved.timeoutMs
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
//#endregion
|
|
239
272
|
//#region src/core/languages/js/index.ts
|
|
240
273
|
const javascriptLanguage = {
|
|
241
274
|
extensions: [
|
|
@@ -299,7 +332,10 @@ function resolveLanguage(file, registry, options) {
|
|
|
299
332
|
function resolveLanguageForPath(filePath, registry, options) {
|
|
300
333
|
const languageName = options.language ?? options.processedLanguage ?? registry.byExtension.get(extname$1(filePath)) ?? "plaintext";
|
|
301
334
|
const language = registry.languages.get(languageName);
|
|
302
|
-
if (!language)
|
|
335
|
+
if (!language) {
|
|
336
|
+
const registered = [...registry.languages.keys()].sort().join(", ");
|
|
337
|
+
throw new Error(`Unknown language "${languageName}". Languages come from plugins, and these are registered: ${registered}.`);
|
|
338
|
+
}
|
|
303
339
|
return language;
|
|
304
340
|
}
|
|
305
341
|
//#endregion
|
|
@@ -602,13 +638,16 @@ function recordMissingLanguages(into, rules, registry, path) {
|
|
|
602
638
|
}
|
|
603
639
|
//#endregion
|
|
604
640
|
//#region package.json
|
|
605
|
-
var version = "0.
|
|
641
|
+
var version = "0.6.0";
|
|
606
642
|
//#endregion
|
|
607
643
|
//#region src/core/cache/types.ts
|
|
608
644
|
const CACHE_MAGIC = "ALINT_CACHE";
|
|
609
645
|
//#endregion
|
|
610
646
|
//#region src/core/cache/store.ts
|
|
611
647
|
const DEFAULT_CACHE_FILE_NAME = ".alintcache";
|
|
648
|
+
const LOCK_STALE_MS = 2e4;
|
|
649
|
+
const LOCK_UPDATE_MS = 3e3;
|
|
650
|
+
const METADATA_READ_LIMIT = 4096;
|
|
612
651
|
const FiniteNumberSchema = pipe(number(), finite());
|
|
613
652
|
const PositionSchema = object({
|
|
614
653
|
column: FiniteNumberSchema,
|
|
@@ -668,18 +707,19 @@ const CacheEntrySchema = object({
|
|
|
668
707
|
}),
|
|
669
708
|
usage: array(UsageSchema)
|
|
670
709
|
});
|
|
710
|
+
const CachedOwnerSchema = object({
|
|
711
|
+
contentHash: optional(string()),
|
|
712
|
+
kind: union([literal("file"), literal("project")]),
|
|
713
|
+
path: string(),
|
|
714
|
+
slots: array(string())
|
|
715
|
+
});
|
|
671
716
|
function objectRecord(value) {
|
|
672
717
|
return pipe(unknown(), check((input) => typeof input === "object" && input !== null && !Array.isArray(input)), record(string(), value));
|
|
673
718
|
}
|
|
674
719
|
const CacheFileBodySchema = pipe(object({
|
|
675
720
|
createdAt: string(),
|
|
676
721
|
entries: objectRecord(CacheEntrySchema),
|
|
677
|
-
owners: objectRecord(
|
|
678
|
-
contentHash: optional(string()),
|
|
679
|
-
kind: union([literal("file"), literal("project")]),
|
|
680
|
-
path: string(),
|
|
681
|
-
slots: array(string())
|
|
682
|
-
})),
|
|
722
|
+
owners: objectRecord(CachedOwnerSchema),
|
|
683
723
|
updatedAt: string()
|
|
684
724
|
}), check((body) => {
|
|
685
725
|
const entryKeys = Object.keys(body.entries);
|
|
@@ -687,22 +727,68 @@ const CacheFileBodySchema = pipe(object({
|
|
|
687
727
|
const uniqueSlots = new Set(referencedSlots);
|
|
688
728
|
return uniqueSlots.size === referencedSlots.length && uniqueSlots.size === entryKeys.length && entryKeys.every((key) => uniqueSlots.has(key));
|
|
689
729
|
}));
|
|
730
|
+
const CacheMetadataSchema = object({
|
|
731
|
+
alintVersion: string(),
|
|
732
|
+
createdAt: string(),
|
|
733
|
+
magic: literal(CACHE_MAGIC),
|
|
734
|
+
schemaVersion: literal(2),
|
|
735
|
+
type: literal("metadata")
|
|
736
|
+
});
|
|
737
|
+
const PutEventSchema = object({
|
|
738
|
+
at: string(),
|
|
739
|
+
entry: CacheEntrySchema,
|
|
740
|
+
owner: CachedOwnerSchema,
|
|
741
|
+
ownerKey: string(),
|
|
742
|
+
slotKey: string(),
|
|
743
|
+
type: literal("put")
|
|
744
|
+
});
|
|
745
|
+
const ReplaceOwnerEventSchema = object({
|
|
746
|
+
at: string(),
|
|
747
|
+
entries: array(object({
|
|
748
|
+
entry: CacheEntrySchema,
|
|
749
|
+
slotKey: string()
|
|
750
|
+
})),
|
|
751
|
+
mode: union([literal("merge"), literal("replace")]),
|
|
752
|
+
owner: CachedOwnerSchema,
|
|
753
|
+
ownerKey: string(),
|
|
754
|
+
type: literal("replace-owner")
|
|
755
|
+
});
|
|
756
|
+
const RemoveOwnerEventSchema = object({
|
|
757
|
+
at: string(),
|
|
758
|
+
ownerKey: string(),
|
|
759
|
+
type: literal("remove-owner")
|
|
760
|
+
});
|
|
761
|
+
const CacheEventSchema = union([
|
|
762
|
+
PutEventSchema,
|
|
763
|
+
ReplaceOwnerEventSchema,
|
|
764
|
+
RemoveOwnerEventSchema
|
|
765
|
+
]);
|
|
690
766
|
async function createCacheStore(options) {
|
|
691
767
|
const location = resolveCacheLocation(options.cwd, options.location);
|
|
692
768
|
if (!options.enabled) return createNoopCacheStore(location);
|
|
693
769
|
const alintVersion = options.alintVersion ?? version;
|
|
694
|
-
const
|
|
695
|
-
|
|
696
|
-
|
|
770
|
+
const initial = await loadCacheLog(location, alintVersion);
|
|
771
|
+
if (options.readOnly) return createReadOnlyCacheStore(location, initial.body, options.cwd);
|
|
772
|
+
const dependencies = {
|
|
773
|
+
append: options.appendFile ?? appendFile,
|
|
774
|
+
lock: options.lock ?? { acquire: lockfile.lock },
|
|
775
|
+
write: options.writeFile ?? writeFile
|
|
776
|
+
};
|
|
777
|
+
const trimmed = await trimOnce(location, alintVersion, initial, dependencies);
|
|
778
|
+
const writer = createEventWriter(location, trimmed.metadata, dependencies);
|
|
697
779
|
const fileExists = options.fileExists ?? defaultFileExists;
|
|
698
|
-
const writeFile$1 = options.writeFile ?? writeFile;
|
|
699
780
|
return {
|
|
700
|
-
beginOwner: (owner) => beginOwner(body, owner, options.cwd),
|
|
781
|
+
beginOwner: (owner, metadata) => beginOwner(trimmed.body, owner, options.cwd, writer, metadata),
|
|
782
|
+
flush: () => writer.flush(false),
|
|
701
783
|
location,
|
|
702
784
|
reconcile: async () => {
|
|
703
|
-
await collectMissingFileOwners(body, options.cwd, fileExists);
|
|
704
|
-
|
|
705
|
-
|
|
785
|
+
const removedOwners = await collectMissingFileOwners(trimmed.body, options.cwd, fileExists);
|
|
786
|
+
for (const ownerKey of removedOwners) writer.enqueue({
|
|
787
|
+
at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
788
|
+
ownerKey,
|
|
789
|
+
type: "remove-owner"
|
|
790
|
+
});
|
|
791
|
+
await writer.flush(true);
|
|
706
792
|
}
|
|
707
793
|
};
|
|
708
794
|
}
|
|
@@ -754,7 +840,50 @@ function resolveCacheLocation(cwd, location) {
|
|
|
754
840
|
} catch {}
|
|
755
841
|
return resolved;
|
|
756
842
|
}
|
|
757
|
-
function
|
|
843
|
+
async function appendBatch(location, payload, append) {
|
|
844
|
+
const handle = await open(location, "a+");
|
|
845
|
+
try {
|
|
846
|
+
const { size } = await handle.stat();
|
|
847
|
+
let separator = "";
|
|
848
|
+
if (size > 0) {
|
|
849
|
+
const finalByte = Buffer.alloc(1);
|
|
850
|
+
await handle.read(finalByte, 0, 1, size - 1);
|
|
851
|
+
separator = finalByte[0] === 10 ? "" : "\n";
|
|
852
|
+
}
|
|
853
|
+
await append(location, `${separator}${payload}`, "utf8");
|
|
854
|
+
} finally {
|
|
855
|
+
await handle.close();
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
function applyEvent(body, event) {
|
|
859
|
+
if (event.type === "remove-owner") {
|
|
860
|
+
removeOwner(body, event.ownerKey);
|
|
861
|
+
body.updatedAt = event.at;
|
|
862
|
+
return;
|
|
863
|
+
}
|
|
864
|
+
if (event.type === "put") {
|
|
865
|
+
const current = body.owners[event.ownerKey];
|
|
866
|
+
const slots = new Set(current?.slots ?? []);
|
|
867
|
+
slots.add(event.slotKey);
|
|
868
|
+
body.entries[event.slotKey] = event.entry;
|
|
869
|
+
body.owners[event.ownerKey] = {
|
|
870
|
+
...event.owner,
|
|
871
|
+
slots: [...slots].sort()
|
|
872
|
+
};
|
|
873
|
+
body.updatedAt = event.at;
|
|
874
|
+
return;
|
|
875
|
+
}
|
|
876
|
+
const entries = event.mode === "merge" ? ownerEntries(body, body.owners[event.ownerKey]) : /* @__PURE__ */ new Map();
|
|
877
|
+
for (const item of event.entries) entries.set(item.slotKey, item.entry);
|
|
878
|
+
for (const slot of body.owners[event.ownerKey]?.slots ?? []) delete body.entries[slot];
|
|
879
|
+
for (const [slotKey, entry] of entries) body.entries[slotKey] = entry;
|
|
880
|
+
body.owners[event.ownerKey] = {
|
|
881
|
+
...event.owner,
|
|
882
|
+
slots: [...entries.keys()].sort()
|
|
883
|
+
};
|
|
884
|
+
body.updatedAt = event.at;
|
|
885
|
+
}
|
|
886
|
+
function beginOwner(body, owner, cwd, writer, ownerMetadata = {}) {
|
|
758
887
|
const normalizedOwner = {
|
|
759
888
|
kind: owner.kind,
|
|
760
889
|
path: normalizeCachePath(cwd, owner.path)
|
|
@@ -762,22 +891,64 @@ function beginOwner(body, owner, cwd) {
|
|
|
762
891
|
const key = ownerKey(normalizedOwner, cwd);
|
|
763
892
|
const previousOwner = body.owners[key];
|
|
764
893
|
const nextEntries = /* @__PURE__ */ new Map();
|
|
894
|
+
const checkpointEntries = /* @__PURE__ */ new Map();
|
|
895
|
+
const commit = (metadata = {}) => {
|
|
896
|
+
const contentHash = metadata.contentHash ?? ownerMetadata.contentHash;
|
|
897
|
+
const committedEntries = metadata.mode === "merge" ? ownerEntries(body, body.owners[key]) : /* @__PURE__ */ new Map();
|
|
898
|
+
for (const [entryKey, cacheEntry] of nextEntries) committedEntries.set(entryKey, cacheEntry);
|
|
899
|
+
const replacedSlots = /* @__PURE__ */ new Set([...previousOwner?.slots ?? [], ...body.owners[key]?.slots ?? []]);
|
|
900
|
+
for (const replacedSlot of replacedSlots) delete body.entries[replacedSlot];
|
|
901
|
+
for (const [entryKey, cacheEntry] of committedEntries) body.entries[entryKey] = cacheEntry;
|
|
902
|
+
const cachedOwner = {
|
|
903
|
+
contentHash,
|
|
904
|
+
kind: normalizedOwner.kind,
|
|
905
|
+
path: normalizedOwner.path,
|
|
906
|
+
slots: [...committedEntries.keys()].sort()
|
|
907
|
+
};
|
|
908
|
+
body.owners[key] = cachedOwner;
|
|
909
|
+
body.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
910
|
+
writer.enqueue({
|
|
911
|
+
at: body.updatedAt,
|
|
912
|
+
entries: [...committedEntries].map(([slotKey, entry]) => ({
|
|
913
|
+
entry,
|
|
914
|
+
slotKey
|
|
915
|
+
})),
|
|
916
|
+
mode: metadata.mode ?? "replace",
|
|
917
|
+
owner: cachedOwner,
|
|
918
|
+
ownerKey: key,
|
|
919
|
+
type: "replace-owner"
|
|
920
|
+
});
|
|
921
|
+
checkpointEntries.clear();
|
|
922
|
+
};
|
|
765
923
|
return {
|
|
766
|
-
|
|
767
|
-
const
|
|
768
|
-
|
|
769
|
-
const replacedSlots = /* @__PURE__ */ new Set([...previousOwner?.slots ?? [], ...body.owners[key]?.slots ?? []]);
|
|
770
|
-
for (const replacedSlot of replacedSlots) delete body.entries[replacedSlot];
|
|
771
|
-
for (const [entryKey, cacheEntry] of committedEntries) body.entries[entryKey] = cacheEntry;
|
|
772
|
-
body.owners[key] = {
|
|
773
|
-
contentHash: metadata.contentHash,
|
|
924
|
+
checkpoint: async () => {
|
|
925
|
+
const cachedOwner = {
|
|
926
|
+
contentHash: ownerMetadata.contentHash,
|
|
774
927
|
kind: normalizedOwner.kind,
|
|
775
928
|
path: normalizedOwner.path,
|
|
776
|
-
slots: [
|
|
929
|
+
slots: []
|
|
777
930
|
};
|
|
778
|
-
|
|
931
|
+
for (const [entryKey, cacheEntry] of checkpointEntries) {
|
|
932
|
+
const event = {
|
|
933
|
+
at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
934
|
+
entry: cacheEntry,
|
|
935
|
+
owner: cachedOwner,
|
|
936
|
+
ownerKey: key,
|
|
937
|
+
slotKey: entryKey,
|
|
938
|
+
type: "put"
|
|
939
|
+
};
|
|
940
|
+
applyEvent(body, event);
|
|
941
|
+
writer.enqueue(event);
|
|
942
|
+
}
|
|
943
|
+
checkpointEntries.clear();
|
|
944
|
+
await writer.flush(false);
|
|
945
|
+
},
|
|
946
|
+
commit,
|
|
947
|
+
discard: (cacheSlot) => {
|
|
948
|
+
const entryKey = slotKey(normalizedOwner, cacheSlot, cwd);
|
|
949
|
+
nextEntries.delete(entryKey);
|
|
950
|
+
checkpointEntries.delete(entryKey);
|
|
779
951
|
},
|
|
780
|
-
discard: (cacheSlot) => nextEntries.delete(slotKey(normalizedOwner, cacheSlot, cwd)),
|
|
781
952
|
lookup: (cacheSlot, fingerprint) => {
|
|
782
953
|
const entryKey = slotKey(normalizedOwner, cacheSlot, cwd);
|
|
783
954
|
const cached = body.entries[entryKey];
|
|
@@ -785,15 +956,21 @@ function beginOwner(body, owner, cwd) {
|
|
|
785
956
|
nextEntries.set(entryKey, cached);
|
|
786
957
|
return cached;
|
|
787
958
|
},
|
|
788
|
-
put: (cacheSlot, cacheEntry) =>
|
|
959
|
+
put: (cacheSlot, cacheEntry) => {
|
|
960
|
+
const entryKey = slotKey(normalizedOwner, cacheSlot, cwd);
|
|
961
|
+
nextEntries.set(entryKey, cacheEntry);
|
|
962
|
+
checkpointEntries.set(entryKey, cacheEntry);
|
|
963
|
+
}
|
|
789
964
|
};
|
|
790
965
|
}
|
|
791
966
|
async function collectMissingFileOwners(body, cwd, fileExists) {
|
|
967
|
+
const removed = [];
|
|
792
968
|
for (const [key, owner] of Object.entries(body.owners)) {
|
|
793
969
|
if (owner.kind !== "file" || await fileExists(resolve$1(cwd, owner.path))) continue;
|
|
794
|
-
|
|
795
|
-
|
|
970
|
+
removeOwner(body, key);
|
|
971
|
+
removed.push(key);
|
|
796
972
|
}
|
|
973
|
+
return removed;
|
|
797
974
|
}
|
|
798
975
|
function createBaseTargetIdentity(target) {
|
|
799
976
|
if (target.identity && (target.kind !== "file" || target.identity !== "file")) return target.filePath ? `${target.kind}:${target.filePath}:${target.identity}` : `${target.kind}:${target.identity}`;
|
|
@@ -802,17 +979,53 @@ function createBaseTargetIdentity(target) {
|
|
|
802
979
|
if (target.range) return `${target.kind}:${target.range.start}:${target.range.end}`;
|
|
803
980
|
return target.kind;
|
|
804
981
|
}
|
|
805
|
-
function createEmptyCacheBody() {
|
|
806
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
982
|
+
function createEmptyCacheBody(createdAt = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
807
983
|
return {
|
|
808
|
-
createdAt
|
|
984
|
+
createdAt,
|
|
809
985
|
entries: {},
|
|
810
986
|
owners: {},
|
|
811
|
-
updatedAt:
|
|
987
|
+
updatedAt: createdAt
|
|
988
|
+
};
|
|
989
|
+
}
|
|
990
|
+
function createEventWriter(location, metadata, dependencies) {
|
|
991
|
+
const backlog = [];
|
|
992
|
+
let validationError;
|
|
993
|
+
let previousWrite = Promise.resolve();
|
|
994
|
+
const persistBacklog = async () => {
|
|
995
|
+
if (validationError) throw validationError;
|
|
996
|
+
if (backlog.length === 0) return;
|
|
997
|
+
await mkdir(dirname(location), { recursive: true });
|
|
998
|
+
await withCacheLock(location, dependencies.lock, getCacheLockOptions({
|
|
999
|
+
factor: 2,
|
|
1000
|
+
maxTimeout: 16e3,
|
|
1001
|
+
minTimeout: 2e3,
|
|
1002
|
+
retries: 4
|
|
1003
|
+
}), async () => {
|
|
1004
|
+
await ensureCompatibleMetadata(location, metadata, dependencies.write);
|
|
1005
|
+
const batchSize = backlog.length;
|
|
1006
|
+
await appendBatch(location, backlog.slice(0, batchSize).map((event) => `${JSON.stringify(event)}\n`).join(""), dependencies.append);
|
|
1007
|
+
backlog.splice(0, batchSize);
|
|
1008
|
+
});
|
|
1009
|
+
validationError = void 0;
|
|
1010
|
+
};
|
|
1011
|
+
return {
|
|
1012
|
+
enqueue: (event) => {
|
|
1013
|
+
try {
|
|
1014
|
+
backlog.push(parse(CacheEventSchema, event));
|
|
1015
|
+
} catch (error) {
|
|
1016
|
+
validationError ??= error;
|
|
1017
|
+
}
|
|
1018
|
+
},
|
|
1019
|
+
flush: (finalAttempt) => {
|
|
1020
|
+
const write = previousWrite.then(persistBacklog);
|
|
1021
|
+
previousWrite = write.catch(() => {});
|
|
1022
|
+
return finalAttempt ? write : write.catch(() => {});
|
|
1023
|
+
}
|
|
812
1024
|
};
|
|
813
1025
|
}
|
|
814
1026
|
function createNoopCacheStore(location) {
|
|
815
1027
|
const transaction = {
|
|
1028
|
+
checkpoint: async () => {},
|
|
816
1029
|
commit: () => {},
|
|
817
1030
|
discard: () => {},
|
|
818
1031
|
lookup: () => void 0,
|
|
@@ -820,22 +1033,24 @@ function createNoopCacheStore(location) {
|
|
|
820
1033
|
};
|
|
821
1034
|
return {
|
|
822
1035
|
beginOwner: () => transaction,
|
|
1036
|
+
flush: async () => {},
|
|
823
1037
|
location,
|
|
824
1038
|
reconcile: async () => {}
|
|
825
1039
|
};
|
|
826
1040
|
}
|
|
827
1041
|
function createReadOnlyCacheStore(location, body, cwd) {
|
|
828
|
-
const transaction = (owner) => ({
|
|
829
|
-
commit: () => {},
|
|
830
|
-
discard: () => {},
|
|
831
|
-
lookup: (slot, fingerprint) => {
|
|
832
|
-
const cached = body.entries[slotKey(owner, slot, cwd)];
|
|
833
|
-
return cached && fingerprintsEqual(cached.fingerprint, fingerprint) ? cached : void 0;
|
|
834
|
-
},
|
|
835
|
-
put: () => {}
|
|
836
|
-
});
|
|
837
1042
|
return {
|
|
838
|
-
beginOwner:
|
|
1043
|
+
beginOwner: (owner) => ({
|
|
1044
|
+
checkpoint: async () => {},
|
|
1045
|
+
commit: () => {},
|
|
1046
|
+
discard: () => {},
|
|
1047
|
+
lookup: (slot, fingerprint) => {
|
|
1048
|
+
const cached = body.entries[slotKey(owner, slot, cwd)];
|
|
1049
|
+
return cached && fingerprintsEqual(cached.fingerprint, fingerprint) ? cached : void 0;
|
|
1050
|
+
},
|
|
1051
|
+
put: () => {}
|
|
1052
|
+
}),
|
|
1053
|
+
flush: async () => {},
|
|
839
1054
|
location,
|
|
840
1055
|
reconcile: async () => {}
|
|
841
1056
|
};
|
|
@@ -849,9 +1064,38 @@ async function defaultFileExists(path) {
|
|
|
849
1064
|
throw error;
|
|
850
1065
|
}
|
|
851
1066
|
}
|
|
1067
|
+
function emptyLoadedLog(alintVersion) {
|
|
1068
|
+
const metadata = {
|
|
1069
|
+
alintVersion,
|
|
1070
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1071
|
+
magic: CACHE_MAGIC,
|
|
1072
|
+
schemaVersion: 2,
|
|
1073
|
+
type: "metadata"
|
|
1074
|
+
};
|
|
1075
|
+
return {
|
|
1076
|
+
body: createEmptyCacheBody(metadata.createdAt),
|
|
1077
|
+
metadata
|
|
1078
|
+
};
|
|
1079
|
+
}
|
|
1080
|
+
async function ensureCompatibleMetadata(location, metadata, write) {
|
|
1081
|
+
try {
|
|
1082
|
+
if (parseMetadataLine(await readMetadataLine(location), metadata.alintVersion)) return;
|
|
1083
|
+
} catch (error) {
|
|
1084
|
+
if (!isMissingFileError(error)) throw error;
|
|
1085
|
+
}
|
|
1086
|
+
await write(location, `${JSON.stringify(metadata)}\n`);
|
|
1087
|
+
}
|
|
852
1088
|
function fingerprintsEqual(left, right) {
|
|
853
1089
|
return left.configHash === right.configHash && left.modelHash === right.modelHash && left.ruleHash === right.ruleHash && left.targetHash === right.targetHash;
|
|
854
1090
|
}
|
|
1091
|
+
function getCacheLockOptions(retries) {
|
|
1092
|
+
return {
|
|
1093
|
+
realpath: false,
|
|
1094
|
+
retries,
|
|
1095
|
+
stale: LOCK_STALE_MS,
|
|
1096
|
+
update: LOCK_UPDATE_MS
|
|
1097
|
+
};
|
|
1098
|
+
}
|
|
855
1099
|
function hasJsonArrayProperties(input, ancestors) {
|
|
856
1100
|
let arrayLength;
|
|
857
1101
|
let indexCount = 0;
|
|
@@ -863,7 +1107,8 @@ function hasJsonArrayProperties(input, ancestors) {
|
|
|
863
1107
|
arrayLength = descriptor.value;
|
|
864
1108
|
continue;
|
|
865
1109
|
}
|
|
866
|
-
|
|
1110
|
+
const index = typeof key === "string" ? Number(key) : NaN;
|
|
1111
|
+
if (typeof key !== "string" || !Number.isInteger(index) || index < 0 || index >= 2 ** 32 - 1 || String(index) !== key || !descriptor.enumerable) return false;
|
|
867
1112
|
if (!isJsonValueAt(descriptor.value, ancestors)) return false;
|
|
868
1113
|
indexCount += 1;
|
|
869
1114
|
}
|
|
@@ -878,10 +1123,6 @@ function hasJsonObjectProperties(input, ancestors) {
|
|
|
878
1123
|
}
|
|
879
1124
|
return true;
|
|
880
1125
|
}
|
|
881
|
-
function isCanonicalArrayIndex(key) {
|
|
882
|
-
const index = Number(key);
|
|
883
|
-
return Number.isInteger(index) && index >= 0 && index < 2 ** 32 - 1 && String(index) === key;
|
|
884
|
-
}
|
|
885
1126
|
function isJsonValue(input) {
|
|
886
1127
|
return isJsonValueAt(input, /* @__PURE__ */ new WeakSet());
|
|
887
1128
|
}
|
|
@@ -907,27 +1148,14 @@ function isJsonValueAt(input, ancestors) {
|
|
|
907
1148
|
function isMissingFileError(error) {
|
|
908
1149
|
return isNodeErrorCode(error, "ENOENT") || isNodeErrorCode(error, "ENOTDIR");
|
|
909
1150
|
}
|
|
910
|
-
function
|
|
911
|
-
return error instanceof Error && "code" in error && error.code === code;
|
|
912
|
-
}
|
|
913
|
-
async function loadCacheBody(location, expectedHeader, readOnly) {
|
|
914
|
-
let handle;
|
|
1151
|
+
async function loadCacheLog(location, alintVersion) {
|
|
915
1152
|
try {
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
await
|
|
919
|
-
handle = void 0;
|
|
920
|
-
if (header !== expectedHeader) {
|
|
921
|
-
if (!readOnly) await rm(location, { force: true });
|
|
922
|
-
return createEmptyCacheBody();
|
|
923
|
-
}
|
|
924
|
-
const text = await readFile(location, "utf8");
|
|
925
|
-
return parseCacheBody(text.slice(text.indexOf("\n") + 1));
|
|
1153
|
+
const metadata = parseMetadataLine(await readMetadataLine(location), alintVersion);
|
|
1154
|
+
if (!metadata) return emptyLoadedLog(alintVersion);
|
|
1155
|
+
return replayLog(await readFile(location, "utf8"), metadata);
|
|
926
1156
|
} catch (error) {
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
if (!readOnly) await rm(location, { force: true }).catch(() => {});
|
|
930
|
-
return createEmptyCacheBody();
|
|
1157
|
+
if (isMissingFileError(error)) return emptyLoadedLog(alintVersion);
|
|
1158
|
+
throw error;
|
|
931
1159
|
}
|
|
932
1160
|
}
|
|
933
1161
|
function ownerEntries(body, owner) {
|
|
@@ -944,27 +1172,72 @@ function ownerKey(owner, cwd) {
|
|
|
944
1172
|
path: normalizeCachePath(cwd, owner.path)
|
|
945
1173
|
});
|
|
946
1174
|
}
|
|
947
|
-
function
|
|
948
|
-
|
|
949
|
-
|
|
1175
|
+
function parseMetadataLine(line, expectedAlintVersion) {
|
|
1176
|
+
if (!line) return void 0;
|
|
1177
|
+
try {
|
|
1178
|
+
const value = JSON.parse(line);
|
|
1179
|
+
const metadata = parse(CacheMetadataSchema, value);
|
|
1180
|
+
if (expectedAlintVersion !== void 0 && metadata.alintVersion !== expectedAlintVersion) return void 0;
|
|
1181
|
+
return metadata;
|
|
1182
|
+
} catch {
|
|
1183
|
+
return;
|
|
1184
|
+
}
|
|
950
1185
|
}
|
|
951
|
-
async function
|
|
952
|
-
const
|
|
953
|
-
|
|
1186
|
+
async function persistCompactedLog(location, loaded, write) {
|
|
1187
|
+
const metadata = parse(CacheMetadataSchema, loaded.metadata);
|
|
1188
|
+
const events = Object.entries(loaded.body.owners).map(([ownerKey, owner]) => ({
|
|
1189
|
+
at: loaded.body.updatedAt,
|
|
1190
|
+
entries: [...ownerEntries(loaded.body, owner)].map(([slotKey, entry]) => ({
|
|
1191
|
+
entry,
|
|
1192
|
+
slotKey
|
|
1193
|
+
})),
|
|
1194
|
+
mode: "replace",
|
|
1195
|
+
owner,
|
|
1196
|
+
ownerKey,
|
|
1197
|
+
type: "replace-owner"
|
|
1198
|
+
})).map((event) => parse(CacheEventSchema, event));
|
|
1199
|
+
const contents = [`${JSON.stringify(metadata)}\n`, ...events.map((event) => `${JSON.stringify(event)}\n`)].join("");
|
|
954
1200
|
const tempPath = join(dirname(location), `.${basename$1(location)}.${process.pid}.${randomUUID()}.tmp`);
|
|
955
1201
|
try {
|
|
956
|
-
await
|
|
1202
|
+
await write(tempPath, contents);
|
|
957
1203
|
await rename(tempPath, location);
|
|
958
1204
|
} catch (error) {
|
|
959
1205
|
await rm(tempPath, { force: true }).catch(() => {});
|
|
960
1206
|
throw error;
|
|
961
1207
|
}
|
|
962
1208
|
}
|
|
963
|
-
async function
|
|
964
|
-
const
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
1209
|
+
async function readMetadataLine(location) {
|
|
1210
|
+
const handle = await open(location, "r");
|
|
1211
|
+
try {
|
|
1212
|
+
const buffer = Buffer.alloc(METADATA_READ_LIMIT);
|
|
1213
|
+
const { bytesRead } = await handle.read(buffer, 0, buffer.length, 0);
|
|
1214
|
+
const newlineIndex = buffer.subarray(0, bytesRead).indexOf(10);
|
|
1215
|
+
if (newlineIndex < 0) return void 0;
|
|
1216
|
+
const lineEnd = newlineIndex > 0 && buffer[newlineIndex - 1] === 13 ? newlineIndex - 1 : newlineIndex;
|
|
1217
|
+
return buffer.toString("utf8", 0, lineEnd);
|
|
1218
|
+
} finally {
|
|
1219
|
+
await handle.close();
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
function removeOwner(body, key) {
|
|
1223
|
+
for (const slot of body.owners[key]?.slots ?? []) delete body.entries[slot];
|
|
1224
|
+
delete body.owners[key];
|
|
1225
|
+
}
|
|
1226
|
+
function replayLog(text, metadata) {
|
|
1227
|
+
const body = createEmptyCacheBody(metadata.createdAt);
|
|
1228
|
+
const lines = text.split(/\r?\n/);
|
|
1229
|
+
for (let index = 1; index < lines.length; index += 1) {
|
|
1230
|
+
const line = lines[index];
|
|
1231
|
+
if (!line) continue;
|
|
1232
|
+
try {
|
|
1233
|
+
const value = JSON.parse(line);
|
|
1234
|
+
applyEvent(body, parse(CacheEventSchema, value));
|
|
1235
|
+
} catch {}
|
|
1236
|
+
}
|
|
1237
|
+
return {
|
|
1238
|
+
body: parse(CacheFileBodySchema, body),
|
|
1239
|
+
metadata
|
|
1240
|
+
};
|
|
968
1241
|
}
|
|
969
1242
|
function slotKey(owner, slot, cwd) {
|
|
970
1243
|
return stableHash({
|
|
@@ -972,6 +1245,43 @@ function slotKey(owner, slot, cwd) {
|
|
|
972
1245
|
...slot
|
|
973
1246
|
});
|
|
974
1247
|
}
|
|
1248
|
+
async function trimOnce(location, alintVersion, fallback, dependencies) {
|
|
1249
|
+
await mkdir(dirname(location), { recursive: true });
|
|
1250
|
+
try {
|
|
1251
|
+
return await withCacheLock(location, dependencies.lock, getCacheLockOptions(0), async () => {
|
|
1252
|
+
const latest = await loadCacheLog(location, alintVersion);
|
|
1253
|
+
await persistCompactedLog(location, latest, dependencies.write);
|
|
1254
|
+
return latest;
|
|
1255
|
+
});
|
|
1256
|
+
} catch (error) {
|
|
1257
|
+
if (isNodeErrorCode(error, "ELOCKED")) return fallback;
|
|
1258
|
+
throw error;
|
|
1259
|
+
}
|
|
1260
|
+
}
|
|
1261
|
+
async function withCacheLock(location, lock, options, operation) {
|
|
1262
|
+
let compromised;
|
|
1263
|
+
const release = await lock.acquire(location, {
|
|
1264
|
+
...options,
|
|
1265
|
+
onCompromised: (error) => {
|
|
1266
|
+
compromised = error;
|
|
1267
|
+
}
|
|
1268
|
+
});
|
|
1269
|
+
let operationError;
|
|
1270
|
+
try {
|
|
1271
|
+
const result = await operation();
|
|
1272
|
+
if (compromised) throw compromised;
|
|
1273
|
+
return result;
|
|
1274
|
+
} catch (error) {
|
|
1275
|
+
operationError = error;
|
|
1276
|
+
throw error;
|
|
1277
|
+
} finally {
|
|
1278
|
+
try {
|
|
1279
|
+
await release();
|
|
1280
|
+
} catch (error) {
|
|
1281
|
+
if (operationError === void 0) throw error;
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
}
|
|
975
1285
|
//#endregion
|
|
976
1286
|
//#region src/core/execution/records.ts
|
|
977
1287
|
function snapshotDiagnostic(diagnostic) {
|
|
@@ -1109,9 +1419,10 @@ async function executeRuleJob(job, options) {
|
|
|
1109
1419
|
failure: failure(handlerCause, job, handlerCause instanceof SourceChangedError ? "source-changed" : "handler"),
|
|
1110
1420
|
state: "failed"
|
|
1111
1421
|
});
|
|
1112
|
-
if (slot && fingerprint)
|
|
1422
|
+
if (slot && fingerprint) {
|
|
1113
1423
|
job.target.cacheOwner?.put(slot, createCacheEntry(job, fingerprint, bucket));
|
|
1114
|
-
|
|
1424
|
+
await job.target.cacheOwner?.checkpoint();
|
|
1425
|
+
}
|
|
1115
1426
|
return finish(job, bucket, {
|
|
1116
1427
|
cache: "miss",
|
|
1117
1428
|
state: "completed"
|
|
@@ -2094,7 +2405,7 @@ async function planSource(input, options) {
|
|
|
2094
2405
|
cacheOwner = options.cacheStore.beginOwner({
|
|
2095
2406
|
kind: "file",
|
|
2096
2407
|
path: file.path
|
|
2097
|
-
});
|
|
2408
|
+
}, { contentHash });
|
|
2098
2409
|
const baseFile = {
|
|
2099
2410
|
contentHash,
|
|
2100
2411
|
language: file.language,
|
|
@@ -2109,10 +2420,7 @@ async function planSource(input, options) {
|
|
|
2109
2420
|
};
|
|
2110
2421
|
}
|
|
2111
2422
|
if (options.signal?.aborted) {
|
|
2112
|
-
cacheOwner.commit({
|
|
2113
|
-
contentHash,
|
|
2114
|
-
mode: "merge"
|
|
2115
|
-
});
|
|
2423
|
+
cacheOwner.commit({ mode: "merge" });
|
|
2116
2424
|
return {
|
|
2117
2425
|
outcomes: Promise.resolve([]),
|
|
2118
2426
|
project
|
|
@@ -2121,11 +2429,9 @@ async function planSource(input, options) {
|
|
|
2121
2429
|
const batch = options.scheduler.schedule(jobs);
|
|
2122
2430
|
reportFilePlanningComplete(input, batch.jobsAdded, options);
|
|
2123
2431
|
return {
|
|
2124
|
-
outcomes: batch.outcomes.then((settled) => {
|
|
2125
|
-
cacheOwner.commit(options.signal?.aborted ? {
|
|
2126
|
-
|
|
2127
|
-
mode: "merge"
|
|
2128
|
-
} : { contentHash });
|
|
2432
|
+
outcomes: batch.outcomes.then(async (settled) => {
|
|
2433
|
+
cacheOwner.commit(options.signal?.aborted ? { mode: "merge" } : void 0);
|
|
2434
|
+
await options.cacheStore.flush();
|
|
2129
2435
|
return settled;
|
|
2130
2436
|
}),
|
|
2131
2437
|
project
|
|
@@ -2402,6 +2708,14 @@ var AlintAbortError = class extends AlintRunCancelledError {
|
|
|
2402
2708
|
this.name = "AlintAbortError";
|
|
2403
2709
|
}
|
|
2404
2710
|
};
|
|
2711
|
+
var AlintCachePersistenceError = class extends Error {
|
|
2712
|
+
result;
|
|
2713
|
+
constructor(result, cause) {
|
|
2714
|
+
super("Failed to persist the alint cache.", { cause });
|
|
2715
|
+
this.name = "AlintCachePersistenceError";
|
|
2716
|
+
this.result = result;
|
|
2717
|
+
}
|
|
2718
|
+
};
|
|
2405
2719
|
var AlintRunError = class extends Error {
|
|
2406
2720
|
failures;
|
|
2407
2721
|
result;
|
|
@@ -2479,6 +2793,7 @@ async function runAlint(options = {}) {
|
|
|
2479
2793
|
const outcomes = [];
|
|
2480
2794
|
const fileFailures = [];
|
|
2481
2795
|
let infrastructureError;
|
|
2796
|
+
let cachePersistenceError;
|
|
2482
2797
|
let infrastructureFailed = false;
|
|
2483
2798
|
let admissionFailed = false;
|
|
2484
2799
|
try {
|
|
@@ -2542,7 +2857,9 @@ async function runAlint(options = {}) {
|
|
|
2542
2857
|
}
|
|
2543
2858
|
if (!admissionFailed && !options.cacheOnly) try {
|
|
2544
2859
|
await cacheStore.reconcile();
|
|
2545
|
-
} catch {
|
|
2860
|
+
} catch (error) {
|
|
2861
|
+
cachePersistenceError = error;
|
|
2862
|
+
}
|
|
2546
2863
|
}
|
|
2547
2864
|
runProgress.finalize();
|
|
2548
2865
|
if (admissionFailed) throw infrastructureError;
|
|
@@ -2571,6 +2888,7 @@ async function runAlint(options = {}) {
|
|
|
2571
2888
|
usage: snapshotRunUsage(result.usage)
|
|
2572
2889
|
});
|
|
2573
2890
|
if (infrastructureFailed) throw infrastructureError;
|
|
2891
|
+
if (cachePersistenceError !== void 0) throw new AlintCachePersistenceError(result, cachePersistenceError);
|
|
2574
2892
|
if (options.signal?.aborted) throw new AlintAbortError(result, { cause: options.signal.reason });
|
|
2575
2893
|
if (failures.length > 0) throw new AlintRunError(fileFailures.length > 0 ? `${failures.length} alint execution${failures.length === 1 ? "" : "s"} failed.` : `${failures.length} rule execution${failures.length === 1 ? "" : "s"} failed.`, result, {
|
|
2576
2894
|
cause: new AggregateError(failures.map((failure) => new Error(failure.message)), "Alint execution failures."),
|
|
@@ -2927,4 +3245,4 @@ function sampleCorpus(seed) {
|
|
|
2927
3245
|
].map((section) => `--- corpus section ${section} ---\n${rotated}`).join("\n\n");
|
|
2928
3246
|
}
|
|
2929
3247
|
//#endregion
|
|
2930
|
-
export { AlintAbortError, AlintRunCancelledError, AlintRunError, benchmarkModels, buildRuleRegistry, createBuiltInLanguageRegistry, createSourceExtractor, createSourceFile, createSourceRuntime, defineConfig, definePlugin, defineRule, hasDiscoveryFilePatterns, matchesDiscoveryFile, normalizeConfig, registerLanguage, resolveConfigForDirectory, resolveConfigForFile, resolveConfigForProject, resolveLanguage, resolveModel, runAlint, sliceLines, sliceRange, targetIdentity, withLanguage, withStableIdentities };
|
|
3248
|
+
export { AlintAbortError, AlintCachePersistenceError, AlintRunCancelledError, AlintRunError, benchmarkModels, buildRuleRegistry, createBuiltInLanguageRegistry, createSourceExtractor, createSourceFile, createSourceRuntime, defaultStopGateConfig, defineConfig, definePlugin, defineRule, hasDiscoveryFilePatterns, matchesDiscoveryFile, maximumStopGateTimeoutMs, normalizeConfig, registerLanguage, resolveConfigForDirectory, resolveConfigForFile, resolveConfigForProject, resolveLanguage, resolveModel, resolveStopGateConfig, runAlint, sliceLines, sliceRange, stableHash, targetIdentity, withLanguage, withStableIdentities };
|
package/dist/languages-js.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as extractJsSourceTargets } from "./extract-
|
|
1
|
+
import { t as extractJsSourceTargets } from "./extract-DhLFgRej.mjs";
|
|
2
2
|
export { extractJsSourceTargets };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { H as ResolvedModel, x as RuleContext } from "./types-Cm5Z7Fll.mjs";
|
|
2
2
|
import { GenericSchema, InferOutput } from "valibot";
|
|
3
3
|
import { JsonSchema } from "@valibot/to-json-schema";
|
|
4
4
|
import { Message } from "@xsai/shared-chat";
|
|
@@ -152,20 +152,32 @@ function parseStructuredResponse(schema, toolName, response) {
|
|
|
152
152
|
retriable: true
|
|
153
153
|
};
|
|
154
154
|
const toolResults = response.toolResults.filter((result) => result.toolName === toolName);
|
|
155
|
-
|
|
155
|
+
const toolCalls = response.toolCalls.filter((call) => call.toolName === toolName);
|
|
156
|
+
const matches = toolResults.length + toolCalls.length;
|
|
157
|
+
if (matches === 0) return {
|
|
156
158
|
error: `Missing ${toolName} tool result; finishReason=${response.finishReason}`,
|
|
157
159
|
ok: false,
|
|
158
160
|
retriable: true
|
|
159
161
|
};
|
|
160
|
-
if (
|
|
161
|
-
error: `Expected one ${toolName} tool result, received ${
|
|
162
|
+
if (matches > 1) return {
|
|
163
|
+
error: `Expected one ${toolName} tool result, received ${matches}`,
|
|
162
164
|
ok: false,
|
|
163
165
|
retriable: true
|
|
164
166
|
};
|
|
167
|
+
let value;
|
|
168
|
+
try {
|
|
169
|
+
value = toolResults[0] !== void 0 ? toolResults[0].result : JSON.parse(toolCalls[0].args);
|
|
170
|
+
} catch (error) {
|
|
171
|
+
return {
|
|
172
|
+
error: `Tool call failed before validation: ${errorMessageFrom(error) ?? String(error)}`,
|
|
173
|
+
ok: false,
|
|
174
|
+
retriable: true
|
|
175
|
+
};
|
|
176
|
+
}
|
|
165
177
|
try {
|
|
166
178
|
return {
|
|
167
179
|
ok: true,
|
|
168
|
-
value: parse(schema,
|
|
180
|
+
value: parse(schema, value)
|
|
169
181
|
};
|
|
170
182
|
} catch (error) {
|
|
171
183
|
return {
|
|
@@ -109,6 +109,7 @@ interface AlintConfigItem {
|
|
|
109
109
|
files?: readonly (readonly string[] | string)[];
|
|
110
110
|
ignore?: IgnoreConfig;
|
|
111
111
|
ignores?: readonly string[];
|
|
112
|
+
integrations?: IntegrationsConfig;
|
|
112
113
|
language?: string;
|
|
113
114
|
languageOptions?: Record<string, unknown>;
|
|
114
115
|
linterOptions?: AlintLinterOptions;
|
|
@@ -160,6 +161,9 @@ interface EnabledRule {
|
|
|
160
161
|
interface IgnoreConfig {
|
|
161
162
|
gitignore?: boolean;
|
|
162
163
|
}
|
|
164
|
+
interface IntegrationsConfig {
|
|
165
|
+
stopGate?: StopGateConfig;
|
|
166
|
+
}
|
|
163
167
|
interface LanguageDefinition {
|
|
164
168
|
extensions?: readonly string[];
|
|
165
169
|
extract: (file: SourceFile, context: LanguageContext) => Awaitable<SourceTarget[]>;
|
|
@@ -263,8 +267,10 @@ interface RuleInferenceUsageRecord {
|
|
|
263
267
|
totalTokens?: number;
|
|
264
268
|
}
|
|
265
269
|
/**
|
|
266
|
-
* - `'any'` — every
|
|
267
|
-
*
|
|
270
|
+
* - `'any'` — every language except `plaintext`, and never a failure. Plain text is what a file
|
|
271
|
+
* falls back to when no language claims it, so a rule asking for any language is asking for a
|
|
272
|
+
* real one. Rules that work from `FunctionInfo` alone want this: install another language pack
|
|
273
|
+
* and they cover it too, unchanged.
|
|
268
274
|
* - A list of language ids — `LanguageDefinition.name` values such as `go` or `typescript`, never
|
|
269
275
|
* file extensions. The rule handles exactly these. Files of other languages are skipped
|
|
270
276
|
* rather than failed, so one plugin can carry rules for several languages behind one `files:`
|
|
@@ -303,6 +309,12 @@ interface RuleWithHandler {
|
|
|
303
309
|
onTargetProject?: never;
|
|
304
310
|
onTargetWith: (target: Target) => Awaitable<void>;
|
|
305
311
|
}
|
|
312
|
+
interface StopGateConfig {
|
|
313
|
+
enabled?: boolean;
|
|
314
|
+
target?: StopGateTarget;
|
|
315
|
+
timeoutMs?: number;
|
|
316
|
+
}
|
|
317
|
+
type StopGateTarget = 'all' | 'dirty-files';
|
|
306
318
|
type Target = DirectoryTarget | PlannedSourceTarget | ProjectTarget;
|
|
307
319
|
//#endregion
|
|
308
|
-
export {
|
|
320
|
+
export { RuleSpecializedHandlers as A, ModelRequirement as B, RuleHandlers as C, RuleOptionsSchema as D, RuleOptionsOutput as E, AgentAdapter as F, ProviderDefinition as G, ResolvedModel as H, AgentRequest as I, RunnerStatsConfig as J, ProviderType as K, AgentResult as L, StopGateConfig as M, StopGateTarget as N, RuleRegistry as O, Target as P, AgentTool as R, RuleDefinition as S, RuleOptionsInput as T, ResolvedProvider as U, ResolveModelOptions as V, ModelSize as W, SetupModelDefinition as X, SetupConfig as Y, ProjectTarget as _, AlintLinterOptions as a, RuleConfigEntry as b, DiagnosticLocation as c, IgnoreConfig as d, IntegrationsConfig as f, ProjectFileEntry as g, ProcessorDefinition as h, AlintConfigItem as i, RuleWithHandler as j, RuleSeverity as k, DirectoryTarget as l, PluginDefinition as m, AlintConfigExtends as n, Awaitable as o, LanguageDefinition as p, RunnerConfig as q, AlintConfigInput as r, DiagnosticDescriptor as s, AlintConfig as t, EnabledRule as u, ProjectTargetEntry as v, RuleInferenceUsageRecord as w, RuleContext as x, RuleCacheConfig as y, AgentUsage as z };
|
package/package.json
CHANGED
|
@@ -1,7 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alint-js/core",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.6.0",
|
|
5
|
+
"description": "Public rule and plugin SDK and run engine for alint",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/moeru-ai/alint.git",
|
|
10
|
+
"directory": "packages/core"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"alint",
|
|
14
|
+
"lint",
|
|
15
|
+
"linter",
|
|
16
|
+
"ai",
|
|
17
|
+
"code-analysis",
|
|
18
|
+
"sdk"
|
|
19
|
+
],
|
|
5
20
|
"exports": {
|
|
6
21
|
".": {
|
|
7
22
|
"types": "./dist/index.d.mts",
|
|
@@ -31,17 +46,20 @@
|
|
|
31
46
|
"dependencies": {
|
|
32
47
|
"@moeru/std": "^0.1.0-beta.20",
|
|
33
48
|
"@valibot/to-json-schema": "^1.7.1",
|
|
34
|
-
"@xsai/generate-text": "^0.5.0-beta.
|
|
35
|
-
"@xsai/shared-chat": "^0.5.0-beta.
|
|
36
|
-
"@xsai/stream-text": "^0.5.0-beta.
|
|
37
|
-
"@xsai/tool": "^0.5.0-beta.
|
|
49
|
+
"@xsai/generate-text": "^0.5.0-beta.8",
|
|
50
|
+
"@xsai/shared-chat": "^0.5.0-beta.8",
|
|
51
|
+
"@xsai/stream-text": "^0.5.0-beta.8",
|
|
52
|
+
"@xsai/tool": "^0.5.0-beta.8",
|
|
38
53
|
"es-toolkit": "^1.50.0",
|
|
39
54
|
"minimatch": "^10.2.6",
|
|
40
55
|
"oxc-parser": "^0.142.0",
|
|
41
56
|
"pathe": "^2.0.3",
|
|
42
|
-
"
|
|
57
|
+
"proper-lockfile": "4.1.2",
|
|
58
|
+
"valibot": "^1.4.2",
|
|
59
|
+
"@alint-js/utils": "0.6.0"
|
|
43
60
|
},
|
|
44
61
|
"devDependencies": {
|
|
62
|
+
"@types/proper-lockfile": "4.1.4",
|
|
45
63
|
"effect": "^3.22.1",
|
|
46
64
|
"sury": "^11.0.0-rc.0"
|
|
47
65
|
},
|