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