summaryrefslogtreecommitdiff
path: root/src/config.ts
blob: fe4549929923b534ad7ccf91f0d23c4324f508cb (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
import type { AstroConfig } from './@types/astro';
import { join as pathJoin, resolve as pathResolve } from 'path';
import { existsSync } from 'fs';

/** Type util */
const type = (thing: any): string => (Array.isArray(thing) ? 'Array' : typeof thing);

/** Throws error if a user provided an invalid config. Manually-implemented to avoid a heavy validation library. */
function validateConfig(config: any): void {
  // basic
  if (config === undefined || config === null) throw new Error(`[astro config] Config empty!`);
  if (typeof config !== 'object') throw new Error(`[astro config] Expected object, received ${typeof config}`);

  // strings
  for (const key of ['projectRoot', 'astroRoot', 'dist', 'public']) {
    if (config[key] && typeof config[key] !== 'string') {
      throw new Error(`[astro config] ${key}: ${JSON.stringify(config[key])}\n  Expected string, received ${type(config[key])}.`);
    }
  }
}

/** Set default config values */
function configDefaults(userConfig?: any): any {
  const config: any = { ...(userConfig || {}) };

  if (!config.projectRoot) config.projectRoot = '.';
  if (!config.astroRoot) config.astroRoot = './astro';
  if (!config.dist) config.dist = './_site';
  if (!config.public) config.public = './public';

  return config;
}

/** Turn raw config values into normalized values */
function normalizeConfig(userConfig: any, root: string): AstroConfig {
  const config: any = { ...(userConfig || {}) };

  config.projectRoot = new URL(config.projectRoot + '/', root);
  config.astroRoot = new URL(config.astroRoot + '/', root);
  config.public = new URL(config.public + '/', root);

  return config as AstroConfig;
}

/** Attempt to load an `astro.config.mjs` file */
export async function loadConfig(rawRoot: string | undefined): Promise<AstroConfig> {
  if (typeof rawRoot === 'undefined') {
    rawRoot = process.cwd();
  }

  let config: any;

  const root = pathResolve(rawRoot);
  const fileProtocolRoot = `file://${root}/`;
  const astroConfigPath = pathJoin(root, 'astro.config.mjs');

  // load
  if (existsSync(astroConfigPath)) {
    config = configDefaults((await import(astroConfigPath)).default);
  } else {
    config = configDefaults();
  }

  // validate
  validateConfig(config);

  // normalize
  config = normalizeConfig(config, fileProtocolRoot);

  return config as AstroConfig;
}