@aurelienbbn/agentlint
Version:
Stateless, deterministic CLI that bridges traditional linters and AI-assisted code review
1 lines • 5.97 kB
Source Map (JSON)
{"version":3,"file":"index.mjs","names":[],"sources":["../src/domain/rule.ts","../src/domain/config.ts"],"sourcesContent":["/**\n * Rule definition types and the `defineRule` helper.\n *\n * A rule is a reusable lint check defined by {@link RuleMeta} (what to check)\n * and a `createOnce` factory (how to check it). The factory returns a\n * {@link Visitors} object whose keys are tree-sitter node types.\n *\n * @module\n * @since 0.1.0\n */\n\nimport { Schema } from \"effect\";\nimport type { AgentReviewNode } from \"./node.js\";\nimport type { TreeSitterNodeType } from \"./node-types.js\";\nimport type { RuleContext } from \"./rule-context.js\";\n\n/**\n * Static metadata for a rule.\n *\n * Defined as a `Schema.Struct` so that rule metadata is validated at\n * runtime when `defineRule` is called — catches typos, missing fields,\n * and wrong types with clear error messages.\n *\n * @since 0.1.0\n * @category models\n */\nexport const RuleMeta = Schema.Struct({\n /** Unique identifier. kebab-case. Used in output and --rule filtering. */\n name: Schema.String,\n /** One-liner explaining what the rule checks. */\n description: Schema.String,\n /** File extensions this rule applies to, without the dot. e.g. `[\"ts\", \"tsx\"]` */\n languages: Schema.Array(Schema.String),\n /**\n * Natural language instruction for the calling AI agent.\n * Defines pass/fail criteria and how to evaluate flagged matches.\n */\n instruction: Schema.String,\n /** If provided, rule only runs on files matching these globs (after global filtering). */\n include: Schema.optional(Schema.Array(Schema.String)),\n /** If provided, files matching these globs are excluded from this rule. */\n ignore: Schema.optional(Schema.Array(Schema.String)),\n});\n\n/** @since 0.1.0 */\nexport type RuleMeta = Schema.Schema.Type<typeof RuleMeta>;\n\n/**\n * Callback invoked when a matching AST node type is visited.\n *\n * @since 0.1.0\n * @category models\n */\nexport type VisitorHandler = (node: AgentReviewNode) => void;\n\n/**\n * Visitor object returned by `createOnce`.\n *\n * Maps tree-sitter node type strings to handler functions.\n * Known node types provide autocomplete; any string is accepted.\n *\n * @since 0.1.0\n * @category models\n */\nexport type Visitors = {\n /**\n * Called once before each file is traversed.\n * Return `false` to skip this file entirely for this rule.\n */\n before?: ((filename: string) => boolean | void) | undefined;\n /**\n * Called once after all files have been visited.\n * Use for aggregate analysis.\n */\n after?: (() => void) | undefined;\n} & { [K in TreeSitterNodeType]?: VisitorHandler } & {\n [nodeType: string]: VisitorHandler | ((filename: string) => boolean | void) | (() => void) | undefined;\n};\n\n/**\n * A complete rule definition.\n *\n * @since 0.1.0\n * @category models\n */\nexport interface AgentReviewRule {\n readonly meta: RuleMeta;\n /**\n * Called once per agentlint run (not per file).\n * The returned visitor object is reused across files.\n * Per-file state must be reset in `before()`.\n */\n readonly createOnce: (context: RuleContext) => Visitors;\n}\n\n/**\n * Identity function that provides type inference and IDE support for rule definitions.\n *\n * @example\n * ```ts\n * import { defineRule } from \"agentlint\"\n *\n * export const myRule = defineRule({\n * meta: {\n * name: \"my-rule\",\n * description: \"Checks for something\",\n * languages: [\"ts\", \"tsx\"],\n * instruction: \"Evaluate whether ...\"\n * },\n * createOnce(context) {\n * return {\n * comment(node) {\n * context.flag({ node, message: \"Found comment\" })\n * }\n * }\n * }\n * })\n * ```\n *\n * @since 0.1.0\n * @category constructors\n */\nexport function defineRule(rule: AgentReviewRule): AgentReviewRule {\n Schema.decodeUnknownSync(RuleMeta)(rule.meta);\n return rule;\n}\n","/**\n * Configuration types and the `defineConfig` helper.\n *\n * A config file (`agentlint.config.ts`) default-exports an {@link AgentReviewConfig}\n * object that maps rule names to rule definitions and optionally scopes which\n * files are scanned.\n *\n * @module\n * @since 0.1.0\n */\n\nimport { Schema } from \"effect\";\nimport type { AgentReviewRule } from \"./rule.js\";\nimport { RuleMeta } from \"./rule.js\";\n\n/**\n * Top-level configuration schema for `agentlint.config.ts`.\n *\n * @since 0.1.0\n * @category models\n */\nexport interface AgentReviewConfig {\n /** Rule registry. Keys are kebab-case names used in output and `--rule` filtering. */\n readonly rules: Record<string, AgentReviewRule>;\n /** If provided, only files matching at least one pattern are scanned. */\n readonly include?: ReadonlyArray<string> | undefined;\n /** Files matching any pattern are excluded (merged with built-in defaults). */\n readonly ignore?: ReadonlyArray<string> | undefined;\n}\n\n/**\n * Identity function that provides type inference and IDE support for config files.\n *\n * @example\n * ```ts\n * import { defineConfig } from \"agentlint\"\n *\n * export default defineConfig({\n * include: [\"src/**\\/*.ts\"],\n * rules: { \"my-rule\": myRule }\n * })\n * ```\n *\n * @since 0.1.0\n * @category constructors\n */\nexport function defineConfig(config: AgentReviewConfig): AgentReviewConfig {\n for (const rule of Object.values(config.rules)) {\n Schema.decodeUnknownSync(RuleMeta)(rule.meta);\n }\n return config;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AA0BA,MAAa,WAAW,OAAO,OAAO;CAEpC,MAAM,OAAO;CAEb,aAAa,OAAO;CAEpB,WAAW,OAAO,MAAM,OAAO,OAAO;CAKtC,aAAa,OAAO;CAEpB,SAAS,OAAO,SAAS,OAAO,MAAM,OAAO,OAAO,CAAC;CAErD,QAAQ,OAAO,SAAS,OAAO,MAAM,OAAO,OAAO,CAAC;CACrD,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgFF,SAAgB,WAAW,MAAwC;AACjE,QAAO,kBAAkB,SAAS,CAAC,KAAK,KAAK;AAC7C,QAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC9ET,SAAgB,aAAa,QAA8C;AACzE,MAAK,MAAM,QAAQ,OAAO,OAAO,OAAO,MAAM,CAC5C,QAAO,kBAAkB,SAAS,CAAC,KAAK,KAAK;AAE/C,QAAO"}