UNPKG

5.67 kBJavaScriptView Raw
1const path = require('path')
2const majo = require('majo')
3const matcher = require('micromatch')
4const { glob, fs } = require('majo')
5const isBinaryPath = require('is-binary-path')
6const logger = require('./logger')
7const getGlobPatterns = require('./utils/getGlobPatterns')
8
9module.exports = async (config, context) => {
10 const actions =
11 typeof config.actions === 'function' ?
12 await config.actions.call(context, context) :
13 config.actions
14
15 for (const action of actions) {
16 logger.debug('Running action:', action)
17 if (action.type === 'add' && action.files) {
18 const stream = majo()
19 stream.source(['!**/node_modules/**'].concat(action.files), {
20 baseDir: path.resolve(
21 context.generator.path,
22 config.templateDir || 'template'
23 )
24 })
25
26 if (action.filters) {
27 const excludedPatterns = getGlobPatterns(
28 action.filters,
29 context.answers,
30 true
31 )
32
33 if (excludedPatterns.length > 0) {
34 stream.use(() => {
35 const excludedFiles = matcher(stream.fileList, excludedPatterns)
36 for (const file of excludedFiles) {
37 stream.deleteFile(file)
38 }
39 })
40 }
41 }
42
43 const shouldTransform =
44 typeof action.transform === 'boolean' ?
45 action.transform :
46 config.transform !== false
47
48 if (shouldTransform) {
49 stream.use(({ files }) => {
50 let fileList = Object.keys(stream.files)
51
52 // Exclude binary path
53 fileList = fileList.filter(fp => !isBinaryPath(fp))
54
55 if (action.transformInclude) {
56 fileList = matcher(fileList, action.transformInclude)
57 }
58 if (action.transformExclude) {
59 fileList = matcher.not(fileList, action.transformExclude)
60 }
61
62 const modulePaths = [context.generator.path, ...module.paths]
63 const transformerName = config.transformer || 'ejs'
64 let transformerPath
65 try {
66 transformerPath = require.resolve(
67 `jstransformer-${transformerName}`,
68 {
69 paths: modulePaths
70 }
71 )
72 } catch (err) {
73 throw new Error(`Cannot resolve transfomer: ${transformerName}`)
74 }
75
76 const transformer = require('jstransformer')(
77 require(transformerPath)
78 )
79
80 fileList.forEach(relativePath => {
81 const contents = files[relativePath].contents.toString()
82
83 logger.debug('context.data', context.data)
84 stream.writeContents(
85 relativePath,
86 transformer.render(
87 contents,
88 config.transformerOptions,
89 Object.assign({}, context.answers, {
90 context
91 }, context.data)
92 ).body
93 )
94 })
95 })
96 }
97 stream.on('write', (_, targetPath) => {
98 logger.fileAction('magenta', 'Created', targetPath)
99 })
100
101 const target = action.target || config.target || '.'
102 const outDir = path.resolve(context.outDir, target)
103 logger.debug('add_action_outDir', outDir)
104 await stream.dest(outDir)
105 } else if (action.type === 'modify' && action.handler) {
106 const stream = majo()
107 stream.source(action.files, { baseDir: context.outDir })
108 stream.use(async ({ files }) => {
109 await Promise.all(
110 // eslint-disable-next-line array-callback-return
111 Object.keys(files).map(async relativePath => {
112 const isJson = relativePath.endsWith('.json')
113 let contents = stream.fileContents(relativePath)
114 if (isJson) {
115 contents = JSON.parse(contents)
116 }
117 let result = await action.handler.call(context, contents, relativePath)
118 if (isJson) {
119 result = JSON.stringify(result, null, 2)
120 }
121 stream.writeContents(relativePath, result)
122 logger.fileAction(
123 'yellow',
124 'Modified',
125 path.join(context.outDir, relativePath)
126 )
127 })
128 )
129 })
130 await stream.dest(context.outDir)
131 } else if (action.type === 'move' && action.patterns) {
132 await Promise.all(
133 Object.keys(action.patterns).map(async pattern => {
134 const files = await glob(pattern, {
135 cwd: context.outDir,
136 absolute: true,
137 onlyFiles: false
138 })
139 if (files.length > 1) {
140 throw new Error('"move" pattern can only match one file!')
141 } else if (files.length === 1) {
142 const from = files[0]
143 const to = path.join(context.outDir, action.patterns[pattern])
144 await fs.move(from, to, {
145 overwrite: true
146 })
147 logger.fileMoveAction(from, to)
148 }
149 })
150 )
151 } else if (action.type === 'remove' && action.files) {
152 let patterns
153 if (typeof action.files === 'function') {
154 action.files = action.files(context.answers)
155 }
156 if (typeof action.files === 'string' || Array.isArray(action.files)) {
157 patterns = [].concat(action.files)
158 } else if (typeof action.files === 'object') {
159 patterns = getGlobPatterns(action.files, context.answers)
160 }
161 const files = await glob(patterns, {
162 cwd: context.outDir,
163 absolute: true
164 })
165 await Promise.all(
166 files.map(file => {
167 logger.fileAction('red', 'Removed', file)
168 return fs.remove(file)
169 })
170 )
171 }
172 }
173}