export type RuleOwner = 'analyzer' | 'oxlint' | 'sdk' export type RuleInfo = { slug: string owner: RuleOwner message: string help: string url: string } const ruleDocsUrl = (slug: string) => `https://docs.astrale.ai/linter/rules/${slug}` export const ruleCatalog = { 'thin-schema-composition-root': { slug: 'thin-schema-composition-root', owner: 'analyzer', message: 'The schema composition root defines a schema member inline.', help: 'Move this member definition to its bounded-context module and import it here.', url: ruleDocsUrl('thin-schema-composition-root'), }, 'one-remote-definition-per-file': { slug: 'one-remote-definition-per-file', owner: 'analyzer', message: 'This file defines more than one Astrale remote callable.', help: 'Keep one remoteMethod or defineRemoteFunction definition per implementation file.', url: ruleDocsUrl('one-remote-definition-per-file'), }, 'core-is-pure': { slug: 'core-is-pure', owner: 'analyzer', message: 'Pure core code depends on an effectful or runtime-only module.', help: 'Move I/O orchestration to runtime or integrations and pass pure data into core.', url: ruleDocsUrl('core-is-pure'), }, 'core-has-no-async': { slug: 'core-has-no-async', owner: 'oxlint', message: 'Production core code contains asynchronous syntax.', help: 'Keep core deterministic and synchronous; perform asynchronous work in runtime or integrations.', url: ruleDocsUrl('core-has-no-async'), }, 'no-nested-steps': { slug: 'no-nested-steps', owner: 'oxlint', message: 'A durable step directly contains another durable step.', help: 'Give each stage one step boundary and call helper-owned steps outside another step callback.', url: ruleDocsUrl('no-nested-steps'), }, 'no-read-inside-mutate': { slug: 'no-read-inside-mutate', owner: 'oxlint', message: 'A graph mutation builder performs a read or is asynchronous.', help: 'Read before mutate, then keep the mutation callback synchronous and limited to patch construction.', url: ruleDocsUrl('no-read-inside-mutate'), }, } as const satisfies Record export type ImplementedRuleSlug = keyof typeof ruleCatalog export function ruleId(slug: ImplementedRuleSlug): `astrale/${ImplementedRuleSlug}` { return `astrale/${slug}` } export function ruleInfo(id: string): RuleInfo | undefined { const slug = id.startsWith('astrale/') ? id.slice('astrale/'.length) : id return ruleCatalog[slug as ImplementedRuleSlug] }