-
Notifications
You must be signed in to change notification settings - Fork 962
/
mjmlconfig.js
139 lines (127 loc) · 4 KB
/
mjmlconfig.js
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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
import path from 'path'
import fs from 'fs'
import { registerDependencies } from 'mjml-validator'
import { registerComponent } from '../components'
export function readMjmlConfig(configPathOrDir = process.cwd()) {
let componentRootPath = process.cwd()
let mjmlConfigPath = configPathOrDir
try {
mjmlConfigPath = path
.basename(configPathOrDir)
.match(/^\.mjmlconfig(\.js)?$/)
? path.resolve(configPathOrDir)
: path.resolve(configPathOrDir, '.mjmlconfig')
componentRootPath = path.dirname(mjmlConfigPath)
const fullPath = path.resolve(mjmlConfigPath)
let mjmlConfig
if (path.extname(mjmlConfigPath) === '.js') {
delete require.cache[fullPath]
mjmlConfig = require(fullPath) // eslint-disable-line global-require, import/no-dynamic-require
} else {
mjmlConfig = JSON.parse(fs.readFileSync(fullPath, 'utf8'))
}
return { mjmlConfig, componentRootPath }
} catch (e) {
if (e.code !== 'ENOENT') {
console.error('Error reading mjmlconfig : ', e) // eslint-disable-line no-console
}
return {
mjmlConfig: { packages: [], options: {} },
mjmlConfigPath,
componentRootPath,
error: e,
}
}
}
export function resolveComponentPath(compPath, componentRootPath) {
if (!compPath) {
return null
}
if (!compPath.startsWith('.') && !path.isAbsolute(compPath)) {
try {
return require.resolve(compPath)
} catch (e) {
if (e.code !== 'MODULE_NOT_FOUND') {
console.error('Error resolving custom component path : ', e) // eslint-disable-line no-console
return null
}
// we got a 'MODULE_NOT_FOUND' error
try {
// try again as relative path to node_modules: (this may be necessary if mjml is installed globally or by npm link)
return resolveComponentPath(
`./node_modules/${compPath}`,
componentRootPath,
)
} catch (e) {
// try again as a plain local path:
return resolveComponentPath(`./${compPath}`, componentRootPath)
}
}
}
return require.resolve(path.resolve(componentRootPath, compPath))
}
export function registerCustomComponent(
comp,
registerCompFn = registerComponent,
) {
if (comp instanceof Function) {
registerCompFn(comp)
} else {
const compNames = Object.keys(comp) // this approach handles both an array and an object (like the mjml-accordion default export)
compNames.forEach((compName) => {
registerCustomComponent(comp[compName], registerCompFn)
})
}
}
export function handleMjmlConfigComponents(
packages,
componentRootPath,
registerCompFn,
) {
const result = {
success: [],
failures: [],
}
packages.forEach((compPath) => {
let resolvedPath = compPath
try {
resolvedPath = resolveComponentPath(compPath, componentRootPath)
if (resolvedPath) {
const requiredComp = require(resolvedPath) // eslint-disable-line global-require, import/no-dynamic-require
registerCustomComponent(
requiredComp.default || requiredComp,
registerCompFn,
)
registerDependencies(
(requiredComp.default || requiredComp).dependencies || {},
)
result.success.push(compPath)
}
} catch (e) {
result.failures.push({ error: e, compPath })
if (e.code === 'ENOENT' || e.code === 'MODULE_NOT_FOUND') {
console.error('Missing or unreadable custom component : ', resolvedPath) // eslint-disable-line no-console
} else {
// eslint-disable-next-line no-console
console.error(
'Error when registering custom component : ',
resolvedPath,
e,
)
}
}
})
return result
}
export default function handleMjmlConfig(
configPathOrDir = process.cwd(),
registerCompFn = registerComponent,
) {
const {
mjmlConfig: { packages },
componentRootPath,
error,
} = readMjmlConfig(configPathOrDir)
if (error) return { error }
return handleMjmlConfigComponents(packages, componentRootPath, registerCompFn)
}