1 |
|
2 |
|
3 | import type {Config, File, FilePath} from '@parcel/types';
|
4 | import type {FileSystem} from '@parcel/fs';
|
5 | import path from 'path';
|
6 | import clone from 'clone';
|
7 |
|
8 | type ConfigOutput = {|
|
9 | config: Config,
|
10 | files: Array<File>
|
11 | |};
|
12 |
|
13 | type ConfigOptions = {|
|
14 | parse?: boolean
|
15 | |};
|
16 |
|
17 | const PARSERS = {
|
18 | json: require('json5').parse,
|
19 | toml: require('@iarna/toml').parse
|
20 | };
|
21 |
|
22 | const existsCache = new Map();
|
23 |
|
24 | export async function resolveConfig(
|
25 | fs: FileSystem,
|
26 | filepath: FilePath,
|
27 | filenames: Array<FilePath>,
|
28 | opts: ?ConfigOptions,
|
29 | root: FilePath = path.parse(filepath).root
|
30 | ): Promise<FilePath | null> {
|
31 | filepath = path.dirname(filepath);
|
32 |
|
33 |
|
34 | if (filepath === root || path.basename(filepath) === 'node_modules') {
|
35 | return null;
|
36 | }
|
37 |
|
38 | for (const filename of filenames) {
|
39 | let file = path.join(filepath, filename);
|
40 | if (await fs.exists(file)) {
|
41 | return file;
|
42 | }
|
43 | }
|
44 |
|
45 | return resolveConfig(fs, filepath, filenames, opts);
|
46 | }
|
47 |
|
48 | export async function loadConfig(
|
49 | fs: FileSystem,
|
50 | filepath: FilePath,
|
51 | filenames: Array<FilePath>,
|
52 | opts: ?ConfigOptions
|
53 | ): Promise<ConfigOutput | null> {
|
54 | let configFile = await resolveConfig(fs, filepath, filenames, opts);
|
55 | if (configFile) {
|
56 | try {
|
57 | let extname = path.extname(configFile).slice(1);
|
58 | if (extname === 'js') {
|
59 | return {
|
60 |
|
61 | config: clone(require(configFile)),
|
62 | files: [{filePath: configFile}]
|
63 | };
|
64 | }
|
65 |
|
66 | let configContent = await fs.readFile(configFile, 'utf8');
|
67 | if (!configContent) {
|
68 | return null;
|
69 | }
|
70 |
|
71 | let config;
|
72 | if (opts && opts.parse === false) {
|
73 | config = configContent;
|
74 | } else {
|
75 | let parse = PARSERS[extname] || PARSERS.json;
|
76 | config = parse(configContent);
|
77 | }
|
78 |
|
79 | return {
|
80 | config: config,
|
81 | files: [{filePath: configFile}]
|
82 | };
|
83 | } catch (err) {
|
84 | if (err.code === 'MODULE_NOT_FOUND' || err.code === 'ENOENT') {
|
85 | existsCache.delete(configFile);
|
86 | return null;
|
87 | }
|
88 |
|
89 | throw err;
|
90 | }
|
91 | }
|
92 |
|
93 | return null;
|
94 | }
|