1 | const path = require('path')
|
2 | const majo = require('majo')
|
3 | const matcher = require('micromatch')
|
4 | const { glob, fs } = require('majo')
|
5 | const isBinaryPath = require('is-binary-path')
|
6 | const logger = require('./logger')
|
7 | const getGlobPatterns = require('./utils/getGlobPatterns')
|
8 |
|
9 | module.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 |
|
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 |
|
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 | })
|
151 | await Promise.all(
|
152 | files.map(file => {
|
153 | logger.fileAction('red', 'Removed', file)
|
154 | return fs.remove(file)
|
155 | })
|
156 | )
|
157 | }
|
158 | }
|
159 | }
|