-
-
Notifications
You must be signed in to change notification settings - Fork 6.3k
/
Copy pathGeneratorAPI.js
117 lines (107 loc) · 3.56 KB
/
GeneratorAPI.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
const fs = require('fs')
const ejs = require('ejs')
const path = require('path')
const walk = require('klaw-sync')
const isBinary = require('isbinaryfile')
const mergeDeps = require('./util/mergeDeps')
const errorParser = require('error-stack-parser')
const isString = val => typeof val === 'string'
const isFunction = val => typeof val === 'function'
const isObject = val => val && typeof val === 'object'
module.exports = class GeneratorAPI {
constructor (id, generator, options) {
this.id = id
this.generator = generator
this.options = options
}
injectFileMiddleware (middleware) {
this.generator.fileMiddlewares.push(middleware)
}
extendPackage (fields, options = { merge: true }) {
const pkg = this.generator.pkg
const toMerge = isFunction(fields) ? fields(pkg) : fields
for (const key in toMerge) {
const value = toMerge[key]
const existing = pkg[key]
if (isObject(value) && (key === 'dependencies' || key === 'devDependencies')) {
// use special version resolution merge
pkg[key] = mergeDeps(
this.id,
existing || {},
value,
this.generator.depSources
)
} else if (!options.merge || !(key in pkg)) {
pkg[key] = value
} else if (Array.isArray(value) && Array.isArray(existing)) {
pkg[key] = existing.concat(value)
} else if (isObject(value) && isObject(existing)) {
pkg[key] = Object.assign({}, existing, value)
} else {
pkg[key] = value
}
}
}
render (fileDir, additionalData = {}, ejsOptions = {}) {
const baseDir = extractCallDir()
if (isString(fileDir)) {
fileDir = path.resolve(baseDir, fileDir)
this.injectFileMiddleware(files => {
const data = Object.assign({
options: this.options
}, additionalData)
const _files = walk(fileDir, {
nodir: true,
filter: file => path.basename(file.path) !== '.DS_Store'
})
for (const file of _files) {
const relativePath = path.relative(fileDir, file.path)
const content = renderFile(file.path, data, ejsOptions)
if (Buffer.isBuffer(content) || content.trim()) {
files[relativePath] = content
}
}
})
} else if (isObject(fileDir)) {
this.injectFileMiddleware(files => {
const data = Object.assign({
options: this.options
}, additionalData)
for (const targetPath in fileDir) {
const sourcePath = path.resolve(baseDir, fileDir[targetPath])
const content = renderFile(sourcePath, data, ejsOptions)
if (Buffer.isBuffer(content) || content.trim()) {
files[targetPath] = content
}
}
})
} else if (isFunction(fileDir)) {
this.injectFileMiddleware(fileDir)
}
}
onCreateComplete (cb) {
this.generator.completeCbs.push(cb)
}
resolve (_path) {
return path.resolve(this.generator.context, _path)
}
hasPlugin (_id) {
const prefixRE = /^(@vue\/|vue-)cli-plugin-/
return this.generator.plugins.some(({ id }) => {
return id === _id || id.replace(prefixRE, '') === _id
})
}
}
function extractCallDir () {
// extract api.render() callsite file location using error stack
const obj = {}
Error.captureStackTrace(obj)
const stack = errorParser.parse(obj)
return path.dirname(stack[2].fileName)
}
function renderFile (name, data, ejsOptions) {
if (isBinary.sync(name)) {
return fs.readFileSync(name) // return buffer
}
return ejs.render(fs.readFileSync(name, 'utf-8'), data, ejsOptions)
}