UNPKG

5.33 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 action.templateDir || 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 const templateData = action.templateData || config.templateData
67 stream.writeContents(
68 relativePath,
69 transformer.render(
70 contents,
71 config.transformerOptions,
72 Object.assign(
73 {},
74 context.answers,
75 typeof templateData === 'function'
76 ? templateData.call(context, context)
77 : templateData,
78 {
79 context
80 }
81 )
82 ).body
83 )
84 })
85 })
86 }
87 stream.on('write', (_, targetPath) => {
88 logger.fileAction('magenta', 'Created', targetPath)
89 })
90 await stream.dest(context.outDir)
91 } else if (action.type === 'modify' && action.handler) {
92 const stream = majo()
93 stream.source(action.files, { baseDir: context.outDir })
94 stream.use(async ({ files }) => {
95 await Promise.all(
96 // eslint-disable-next-line array-callback-return
97 Object.keys(files).map(async relativePath => {
98 const isJson = relativePath.endsWith('.json')
99 let contents = stream.fileContents(relativePath)
100 if (isJson) {
101 contents = JSON.parse(contents)
102 }
103 let result = await action.handler(contents, relativePath)
104 if (isJson) {
105 result = JSON.stringify(result, null, 2)
106 }
107 stream.writeContents(relativePath, result)
108 logger.fileAction(
109 'yellow',
110 'Modified',
111 path.join(context.outDir, relativePath)
112 )
113 })
114 )
115 })
116 await stream.dest(context.outDir)
117 } else if (action.type === 'move' && action.patterns) {
118 await Promise.all(
119 Object.keys(action.patterns).map(async pattern => {
120 const files = await glob(pattern, {
121 cwd: context.outDir,
122 absolute: true,
123 onlyFiles: false
124 })
125 if (files.length > 1) {
126 throw new Error('"move" pattern can only match one file!')
127 } else if (files.length === 1) {
128 const from = files[0]
129 const to = path.join(context.outDir, action.patterns[pattern])
130 await fs.move(from, to, {
131 overwrite: true
132 })
133 logger.fileMoveAction(from, to)
134 }
135 })
136 )
137 } else if (action.type === 'remove' && action.files) {
138 let patterns
139 if (typeof action.files === 'function') {
140 action.files = action.files(context.answers)
141 }
142 if (typeof action.files === 'string' || Array.isArray(action.files)) {
143 patterns = [].concat(action.files)
144 } else if (typeof action.files === 'object') {
145 patterns = getGlobPatterns(action.files, context.answers)
146 }
147 const files = await glob(patterns, {
148 cwd: context.outDir,
149 absolute: true,
150 onlyFiles: false
151 })
152 await Promise.all(
153 files.map(file => {
154 logger.fileAction('red', 'Removed', file)
155 return fs.remove(file)
156 })
157 )
158 }
159 }
160}