UNPKG

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