/** * Validate provider docs against ground truth introspected from the real package. * * Companion to scripts/gen_python_truth.py, which writes * data/provider-truth/.json from an installed package. This module * checks docs//*.md against those facts and is run by the test suite, * so a doc claiming a symbol or enum member that does not exist fails the build. * * Three checks, all chosen for precision over coverage: * * 1. Imports - every `from import X` in a doc must resolve to a real * symbol. This is what catches fabricated API surface. * 2. Enum members - every SCREAMING_SNAKE token in a code span must belong to * one of the package's enums, or be explicitly allowlisted below. * 3. Literal arguments - every `param="value"` a doc writes must be a value that * parameter's Literal annotation actually accepts. Checks 1 and 2 * both assume a vocabulary is made of identifiers; fast-forward's * is entirely lowercase strings, so without this its docs would * pass while naming a coordinate system that does not exist. * * Regenerate a truth file after a version bump: * python3 scripts/gen_python_truth.py kloppy --provider kloppy */ export interface PythonPackageTruth { provider: string; kind: string; source: { package: string; version: string; generated_at: string; }; modules: Record; enums: Record; valueLists: Record; /** Parameter name -> every value any function in the package accepts for it. */ literals: Record; /** Qualified function -> its own Literal parameters, which are often narrower. */ literalsByFunction: Record>; classes: string[]; symbols: string[]; signatures: Record; } export interface DocFile { file: string; text: string; } export interface OpenApiTruth { provider: string; kind: string; source: { specs: Array<{ spec: string; title: string; version: string; }>; generated_at: string; }; /** Server base paths (e.g. /soccer/trial/v4), which callable URLs include. */ basePaths?: string[]; /** Endpoint path -> the HTTP methods the spec defines on it. */ paths: Record; parameters: string[]; schemas: string[]; fields: string[]; enums: Record; } /** * The endpoint check needs only a provider name and a path->methods map, so it * works for any truth kind that carries one - an OpenAPI spec, or a vendor guide * the endpoints were derived from. */ export type EndpointTruth = Pick & Partial>; /** * Compare endpoints on shape, not on parameter naming. Docs and specs often use * different placeholder names for the same path segment, and that is a style * difference rather than a documentation error. */ export declare function normalisePath(path: string, basePaths?: string[]): string; /** * Endpoint claims in a doc set, from both notations the corpus uses: inline code * spans (`GET /matches/{wyId}/events`) and HTTP request lines inside fenced * blocks (```http ... GET /api/players HTTP/1.1). */ export declare function extractDocumentedEndpoints(text: string): Array<{ method: string; path: string; }>; /** * How many endpoint claims a doc set actually makes. * * validateOpenApiDocs returns no violations both when every endpoint is correct * and when a doc set cites no endpoints at all. Those are very different states, * and only one of them means anything, so callers can check coverage separately. */ export declare function countDocumentedEndpoints(docs: DocFile[]): number; export declare function loadOpenApiTruth(provider: string): OpenApiTruth; export declare function listOpenApiProviders(): string[]; /** Check that every endpoint a doc set cites exists in the vendor's own spec. */ export declare function validateOpenApiDocs(docs: DocFile[], truth: EndpointTruth): string[]; /** * Some vendors publish their API contract as a Notion page rather than as a * specification. scripts/gen_notion_truth.py derives the same facts the endpoint * check needs - paths, methods, parameter and field names - without mirroring the * page, whose response samples carry the vendor's own match data. */ export interface NotionTruth { provider: string; kind: string; source: { page: string; page_id: string; title: string; generated_at: string; }; basePaths: string[]; paths: Record; parameters: string[]; fields: string[]; operations: Record; } export declare function loadNotionTruth(provider: string): NotionTruth; export declare function listNotionProviders(): string[]; export declare function loadProviderTruth(provider: string): PythonPackageTruth; export declare function listTruthProviders(): string[]; export declare function loadProviderDocs(provider: string): DocFile[]; /** Names imported from the package in `from x import a, b` statements. */ export declare function extractImportedSymbols(text: string, pkg: string): string[]; /** SCREAMING_SNAKE_CASE tokens inside backtick code spans. */ export declare function extractEnumTokens(text: string): string[]; /** * A provider can have both a package truth and a spec truth - SkillCorner ships * a pip client and publishes an OpenAPI document. A doc citing a value the spec * enumerates (`U23`, say) is grounded, even though the pip package never names * it, so the spec's enum members count as known tokens here too. */ export declare function specEnumTokens(provider: string): string[]; export declare function validateProviderDocs(docs: DocFile[], truth: PythonPackageTruth): string[]; /** * `param="value"` pairs a doc writes, for parameters with a Literal annotation. * * Also matches the `to_`-prefixed form: fast-forward's transform() takes * `to_coordinates` and `to_orientation` typed as plain `Optional[str]`, but the * values they accept are the same vocabulary as the `coordinates` and * `orientation` load parameters, and that is where a wrong value would be written. */ export declare function extractLiteralArguments(text: string, params: string[]): Array<{ param: string; value: string; }>; export declare function validateLiteralArguments(docs: DocFile[], truth: PythonPackageTruth): string[]; /** * How many literal arguments a doc set actually cites. * * validateLiteralArguments returns no violations both when every documented value * is real and when the docs cite none at all, so the tests assert this separately * rather than reading an empty violation list as coverage. */ export declare function countDocumentedLiteralArguments(docs: DocFile[], truth: PythonPackageTruth): number; export interface PostmanTruth { provider: string; kind: string; source: { collection: string; name: string; dispatch_param: string | null; generated_at: string; }; baseUrls: string[]; parameters: string[]; operations: Record; } export declare function loadPostmanTruth(provider: string): PostmanTruth; export declare function listPostmanProviders(): string[]; /** Resource selectors a doc set cites, e.g. `req=match_lineups`. */ export declare function extractDispatchValues(text: string, param: string): string[]; /** * Check a single-endpoint API's docs against the published request vocabulary. * * With no paths to get wrong, the failure mode moves to the dispatch parameter: * an invented or misspelled `req` value is not a routing error and will not * necessarily look like one at runtime. */ export declare function validatePostmanDocs(docs: DocFile[], truth: PostmanTruth): string[];