UNPKG

4.98 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 if (shouldTransform) {
48 stream.use(({ files }) => {
49 let fileList = Object.keys(stream.files)
50
51 // Exclude binary path
52 fileList = fileList.filter(fp => !isBinaryPath(fp))
53
54 if (action.transformInclude) {
55 fileList = matcher(fileList, action.transformInclude)
56 }
57 if (action.transformExclude) {
58 fileList = matcher.not(fileList, action.transformExclude)
59 }
60
61 fileList.forEach(relativePath => {
62 const contents = files[relativePath].contents.toString()
63 const transformer = require('jstransformer')(
64 require(`jstransformer-${config.transformer || 'ejs'}`)
65 )
66 stream.writeContents(
67 relativePath,
68 transformer.render(
69 contents,
70 config.transformerOptions,
71 Object.assign({}, context.answers, {
72 context
73 })
74 ).body
75 )
76 })
77 })
78 }
79 stream.on('write', (_, targetPath) => {
80 logger.fileAction('magenta', 'Created', targetPath)
81 })
82 await stream.dest(context.outDir)
83 } else if (action.type === 'modify' && action.handler) {
84 const stream = majo()
85 stream.source(action.files, { baseDir: context.outDir })
86 stream.use(async ({ files }) => {
87 await Promise.all(
88 // eslint-disable-next-line array-callback-return
89 Object.keys(files).map(async relativePath => {
90 const isJson = relativePath.endsWith('.json')
91 let contents = stream.fileContents(relativePath)
92 if (isJson) {
93 contents = JSON.parse(contents)
94 }
95 let result = await action.handler(contents, relativePath)
96 if (isJson) {
97 result = JSON.stringify(result, null, 2)
98 }
99 stream.writeContents(relativePath, result)
100 logger.fileAction(
101 'yellow',
102 'Modified',
103 path.join(context.outDir, relativePath)
104 )
105 })
106 )
107 })
108 await stream.dest(context.outDir)
109 } else if (action.type === 'move' && action.patterns) {
110 await Promise.all(
111 Object.keys(action.patterns).map(async pattern => {
112 const files = await glob(pattern, {
113 cwd: context.outDir,
114 absolute: true,
115 onlyFiles: false
116 })
117 if (files.length > 1) {
118 throw new Error('"move" pattern can only match one file!')
119 } else if (files.length === 1) {
120 const from = files[0]
121 const to = path.join(context.outDir, action.patterns[pattern])
122 await fs.move(from, to, {
123 overwrite: true
124 })
125 logger.fileMoveAction(from, to)
126 }
127 })
128 )
129 } else if (action.type === 'remove' && action.files) {
130 let patterns
131 if (typeof action.files === 'function') {
132 action.files = action.files(context.answers)
133 }
134 if (typeof action.files === 'string' || Array.isArray(action.files)) {
135 patterns = [].concat(action.files)
136 } else if (typeof action.files === 'object') {
137 patterns = getGlobPatterns(action.files, context.answers)
138 }
139 const files = await glob(patterns, {
140 cwd: context.outDir,
141 absolute: true
142 })
143 await Promise.all(
144 files.map(file => {
145 logger.fileAction('red', 'Removed', file)
146 return fs.remove(file)
147 })
148 )
149 }
150 }
151}