import type { CallExpression, SourceFile } from "ts-morph"; import type { EnvSchemaPattern, ExposesApiPattern, ExtendsRegistrarPattern, UsesApiPattern, } from "../patterns"; import { sourceLocationFromNode } from "../source-location"; import { type ExtractOutput, fail, ok, readNameLiteral, readNameLiteralRef } from "./shared"; export function extractEnvSchema( call: CallExpression, sourceFile: SourceFile, ): ExtractOutput { const arg = call.getArguments()[0]; if (!arg) { return fail( "envSchema", sourceLocationFromNode(call, sourceFile), "expected a single Zod-object schema argument (e.g. z.object({...}))", ); } return ok({ kind: "envSchema", source: sourceLocationFromNode(call, sourceFile), schemaBody: sourceLocationFromNode(arg, sourceFile), }); } export function extractExtendsRegistrar( call: CallExpression, sourceFile: SourceFile, ): ExtractOutput { const args = call.getArguments(); const first = args[0]; const extensionNameRef = first && readNameLiteralRef(first); if (!extensionNameRef) { return fail( "extendsRegistrar", sourceLocationFromNode(call, sourceFile), "first argument must be a string literal extension name, or an identifier resolving to one", ); } const defArg = args[1]; if (!defArg) { return fail( "extendsRegistrar", sourceLocationFromNode(call, sourceFile), "expected a definition argument", ); } return ok({ kind: "extendsRegistrar", source: sourceLocationFromNode(call, sourceFile), extensionName: extensionNameRef.value, ...(extensionNameRef.raw !== undefined && { extensionNameRaw: extensionNameRef.raw }), defBody: sourceLocationFromNode(defArg, sourceFile), }); } export function extractUsesApi( call: CallExpression, sourceFile: SourceFile, ): ExtractOutput { const arg = call.getArguments()[0]; const apiName = arg && readNameLiteral(arg); if (!apiName) { return fail( "usesApi", sourceLocationFromNode(call, sourceFile), 'expected a single string-literal API name (e.g. "sessions.revokeAllForUser"), or an identifier resolving to one', ); } return ok({ kind: "usesApi", source: sourceLocationFromNode(call, sourceFile), apiName, }); } export function extractExposesApi( call: CallExpression, sourceFile: SourceFile, ): ExtractOutput { const arg = call.getArguments()[0]; const apiName = arg && readNameLiteral(arg); if (!apiName) { return fail( "exposesApi", sourceLocationFromNode(call, sourceFile), 'expected a single string-literal API name (e.g. "sessions.revokeAllForUser"), or an identifier resolving to one', ); } return ok({ kind: "exposesApi", source: sourceLocationFromNode(call, sourceFile), apiName, }); } export function extractStoreTable( call: CallExpression, sourceFile: SourceFile, ): ExtractOutput { // The meta argument is always a factory call (defineUnmanagedTable / // deriveEntityTableMeta) or a captured identifier — never an inline literal, // so there is nothing to extract statically. A clean ParseError (not // UnknownPattern) marks it design-time-unreadable, like entity-by-identifier. return fail( "storeTable", sourceLocationFromNode(call, sourceFile), "storeTable meta is a factory/identifier argument, not a static literal", ); }