Gå til innholdet

Rule API

Archgate-regler er TypeScript-filer som eksporterer et vanlig objekt typet med satisfies RuleSet. Hver regel mottar en RuleContext med verktøy for å søke i filer, lese innhold og rapportere brudd.

/// <reference path="../rules.d.ts" />
export default {
rules: {
"my-rule-id": {
description: "Human-readable description of what this rule checks",
async check(ctx) {
// Rule logic here -- the report method decides the severity
ctx.report.violation({ message: "..." });
},
},
},
} satisfies RuleSet;

En regelfil eksporterer som standard et vanlig objekt med en rules-post indeksert etter regel-ID. Nøklene blir regel-ID-ene som vises i sjekkutdata og bruddrapporter. Annotasjonen satisfies RuleSet gir typekontroll uten å pakke inn i et funksjonskall.

type RuleSet = { rules: Record<string, RuleConfig> };

Hver regel i posten må samsvare med RuleConfig-grensesnittet.

interface RuleConfig {
description: string;
severity?: Severity;
check: (ctx: RuleContext) => Promise<void>;
}
FeltTypePåkrevdBeskrivelse
descriptionstringJaLesbar beskrivelse som vises i sjekkutdata
severitySeverityNeiGodtas og valideres, men uten effekt — se under
check(ctx: RuleContext) => Promise<void>JaAsynkron funksjon som inneholder regellogikken

check-funksjonen mottar et RuleContext-objekt med prosjekttilstand og hjelpemetoder.

interface RuleContext {
projectRoot: string;
scopedFiles: string[];
changedFiles: string[];
glob(pattern: string): Promise<string[]>;
grep(file: string, pattern: RegExp): Promise<GrepMatch[]>;
grepFiles(pattern: RegExp, fileGlob: string): Promise<GrepMatch[]>;
readFile(path: string): Promise<string>;
fileAtBase(path: string): Promise<string | null>;
readJSON(path: "package.json"): Promise<PackageJson>;
readJSON(path: string): Promise<unknown>;
readTOML(path: string): Promise<unknown>;
readYAML(path: string): Promise<ReadYamlResult>;
ast(
path: string,
language: "typescript" | "javascript",
opts?: AstOptions
): Promise<EsTreeProgram>;
ast(
path: string,
language: "python",
opts?: AstOptions
): Promise<PythonAstModule>;
ast(
path: string,
language: "ruby",
opts?: AstOptions
): Promise<RubyAstProgram>;
ast(path: string, language: AstLanguage, opts?: AstOptions): Promise<AstNode>;
findAstNodes(tree: EsTreeNode, ...types: string[]): EsTreeNode[];
findAstNodes(tree: PythonAstNode, ...types: string[]): PythonAstNode[];
findAstNodes(
tree: unknown,
...types: string[]
): (EsTreeNode | PythonAstNode)[];
checkCase(value: string, scheme: CaseScheme): boolean;
report: RuleReport;
}
projectRoot: string;

Absolutt sti til prosjektets rotkatalog (der .archgate/ ligger).

scopedFiles: string[];

Filer som matcher ADR-ens files-globmønstre fra frontmatter. Hvis ADR-en ikke har et files-felt, inneholder denne alle prosjektfiler. Bruk denne som den primære fillisten for regelkontrollene dine.

changedFiles: string[];

Filer som har blitt endret ifølge git. Som standard fylles denne automatisk med branch-diffen mot den detekterte basisgrenen (f.eks. origin/main) pluss eventuelle ikke-committede endringer i arbeidstreet (stagede, ustagede og usporede ikke-ignorerte filer). Når --staged brukes, inneholder den kun stagede filer. Når --base <ref> brukes, inneholder den alle filer som er endret siden den referansen pluss ikke-committede endringer i arbeidstreet. Tom når basisdeteksjon feiler eller ingen endringer finnes. Bruk denne til å bygge regler for avhengigheter mellom filer (f.eks. “hvis fil A endret seg, må fil B også endres”).

