{"version":3,"file":"read-typescript-config.d.ts","sourceRoot":"","sources":["../../src/read-typescript-config.ts"],"names":[],"mappings":";;;AAuBA,wBAGC","sourcesContent":["// read the actual configuration that tsc is using\n// reimplemented in this way to avoid pulling in the massive pile\n// of CommonJS that is the typescript module, since we really do not\n// need most of the logic that it (reasonably) applies when parsing\n// configs, just for our purposes.\nimport { dirname, isAbsolute, resolve } from 'node:path'\nimport config from './config.js'\nimport type { ParsedCommandLine } from 'typescript'\nimport { readFileSync, statSync } from 'node:fs'\nimport { walkUp } from 'walk-up-path'\nimport JSON from 'jsonc-simple-parser'\n\nconst isFile = (f: string) => {\n  try {\n    return statSync(f).isFile()\n  } catch {\n    return false\n  }\n}\n\nlet parsedTsConfig: Record<string, any> & {\n  compilerOptions: ParsedCommandLine['options']\n}\nexport default () => {\n  const configPath = config.project ?? 'tsconfig.json'\n  return (parsedTsConfig ??= parseTsConfig(resolveConfig(configPath)))\n}\n\nconst resolveConfig = (\n  target: string,\n  from: string = process.cwd(),\n): string => {\n  if (isAbsolute(target)) return target\n  let local = resolve(from, target)\n  if (!isFile(local) && isFile(local + '.json')) local += '.json'\n  if (\n    isFile(local) ||\n    target.startsWith('.\\\\') ||\n    target.startsWith('./')\n  ) {\n    return local\n  }\n\n  // starts with a package name?\n  for (const p of walkUp(from)) {\n    const found = resolve(p, 'node_modules', target)\n    if (isFile(found)) return found\n    const pre = resolve(p, 'node_modules', target)\n    const foundTsconfig = resolve(pre, 'tsconfig.json')\n    if (isFile(foundTsconfig)) return foundTsconfig\n    if (isFile(pre + '.json')) return pre + '.json'\n  }\n\n  throw new Error('Could not resolve tsconfig file location', {\n    cause: {\n      target,\n      from,\n    },\n  })\n}\n\nconst applyExtends = (\n  data: Record<string, any>,\n  base: Record<string, any>,\n) => {\n  for (const [key, val] of Object.entries(base)) {\n    if (typeof val !== 'object' || Array.isArray(val)) {\n      data[key] ??= val\n    } else if (!(key in data)) {\n      data[key] = val\n    } else if (\n      typeof data[key] === 'object' &&\n      !Array.isArray(data[key])\n    ) {\n      data[key] = applyExtends(data[key], val)\n    }\n  }\n  return data\n}\n\nconst parseTsConfig = (configPath: string, seen = new Set<string>()) => {\n  try {\n    const data = JSON.parse(\n      readFileSync(resolveConfig(configPath), 'utf8'),\n    )\n    if (!data || typeof data !== 'object' || Array.isArray(data)) {\n      throw new Error('invalid data, expected object', {\n        cause: data,\n      })\n    }\n    if (!data.compilerOptions) data.compilerOptions = {}\n    if (typeof data.extends === 'string') {\n      const ext = resolveConfig(data.extends, dirname(configPath))\n      if (!seen.has(ext)) {\n        seen.add(ext)\n        applyExtends(data, parseTsConfig(ext, seen))\n      }\n    }\n    return data\n  } catch (e) {\n    throw new Error('Invalid tsconfig file', { cause: e })\n  }\n}\n"]}