1 | const chalk = require("chalk");
|
2 | const Metalsmith = require("metalsmith");
|
3 | const Handlebars = require("handlebars");
|
4 | const async = require("async");
|
5 | const render = require("consolidate").handlebars.render;
|
6 | const path = require("path");
|
7 | const multimatch = require("multimatch");
|
8 | const getOptions = require("./options");
|
9 | const ask = require("./ask");
|
10 | const filter = require("./filter");
|
11 | const logger = require("./logger");
|
12 |
|
13 |
|
14 | Handlebars.registerHelper("if_eq", function(a, b, opts) {
|
15 | return a === b ? opts.fn(this) : opts.inverse(this);
|
16 | });
|
17 |
|
18 | Handlebars.registerHelper("unless_eq", function(a, b, opts) {
|
19 | return a === b ? opts.inverse(this) : opts.fn(this);
|
20 | });
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 | module.exports = function generate(name, src, dest, done) {
|
32 | const opts = getOptions(name, src);
|
33 | const metalsmith = Metalsmith(path.join(src));
|
34 | const data = Object.assign(metalsmith.metadata(), {
|
35 | destDirName: name,
|
36 | inPlace: dest === process.cwd(),
|
37 | noEscape: true
|
38 | });
|
39 | opts.helpers &&
|
40 | Object.keys(opts.helpers).map(key => {
|
41 | Handlebars.registerHelper(key, opts.helpers[key]);
|
42 | });
|
43 |
|
44 | const helpers = { chalk, logger };
|
45 |
|
46 | if (opts.metalsmith && typeof opts.metalsmith.before === "function") {
|
47 | opts.metalsmith.before(metalsmith, opts, helpers);
|
48 | }
|
49 |
|
50 | metalsmith
|
51 | .use(askQuestions(opts.prompts))
|
52 | .use(filterFiles(opts.filters))
|
53 | .use(renderTemplateFiles(opts.skipInterpolation));
|
54 |
|
55 | if (typeof opts.metalsmith === "function") {
|
56 | opts.metalsmith(metalsmith, opts, helpers);
|
57 | } else if (opts.metalsmith && typeof opts.metalsmith.after === "function") {
|
58 | opts.metalsmith.after(metalsmith, opts, helpers);
|
59 | }
|
60 |
|
61 | metalsmith
|
62 | .clean(false)
|
63 | .source(".")
|
64 | .destination(dest)
|
65 | .build((err, files) => {
|
66 | done(err);
|
67 | if (typeof opts.complete === "function") {
|
68 | const helpers = { chalk, logger, files };
|
69 | opts.complete(data, helpers);
|
70 | } else {
|
71 | logMessage(opts.completeMessage, data);
|
72 | }
|
73 | });
|
74 |
|
75 | return data;
|
76 | };
|
77 |
|
78 |
|
79 |
|
80 |
|
81 |
|
82 |
|
83 |
|
84 |
|
85 | function askQuestions(prompts) {
|
86 | return (files, metalsmith, done) => {
|
87 | ask(prompts, metalsmith.metadata(), done);
|
88 | };
|
89 | }
|
90 |
|
91 |
|
92 |
|
93 |
|
94 |
|
95 |
|
96 |
|
97 |
|
98 | function filterFiles(filters) {
|
99 | return (files, metalsmith, done) => {
|
100 | filter(files, filters, metalsmith.metadata(), done);
|
101 | };
|
102 | }
|
103 |
|
104 |
|
105 |
|
106 |
|
107 |
|
108 |
|
109 |
|
110 |
|
111 |
|
112 | function renderTemplateFiles(skipInterpolation) {
|
113 | skipInterpolation =
|
114 | typeof skipInterpolation === "string"
|
115 | ? [skipInterpolation]
|
116 | : skipInterpolation;
|
117 | return (files, metalsmith, done) => {
|
118 | const keys = Object.keys(files);
|
119 | const metalsmithMetadata = metalsmith.metadata();
|
120 | async.each(
|
121 | keys,
|
122 | (file, next) => {
|
123 |
|
124 | if (
|
125 | skipInterpolation &&
|
126 | multimatch([file], skipInterpolation, { dot: true }).length
|
127 | ) {
|
128 | return next();
|
129 | }
|
130 | const str = files[file].contents.toString();
|
131 |
|
132 | if (!/{{([^{}]+)}}/g.test(str) && !(/package.json|vender-list.js/g.test(file))) {
|
133 | return next();
|
134 | }
|
135 | render(str, metalsmithMetadata, (err, res) => {
|
136 | if (err) {
|
137 | err.message = `[${file}] ${err.message}`;
|
138 | return next(err);
|
139 | }
|
140 | if (file === "package.json") {
|
141 | const packageFile = generatePackageJson(res);
|
142 | files[file].contents = new Buffer(packageFile);
|
143 | return next();
|
144 | }
|
145 |
|
146 | if (file === "vender-list.js" && global["talentui_info"]["dllList"]) {
|
147 | const dllListFile = renderDllListFile(res);
|
148 | files[file].contents = new Buffer(dllListFile);
|
149 | return next();
|
150 | }
|
151 | files[file].contents = new Buffer(res);
|
152 | next();
|
153 | });
|
154 | },
|
155 | done
|
156 | );
|
157 | };
|
158 | }
|
159 | function renderDllListFile(res){
|
160 |
|
161 | const str = global["talentui_info"]["dllList"].map(item => `"${item.split('@')[0]}"`).toString()
|
162 | return `module.exports = [${str}];`
|
163 | }
|
164 | function generatePackageJson(res) {
|
165 | let contentJson = JSON.parse(res);
|
166 | let {
|
167 | name,
|
168 | version,
|
169 | author,
|
170 | repository_type,
|
171 | repository_url,
|
172 | bugs_url,
|
173 | homePage,
|
174 | description
|
175 | } = global["talentui_info"];
|
176 | contentJson.name = name;
|
177 | contentJson.version = version;
|
178 | contentJson.author = author;
|
179 | contentJson.repository = {
|
180 | type: repository_type,
|
181 | url: repository_url
|
182 | };
|
183 | contentJson.bugs = {
|
184 | url: bugs_url
|
185 | };
|
186 | contentJson.homepage = homePage;
|
187 | contentJson.description = description;
|
188 |
|
189 | if (global["talentui_info"]["dllList"]) {
|
190 | let dllList = global["talentui_info"]["dllList"];
|
191 | dllList.map(item => {
|
192 | let name = item.split('@')[0];
|
193 | let version = item.split('@')[1];
|
194 | contentJson.devDependencies[name] = version;
|
195 | contentJson.peerDependencies[name] = version;
|
196 | })
|
197 | }
|
198 | return JSON.stringify(contentJson, null, 4);
|
199 | }
|
200 |
|
201 |
|
202 |
|
203 |
|
204 |
|
205 |
|
206 |
|
207 | function logMessage(message, data) {
|
208 | if (!message) return;
|
209 | render(message, data, (err, res) => {
|
210 | if (err) {
|
211 | console.error(
|
212 | "\n Error when rendering template complete message: " +
|
213 | err.message.trim()
|
214 | );
|
215 | } else {
|
216 | console.log(
|
217 | "\n" +
|
218 | res
|
219 | .split(/\r?\n/g)
|
220 | .map(line => " " + line)
|
221 | .join("\n")
|
222 | );
|
223 | }
|
224 | });
|
225 | }
|