{"version":3,"sources":["../src/env-types.ts","../src/write-file-if-changed.ts"],"sourcesContent":["import * as fs from \"fs\";\nimport * as path from \"path\";\nimport { writeFileIfChanged } from \"./write-file-if-changed\";\n\nexport interface GenerateEnvTypesOptions {\n  root: string;\n  srcDir?: string;\n  outFile?: string;\n  configPath?: string;\n  /** Lower-priority layer config files, ordered before the project config. */\n  layerConfigPaths?: readonly string[];\n}\n\nconst DEFAULT_OUT_FILE = \"farm-env.d.ts\";\nconst CONFIG_FILENAMES = [\n  \"farm.config.ts\",\n  \"farm.config.tsx\",\n  \"farm.config.mts\",\n  \"farm.config.cts\",\n  \"farm.config.js\",\n  \"farm.config.jsx\",\n  \"farm.config.mjs\",\n  \"farm.config.cjs\",\n  \"config.ts\",\n  \"config.tsx\",\n  \"config.mts\",\n  \"config.cts\",\n  \"config.js\",\n  \"config.jsx\",\n  \"config.mjs\",\n  \"config.cjs\",\n];\n\nexport async function generateEnvTypes(options: GenerateEnvTypesOptions): Promise<string> {\n  const root = path.resolve(options.root);\n  const srcDir = options.srcDir || \"src\";\n  const outFile = options.outFile || DEFAULT_OUT_FILE;\n  const outPath = path.isAbsolute(outFile) ? outFile : path.join(root, srcDir, outFile);\n  const content = createEnvTypeDeclarations(options, outPath);\n\n  fs.mkdirSync(path.dirname(outPath), { recursive: true });\n  writeFileIfChanged(outPath, content);\n\n  return outPath;\n}\n\nexport function createEnvTypeDeclarations(\n  options: GenerateEnvTypesOptions,\n  outPath: string,\n): string {\n  const root = path.resolve(options.root);\n  const configPath = findConfigPath(root, options.configPath);\n  const configPaths = [\n    ...(options.layerConfigPaths ?? []).filter((value) => fs.existsSync(value)),\n    ...(configPath ? [configPath] : []),\n  ];\n  const content =\n    configPaths.length > 1\n      ? createLayeredConfigBackedEnvTypes(outPath, configPaths)\n      : configPaths.length === 1\n        ? createConfigBackedEnvTypes(outPath, configPaths[0])\n        : createEmptyEnvTypes();\n\n  return content;\n}\n\nfunction createLayeredConfigBackedEnvTypes(outPath: string, configPaths: string[]): string {\n  const imports = configPaths\n    .map(\n      (configPath, index) =>\n        `import type FarmConfig${index} from ${JSON.stringify(toTypeImportPath(outPath, configPath))};`,\n    )\n    .join(\"\\n\");\n  const resolvedTypes = configPaths\n    .map(\n      (_configPath, index) => `\ntype FarmConfigEnv${index} = typeof FarmConfig${index} extends { env?: infer TEnv }\n  ? NonNullable<TEnv>\n  : never;\ntype FarmResolvedEnv${index} = [FarmConfigEnv${index}] extends [never]\n  ? { server: {}; public: {} }\n  : InferEnv<FarmConfigEnv${index}>;`,\n    )\n    .join(\"\\n\");\n  const mergedTypes = configPaths\n    .slice(1)\n    .map(\n      (_configPath, index) =>\n        `type FarmMergedEnv${index + 1} = MergeFarmEnv<${index === 0 ? \"FarmResolvedEnv0\" : `FarmMergedEnv${index}`}, FarmResolvedEnv${index + 1}>;`,\n    )\n    .join(\"\\n\");\n  const finalType = `FarmMergedEnv${configPaths.length - 1}`;\n\n  return `/**\n * Auto-generated env types from Farm layers and farm.config.\n * Regenerated on dev start, build, and farm generate.\n */\n${imports}\nimport type { InferEnv } from \"@farm.js/core/env\";\n\ntype MergeFarmEnv<TBase, TOverride> = {\n  server: Omit<TBase extends { server: infer T } ? T : {}, keyof (TOverride extends { server: infer T } ? T : {})> &\n    (TOverride extends { server: infer T } ? T : {});\n  public: Omit<TBase extends { public: infer T } ? T : {}, keyof (TOverride extends { public: infer T } ? T : {})> &\n    (TOverride extends { public: infer T } ? T : {});\n};\n${resolvedTypes}\n${mergedTypes}\n\ntype FarmResolvedEnv = ${finalType};\n\ndeclare module \"@farm.js/core/env\" {\n  interface FarmEnvTypes {\n    server: FarmResolvedEnv[\"server\"];\n    public: FarmResolvedEnv[\"public\"];\n  }\n}\n\ndeclare module \"@farm.js/core\" {\n  interface FarmEnvTypes {\n    server: FarmResolvedEnv[\"server\"];\n    public: FarmResolvedEnv[\"public\"];\n  }\n}\n\nexport {};\n`;\n}\n\nfunction findConfigPath(root: string, configPath?: string): string | null {\n  if (configPath) {\n    const resolvedPath = path.isAbsolute(configPath) ? configPath : path.join(root, configPath);\n    return fs.existsSync(resolvedPath) ? resolvedPath : null;\n  }\n\n  for (const filename of CONFIG_FILENAMES) {\n    const resolvedPath = path.join(root, filename);\n    if (fs.existsSync(resolvedPath)) {\n      return resolvedPath;\n    }\n  }\n\n  return null;\n}\n\nfunction createConfigBackedEnvTypes(outPath: string, configPath: string): string {\n  const configImportPath = toTypeImportPath(outPath, configPath);\n\n  return `/**\n * Auto-generated env types from farm.config.\n * Regenerated on dev start, build, and farm generate.\n */\nimport type FarmConfig from ${JSON.stringify(configImportPath)};\nimport type { InferEnv } from \"@farm.js/core/env\";\n\ntype FarmConfigEnv = typeof FarmConfig extends { env?: infer TEnv } ? NonNullable<TEnv> : never;\ntype FarmResolvedEnv = [FarmConfigEnv] extends [never]\n  ? { server: {}; public: {} }\n  : InferEnv<FarmConfigEnv>;\n\ndeclare module \"@farm.js/core/env\" {\n  interface FarmEnvTypes {\n    server: FarmResolvedEnv[\"server\"];\n    public: FarmResolvedEnv[\"public\"];\n  }\n}\n\ndeclare module \"@farm.js/core\" {\n  interface FarmEnvTypes {\n    server: FarmResolvedEnv[\"server\"];\n    public: FarmResolvedEnv[\"public\"];\n  }\n}\n\nexport {};\n`;\n}\n\nfunction createEmptyEnvTypes(): string {\n  return `/**\n * Auto-generated env types from farm.config.\n * Regenerated on dev start, build, and farm generate.\n */\ndeclare module \"@farm.js/core/env\" {\n  interface FarmEnvTypes {\n    server: {};\n    public: {};\n  }\n}\n\ndeclare module \"@farm.js/core\" {\n  interface FarmEnvTypes {\n    server: {};\n    public: {};\n  }\n}\n\nexport {};\n`;\n}\n\nfunction toTypeImportPath(outPath: string, targetPath: string): string {\n  const relativePath = path\n    .relative(path.dirname(outPath), targetPath)\n    .replace(/\\\\/g, \"/\")\n    .replace(/\\.(tsx?|jsx?|mjs|cjs|mts|cts)$/, \"\");\n\n  return relativePath.startsWith(\".\") ? relativePath : `./${relativePath}`;\n}\n","import { readFileSync, writeFileSync } from \"node:fs\";\n\nexport function writeFileIfChanged(filePath: string, content: string): boolean {\n  try {\n    if (readFileSync(filePath, \"utf8\") === content) {\n      return false;\n    }\n  } catch (error) {\n    if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") {\n      throw error;\n    }\n  }\n\n  writeFileSync(filePath, content, \"utf8\");\n  return true;\n}\n"],"mappings":"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","names":[]}