report: RuleReport;

Rapporteringsgrensesnittet for å registrere brudd, advarsler og informasjonsmeldinger. Se RuleReport nedenfor.

glob(pattern: string): Promise<string[]>;

Finn filer som matcher et globmønster relativt til prosjektroten. Returnerer en matrise med filstier. Filer som ignoreres av .gitignore er ekskludert som standard. Sett respectGitignore: false i ADR-ens frontmatter for å inkludere dem.

const testFiles = await ctx.glob("tests/**/*.test.ts");
grep(file: string, pattern: RegExp): Promise<GrepMatch[]>;

Søk i en enkelt fil etter linjer som matcher et regulært uttrykk. Returnerer en matrise med GrepMatch-objekter med filsti, linjenummer, kolonne og matchet innhold.

const matches = await ctx.grep(file, /console\.error\(/);
grepFiles(pattern: RegExp, fileGlob: string): Promise<GrepMatch[]>;

Søk i flere filer som matcher et globmønster etter linjer som matcher et regulært uttrykk. Kombinerer glob og grep i ett enkelt kall. Filer som ignoreres av .gitignore er ekskludert som standard. Sett respectGitignore: false i ADR-ens frontmatter for å inkludere dem.

const matches = await ctx.grepFiles(/TODO:/i, "src/**/*.ts");
readFile(path: string): Promise<string>;

Les innholdet i en fil som en streng. Stien er relativ til prosjektroten.

const content = await ctx.readFile("src/config.ts");
fileAtBase(path: string): Promise<string | null>;

Les en fils kildekode ved den sammenligningsgrunnlagsrevisjonen — fellespunktet (merge base) mellom grunnreferansen og HEAD, den samme commiten changedFiles beregnes mot. Bruk den til å sammenligne arbeidstreet mot punktet der endringssettet delte seg fra basisen.

archgate check løser selv grunnreferansen, i denne rekkefølgen: --base <ref>, deretter grunngrenen lagret i .archgate/config.json, deretter automatisk deteksjon (origin/HEAD, origin/main/origin/master, deretter lokal main/master). En basis er derfor normalt tilgjengelig uten å sende noe flagg.

Returnerer null i de to “ingenting å sammenligne mot”-tilfellene, slik at en enkelt null-sjekk dekker begge:

  • Ingen basis er løst — en --staged-kjøring, et prosjekt som ikke er et git-repository, ingen grunngren kunne oppdages, eller historikkene er urelaterte.
  • Filen fantes ikke ved basisen — en lagt-til fil.
const before = await ctx.fileAtBase("data/schema.py");
if (before === null) {
// Ingen basisversjon å sammenligne mot -- hopp over.
return;
}
const after = await ctx.readFile("data/schema.py");

For en strukturell sammenligning (som ignorerer kommentarer og formatering), foretrekk ast(path, language, { rev: "base" }) nedenfor.

readJSON(path: "package.json"): Promise<PackageJson>;
readJSON(path: string): Promise<unknown>;

Les og parse en JSON-fil. Stien er relativ til prosjektroten. Returnerer den parsede verdien som unknown — cast til forventet type i regelen din. Den bokstavelige stien "package.json" matcher en dedikert overload som returnerer det ambiente PackageJson-grensesnittet (name, version, scripts, dependencies, devDependencies, peerDependencies, optionalDependencies, workspaces, engines, … pluss en indekssignatur), så det vanlige tilfellet trenger ingen cast.

I motsetning til glob, readFile og ast caches ikke den parsede verdien på tvers av regler: hvert kall returnerer et ferskt objekt, så en mutasjon kan ikke lekke inn i en annen regel.

const pkg = await ctx.readJSON("package.json");
const deps = pkg.dependencies ?? {};
const tsconfig = (await ctx.readJSON("tsconfig.json")) as {
compilerOptions?: Record<string, unknown>;
};
readTOML(path: string): Promise<unknown>;

Les og parse en TOML-fil med Buns innebygde parser. Stien er relativ til prosjektroten og bruker samme sandkasse som readFile. Alle filnavn godtas, inkludert .prototools. Returverdien er unknown; snevre inn eller konverter typen til strukturen regelen forventer.

Hvert kall returnerer et nytt objekt, slik at mutasjoner ikke påvirker andre kall eller regler. Ugyldig TOML og filer som ikke kan leses, kaster en feil som gir en regelkjøringsfeil med avslutningskode 2.

const doc = (await ctx.readTOML("pyproject.toml")) as {
project?: { dependencies?: string[] };
"dependency-groups"?: Record<string, string[]>;
};
const dependencies = doc.project?.dependencies ?? [];
const workerDependencies = doc["dependency-groups"]?.worker ?? [];

De parsede verdiene inkluderer ikke posisjoner i kildefilen. Bruk ctx.grep() når et regelbrudd trenger et linjenummer; treffene inkluderer linje og kolonne. Et regex-søk finner tekstforekomster, så begrens søket til den relevante tabellen når nøkler gjentas.

readYAML(path: string): Promise<ReadYamlResult>;
interface ReadYamlResult {
frontmatter: Record<string, YamlValue> | null;
content: YamlValue;
}
type YamlValue =
| string
| number
| boolean
| null
| YamlValue[]
| { [key: string]: YamlValue };

Les en YAML-fil eller en Markdown-fil med YAML-frontmatter. Stien er relativ til prosjektroten og går gjennom samme sandkasse som readFile. Ett resultatobjekt dekker begge formene — en nullbar frontmatter-mapping og en content av typen YamlValue, de JSON-lignende dataene YAMLs kjerneskjema produserer (etter en typeof-sjekk kan du indeksere i mappinger og sekvenser uten cast) — og valget er basert på filendelsen:

  • .yml-/.yaml-filer: hele dokumentet parses som YAML. frontmatter er alltid null; content er den parsede verdien, innsnevret med en typeof-sjekk i stedet for en cast — i motsetning til readJSON, som returnerer unknown. Fordi valget skjer per filendelse, blir ----skilletegnene i en flerdokumentstrøm (Kubernetes-manifester, CI-konfigurasjoner) aldri feiltolket som frontmatter.
  • Alle andre filer (typisk Markdown): den innledende ----avgrensede blokken parses som frontmatter — null når den mangler (“har denne filen frontmatter?” er én enkelt null-test, som speiler fileAtBase), {} når den finnes, men er tom. content er resten av brødteksten, trimmet — den parses ikke som YAML.

readYAML() kaster (fail-closed, som ast()) når en .yml-/.yaml-fil er ugyldig YAML, eller når en frontmatter-blokk er ugyldig YAML eller parses til noe annet enn en mapping (en skalar eller en sekvens) — og vises som en regelkjøringsfeil med exit-kode 2 i stedet for en falsk bestått sjekk.

const { content } = await ctx.readYAML(".github/workflows/ci.yml");
if (
typeof content === "object" &&
content !== null &&
!Array.isArray(content)
) {
const jobs = content.jobs; // YamlValue -- no cast needed
}
for (const file of await ctx.glob("docs/**/*.md")) {
const { frontmatter } = await ctx.readYAML(file);
if (frontmatter === null) {
ctx.report.violation({ message: `${file} is missing frontmatter`, file });
continue;
}
if (typeof frontmatter.title !== "string") {
ctx.report.violation({
message: `${file} frontmatter must declare a title`,
file,
});
}
}
ast(
path: string,
language: "typescript" | "javascript",
opts?: AstOptions
): Promise<EsTreeProgram>;
ast(
path: string,
language: "python",
opts?: AstOptions
): Promise<PythonAstModule>;
ast(
path: string,
language: "ruby",
opts?: AstOptions
): Promise<RubyAstProgram>;
ast(path: string, language: AstLanguage, opts?: AstOptions): Promise<AstNode>;
interface AstOptions {
rev?: "base";
comments?: boolean;
}

Parse en kildefil til dens språknative AST. Stien er relativ til prosjektroten og går gjennom samme sandkasse som readFile. Å sende språket som et bokstavelig strengliteral velger en per-språk-overload, så returtypen er allerede innsnevret — program.body er typet uten cast, og det er bare en ikke-literal AstLanguage som faller tilbake til AstNode-unionen. TypeScript og JavaScript parses i prosessen; Python og Ruby parses ved å starte systemtolkens egen AST-fasilitet fra standardbiblioteket som en underprosess. Formen på det returnerte treet varierer per språk — se AstNode.

Parseresultater caches gjennom én enkelt archgate check-kjøring, med nøkkel (path, language, rev, comments): gjentatte identiske kall — på tvers av regler, eller samtidige innenfor én regel — koster én parse (én tolkoppstart for Python/Ruby), og en mislykket parse kaster den samme feilen på nytt til alle kallere. Behandle det returnerte treet som skrivebeskyttet — det kan være delt med andre regler.

const program = await ctx.ast("src/cli.ts", "typescript");
for (const node of program.body) {
console.log(node.type);
}
Parsing av grunnrevisjonen ({ rev: "base" })
Section titled “Parsing av grunnrevisjonen ({ rev: "base" })”

Med { rev: "base" } parser ast() filen ved den sammenligningsgrunnlagsrevisjonen i stedet for arbeidstreet — alt annet (returform, kastekontrakt) er identisk. Parse begge revisjonene for å spørre “endret den kjørbare strukturen seg?” Kommentarer er fraværende fra ESTree- og Python-ast-formene, men det er ikke nodeposisjonene: loc- / lineno-feltene forskyves når en kommentar eller tom linje flytter linjene under seg. Sammenlign en posisjonsfri projeksjon — fjern loc / range (ESTree) og lineno / col_offset (Python) før sammenligning — slik at en ren kommentarendring leses som uendret. (Python-dokstrenger er strengnoder i treet, så en endret dokstreng er en reell endring; fjern dem også hvis dokumentasjonsendringer skal være nøytrale.)

// Merk en endring bare når den kjørbare strukturen faktisk endret seg.
// `structurallyEqual` sammenligner trærne med posisjonsmetadata (loc/range,
// lineno/col_offset) fjernet -- se writing-rules-guiden for en konkret
// implementasjon.
for (const file of ctx.changedFiles.filter((f) => f.endsWith(".py"))) {
// Hopp over filer uten basismotpart -- ast({ rev: "base" }) ville kastet.
if ((await ctx.fileAtBase(file)) === null) continue;
const before = await ctx.ast(file, "python", { rev: "base" });
const after = await ctx.ast(file, "python");
if (!structurallyEqual(before, after)) {
ctx.report.violation({ message: `${file} changed behavior`, file });
}
}

Bruk fileAtBase() først når du trenger å oppdage tilfellene uten basis eller med lagt-til fil som ordinær kontrollflyt — ast({ rev: "base" }) kaster for disse (se nedenfor).

Samle inn kommentarer ({ comments: true })
Section titled “Samle inn kommentarer ({ comments: true })”

Med { comments: true } bærer det returnerte treet en comments-matrise — strukturert kommentardata for kommentarstyringsregler, i stedet for linje-for-linje regulære uttrykk. Støttet for alle fire språk. For ruby er det returnerte treet en matrise (Ripper.sexp-utdata), så comments-matrisen ligger på den som en ikke-indeksert egenskap.

interface CommentToken {
type: "line" | "block";
value: string; // skilletegn (`//`, `/* */`, `#`) fjernet
loc: {
start: { line: number; column: number };
end: { line: number; column: number };
};
}
const tree = await ctx.ast("src/api.ts", "typescript", { comments: true });
for (const comment of tree.comments ?? []) {
const lines = comment.value.split("\n").length;
if (lines > 10) {
ctx.report.warning({
message: "Comment block is too long -- link to an ADR instead",
file: "src/api.ts",
line: comment.loc.start.line,
});
}
}

Kommentarposisjoner er nøyaktige mot originalkilden, selv for TypeScript. Dette er en bevisst fordel fremfor treets egen loc, som er transpilert-relativ for TypeScript (se AstNode): kommentarer skannes fra kildekoden før transpilering, så deres loc driver aldri. Python-kommentarer er alltid type: "line" (#) — Python har ingen blokkommentarer, og """-dokstrenger er strengeuttrykk i treet, ikke kommentarer. Ruby #-kommentarer er type: "line"; hver =begin/=end-dokumentasjonsblokk er ett enkelt type: "block"-token der value er det indre innholdet (markørlinjene =begin/=end er fjernet, tilsvarende fjerningen av /* */-skilletegn) og der loc spenner fra =begin-linjen til og med =end-linjen. Kolonnene i loc for Ruby-kommentarer er tegnposisjoner, i samsvar med de andre språkene (Rippers egne sexp-nodeposisjoner er byteposisjoner), og linjeskift i value for blokker normaliseres til LF uavhengig av kildefilens linjeskift. For Python og Ruby er kommentaruthentingen et eget pass over samme kilde (tokenize / Ripper.lex); en tokeniseringsfeil på ellers parsbar kode degraderer til en tom kommentarliste i stedet for å feile hele parsingen. TypeScript/JavaScript-skanneren er streng- og malstreng-bevisst, men sporer ikke regulært-uttrykk-literaler, så et kommentarskilletegn inne i en regex-literal er et kjent blindpunkt.

ast() kaster ved feil — den returnerer aldri null:

  • Parsefeil: filen kan ikke parses som det forespurte språket. Feilmeldingen inkluderer parserens diagnostikk.
  • Manglende tolk (kun python/ruby): ingen egnet tolk ble funnet på PATH.
  • Usannsynlig input: filens navn samsvarer ikke med det forespurte språket (f.eks. kaster ctx.ast("config.json", "python") før noen tolk startes). Godtatte navn er .ts/.tsx/.mts/.cts for typescript, .js/.jsx/.mjs/.cjs for javascript, .py/.pyi for python, og .rb/.rake/.gemspec pluss de bare grunnfilnavnene Rakefile og Gemfile for ruby.
  • Ingen grunnrevisjon (kun { rev: "base" }): ingen grunnreferanse ble løst for denne kjøringen (se fileAtBase), så det finnes ingen basis å parse. Bruk fileAtBase() for å oppdage dette som null i stedet.
  • Fil ikke til stede ved basisen (kun { rev: "base" }): stien ble lagt til etter basisen og fantes ikke der.

En kastet feil er isolert til regelen som feiler: andre regler og ADR-er i samme sjekk-kjøring fortsetter som normalt, og feilen vises som en regelkjøringsfeil med avslutningskode 2 (til forskjell fra avslutningskode 1 for brudd). Kastetilfellene kan skilles fra hverandre på meldingsteksten, slik at sjekkutdataene skiller “dette miljøet kan ikke kjøre denne regelen” fra “denne filen har en syntaksfeil” eller “det finnes ingen grunnrevisjon”.

findAstNodes(tree: EsTreeNode, ...types: string[]): EsTreeNode[];
findAstNodes(tree: PythonAstNode, ...types: string[]): PythonAstNode[];
findAstNodes(tree: unknown, ...types: string[]): (EsTreeNode | PythonAstNode)[];

Samler rekursivt inn hver node i en parset AST der typediskriminantfeltet matcher en av types, i preorder (tom når ingenting matcher). Dette er den innebygde erstatningen for den rekursive vandreren AST-regler tidligere måtte håndrulle: ctx.ast() returnerer bevisst språknative former, men å finne noder etter typenavn avhenger bare av diskriminantfeltet, så én hjelpemetode dekker alle språk. Synkron — ingen await nødvendig.

  • Språkagnostisk: hver objektnode sjekkes mot det diskriminantfeltet den faktisk bærer — _type (Python) eller type (ESTree TypeScript/JavaScript).
  • Full traversering: egne enumererbare objektverdier og arrayer traverseres rekursivt, og selve tree-argumentet er en matchkandidat.
  • Matching av flere typer: send inn flere navn når én konstruksjon spenner over flere nodetyper — det vanlige tilfellet ("FunctionDef"/"AsyncFunctionDef", synkrone/asynkrone varianter).
  • Ruby: Ripper.sexp-noder er rene arrayer uten objektdiskriminantfelt, så et Ruby-tre traverseres, men de array-formede nodene matcher aldri — gå gjennom Ripper-utdata mot dens egen grammatikk i stedet.

Før — innsamleren hver regelfil måtte gjenta (regelfiler kan ikke importere delte hjelpemoduler):

function collectFunctionDefs(
node: unknown,
out: PythonAstNode[] = []
): PythonAstNode[] {
if (Array.isArray(node)) {
for (const item of node) collectFunctionDefs(item, out);
return out;
}
if (!node || typeof node !== "object") return out;
const n = node as PythonAstNode;
if (n._type === "FunctionDef" || n._type === "AsyncFunctionDef") out.push(n);
for (const value of Object.values(n)) {
if (value && typeof value === "object") collectFunctionDefs(value, out);
}
return out;
}
const tree = await ctx.ast("app/models.py", "python");
const funcDefs = collectFunctionDefs(tree);

Etter:

const tree = await ctx.ast("app/models.py", "python");
const funcDefs = ctx.findAstNodes(tree, "FunctionDef", "AsyncFunctionDef");
checkCase(value: string, scheme: CaseScheme): boolean;
type CaseScheme =
| "kebab-case"
| "camelCase"
| "PascalCase"
| "snake_case"
| "SCREAMING_SNAKE_CASE";

Sjekk om en streng følger et casing-skjema — den innebygde erstatningen for regexene per skjema som navngivningsregler tidligere måtte håndrulle. Synkron og ren — ingen await nødvendig. Matchingen er alt-eller-ingenting (hele strengen må samsvare; den tomme strengen matcher ingen skjemaer), og vokabularet er kun ASCII-bokstaver og sifre.

SkjemaMatcherAvviser
kebab-casewriting-rules, 2fa-setupWriting-Rules, writing_rules, writing--rules
camelCasecheckCase, parseURLCheckCase, check_case, 2fast
PascalCaseCheckCase, HTTPServercheckCase, Check_Case, 1Value
snake_casecheck_case, 2fa_setupCheck_Case, check-case, check__case
SCREAMING_SNAKE_CASECHECK_CASE, V2check_case, CHECK-CASE, CHECK__CASE

camelCase og PascalCase følger økosystemkonvensjonen (typescript-eslints naming-convention): en innledende liten/stor bokstav etterfulgt av vilkårlige ASCII-alfanumeriske tegn, så akronymsekvenser (parseURL, HTTPServer) matcher. Degenererte verdier kan tilfredsstille flere skjemaer samtidig (value er gyldig kebab-case, snake_case og camelCase). Å sende inn et ukjent skjemanavn kaster i stedet for å stille returnere false, slik at en skrivefeil vises som en regelfeil i stedet for et falskt resultat.

for (const file of await ctx.glob("docs/**/*.md")) {
const stem = file.split("/").pop()?.replace(/\.md$/, "") ?? "";
if (!ctx.checkCase(stem, "kebab-case")) {
ctx.report.violation({
message: `${file} must have a kebab-case filename`,
file,
});
}
}

Rapporteringsgrensesnittet for å registrere sjekkresultater. Hver metode aksepterer et detalobjekt som beskriver problemet.

interface RuleReport {
violation(detail: ReportDetail): void;
warning(detail: ReportDetail): void;
info(detail: ReportDetail): void;
}
report.violation(detail: ReportDetail): void;

Rapporter et regelbrudd. Brudd får sjekken til å feile med avslutningskode 1. Bruk for harde begrensninger som ikke skal merges.

report.warning(detail: ReportDetail): void;

Rapporter en advarsel. Advarsler vises i sjekkutdata, men får ikke sjekken til å feile — med mindre archgate check --strict brukes, som gjør enhver advarsel til en feil (exit-kode 1). Bruk for ikke-blokkerende veiledning.

report.info(detail: ReportDetail): void;

Rapporter en informasjonsmelding. Påvirker ikke avslutningskoden for sjekken. Bruk for forslag eller notater.

Detalobjektet som sendes til violation, warning og info.

interface ReportDetail {
message: string;
file?: string;
line?: number;
endLine?: number;
endColumn?: number;
fix?: string;
}
FeltTypePåkrevdBeskrivelse
messagestringJaLesbar beskrivelse av problemet
filestringNeiFilsti der problemet ble funnet
linenumberNeiStartlinjenummer (1-basert)
endLinenumberNeiSluttlinjenummer (1-basert)
endColumnnumberNeiSluttkolonnenummer (0-basert)
fixstringNeiForeslått rettelse eller utbedringstiltak

Hvilken rapportør som viser hvilket felt:

  • Konsollet skriver ut message og file:line. Den skriver ut fix bare under --verbose, og aldri kolonner.
  • --output json inneholder alle feltene over, slik at agenter og redigeringsintegrasjoner kan utheve det nøyaktige området i stedet for hele linjen.
  • --output sarif inneholder message, file, line og endLine (som en SARIF-region). Kolonner og fix utelates — Archgates report-detalj bærer en endColumn men ingen startColumn å forankre den til, så serialisereren sender bare linjefeltene.
  • --output github sender ut file/line-annotasjoner med kun message.

Legg alt en gjennomgåer må lese i message; behandle fix som en berikelse for lokal og agent-rettet utdata.


Returnert av ctx.grep() og ctx.grepFiles().

interface GrepMatch {
file: string;
line: number;
column: number;
content: string;
}
FeltTypeBeskrivelse
filestringProsjektrelativ sti til den matchede filen
linenumberLinjenummer for treffet (1-basert)
columnnumberKolonnenummer for treffet (1-basert)
contentstringFullt innhold av den matchede linjen

Returnert av ctx.ast(). Formen er språknativ og bevisst ikke enhetlig på tvers av språk — hvert språk returnerer sitt eget standard AST-vokabular, så en regel som inspiserer Python-kode jobber mot en annen grammatikk enn en som inspiserer TypeScript.

type AstLanguage = "typescript" | "javascript" | "python" | "ruby";
/** Bare feltene alle noder deler er typet; gå gjennom resten via indekssignaturen. */
interface EsTreeNode {
type: string;
loc?: {
start: { line: number; column: number };
end: { line: number; column: number };
} | null;
range?: [number, number];
[key: string]: unknown;
}
interface EsTreeProgram extends EsTreeNode {
type: "Program";
sourceType: "module" | "script";
body: EsTreeNode[];
comments?: CommentToken[];
}
interface PythonAstNode {
_type: string;
lineno?: number;
col_offset?: number;
end_lineno?: number;
end_col_offset?: number;
[key: string]: unknown;
}
interface PythonAstModule extends PythonAstNode {
_type: "Module";
body: PythonAstNode[];
comments?: CommentToken[];
}
type RubyAstNode = unknown[];
interface RubyAstProgram extends Array<unknown> {
comments?: CommentToken[];
}
/** Bare returtypen til overloaden for ikke-literal språk. */
type AstNode = EsTreeProgram | PythonAstModule | RubyAstProgram;

Alle disse navnene er ambiente i .rules.ts-filer via rules.d.ts-referansen — ingen import er nødvendig for å annotere en vandrer med EsTreeNode eller PythonAstNode.

Når parset med { comments: true }, bærer rotnoden også en comments: CommentToken[]-matrise (alle fire språk; for ruby er den en ikke-indeksert egenskap på rot-sexp-matrisen). Den er fraværende ellers.

SpråkUnderliggende parserReturnert form
typescriptmeriyah, i prosessen, etter at TypeScript er transpilert bort med Bun.TranspilerESTree Program med loc-posisjonsinfo. Typenivå-syntaks (interface, typealiaser, export type { ... } from) fjernes før parsing — en fil som bare inneholder setninger på typenivå parses til en tom Program-body. loc-posisjoner refererer til det transpilerte resultatet, ikke den opprinnelige .ts-filen — fjernede typenivå-setninger, kommentarer og tomme linjer gjør at linjenumrene forskyves, så finn konstruksjonen på nytt i den opprinnelige kildekoden (f.eks. ctx.readFile() pluss indexOf) før du rapporterer en line, eller utelat line helt; loc er nøyaktig mot kildekoden bare for javascript
javascriptmeriyah, i prosessenESTree Program med loc-posisjonsinfo
pythonPythons ast-modul fra standardbiblioteket, via systemtolkenJSON-serialiserte ast-noder: { "_type": "Module", "body": [...] } — hver node har _type, nodens egne felt og posisjonene lineno / col_offset
rubyRubys Ripper fra standardbiblioteket, via systemtolkenNestede Ripper.sexp-matriser: ["program", [["command", ...]]] med [line, column]-posisjonspar innebygd i token-oppføringene

Se Strukturelle sjekker med ctx.ast() for et komplett eksempel på en regel per språk.


type Severity = "error" | "warning" | "info";
VerdiRapportert avPåvirkning på avslutningskodeBeskrivelse
"error"ctx.report.violation()Forårsaker avslutningskode 1Hard begrensning, blokkerer sammenslåinger
"warning"ctx.report.warning()Ingen, men avslutningskode 1 under --strictIkke-blokkerende veiledning
"info"ctx.report.info()IngenInformasjon, kun forslag

En regel som kaster en feil (eller overskrider tidsgrensen på 30 sekunder for regler) er en regelkjøringsfeil, som avsluttes med kode 2 i stedet for 1.


Den interne representasjonen av et rapportert problem, brukt i sjekkutdata og JSON-resultater.

interface ViolationDetail {
ruleId: string;
adrId: string;
message: string;
file?: string;
line?: number;
endLine?: number;
endColumn?: number;
fix?: string;
severity: Severity;
}
FeltTypeBeskrivelse
ruleIdstringRegel-ID fra rules-objektnøkkelen
adrIdstringADR-ID fra frontmatter
messagestringLesbar beskrivelse
filestring?Filsti der problemet ble funnet
linenumber?Startlinjenummer (1-basert)
endLinenumber?Sluttlinje (1-basert) — for presis uthevning i editoren
endColumnnumber?Sluttkolonne (0-basert) — for presis uthevning i editoren
fixstring?Foreslått rettelse
severitySeverityEffektiv alvorlighetsgrad for dette bruddet

Brudd kan undertrykkes i kildekoden ved hjelp av archgate-ignore-kommentarer. Motoren håndterer dette automatisk. Regler trenger ingen spesiell logikk.

// archgate-ignore ARCH-006/no-unapproved-deps legacy-avhengighet, migrering planlagt
import chalk from "chalk";

En begrunnelse er påkrevd. Filnivå-undertrykkelse bruker archgate-ignore-file. Stable flere kommentarer for å undertrykke mer enn én regel på samme linje. Se Opt-out-direktiver for fullstendige detaljer og egendefinerte direktivmønstre.