1 |
|
2 | 'use strict'
|
3 | const fs = require('fs')
|
4 | const path = require('path')
|
5 | const YError = require('./yerror')
|
6 |
|
7 | let previouslyVisitedConfigs = []
|
8 |
|
9 | function checkForCircularExtends (cfgPath) {
|
10 | if (previouslyVisitedConfigs.indexOf(cfgPath) > -1) {
|
11 | throw new YError(`Circular extended configurations: '${cfgPath}'.`)
|
12 | }
|
13 | }
|
14 |
|
15 | function getPathToDefaultConfig (cwd, pathToExtend) {
|
16 | return path.resolve(cwd, pathToExtend)
|
17 | }
|
18 |
|
19 | function mergeDeep (config1, config2) {
|
20 | const target = {}
|
21 | const isObject = obj => obj && typeof obj === 'object' && !Array.isArray(obj)
|
22 | Object.assign(target, config1)
|
23 | for (const key of Object.keys(config2)) {
|
24 | if (isObject(config2[key]) && isObject(target[key])) {
|
25 | target[key] = mergeDeep(config1[key], config2[key])
|
26 | } else {
|
27 | target[key] = config2[key]
|
28 | }
|
29 | }
|
30 | return target
|
31 | }
|
32 |
|
33 | function applyExtends (config, cwd, mergeExtends) {
|
34 | let defaultConfig = {}
|
35 |
|
36 | if (Object.prototype.hasOwnProperty.call(config, 'extends')) {
|
37 | if (typeof config.extends !== 'string') return defaultConfig
|
38 | const isPath = /\.json|\..*rc$/.test(config.extends)
|
39 | let pathToDefault = null
|
40 | if (!isPath) {
|
41 | try {
|
42 | pathToDefault = require.resolve(config.extends)
|
43 | } catch (err) {
|
44 |
|
45 | }
|
46 | } else {
|
47 | pathToDefault = getPathToDefaultConfig(cwd, config.extends)
|
48 | }
|
49 |
|
50 |
|
51 | if (!pathToDefault && !isPath) return config
|
52 |
|
53 | checkForCircularExtends(pathToDefault)
|
54 |
|
55 | previouslyVisitedConfigs.push(pathToDefault)
|
56 |
|
57 | defaultConfig = isPath ? JSON.parse(fs.readFileSync(pathToDefault, 'utf8')) : require(config.extends)
|
58 | delete config.extends
|
59 | defaultConfig = applyExtends(defaultConfig, path.dirname(pathToDefault), mergeExtends)
|
60 | }
|
61 |
|
62 | previouslyVisitedConfigs = []
|
63 |
|
64 | return mergeExtends ? mergeDeep(defaultConfig, config) : Object.assign({}, defaultConfig, config)
|
65 | }
|
66 |
|
67 | module.exports = applyExtends
|