UNPKG

14.2 kBJavaScriptView Raw
1#!/usr/bin/env node
2
3const yargs = require("yargs");
4const path = require("path");
5const fs = require("fs-extra");
6const chalk = require('chalk');
7const inquirer = require('inquirer');
8const ora = require('ora');
9const shelljs = require('shelljs');
10const utils = require("./lib/utils");
11const logger = require("./lib/utils/logger");
12const backup = require("./lib/utils/backup");
13const runapp = require("./lib/run");
14const builder = require("./lib/builder");
15const plugin = require('./lib/plugin');
16const create = require('./lib/plugin/create');
17const publish = require('./lib/plugin/publish');
18
19const TemplateRelease = require("./template-release");
20const constants = require('./index').constants;
21const templateRelease = new TemplateRelease(constants.cacheDirName, constants.templateReleaseUrl);
22
23let questions = function (inputName, releaseLists) {
24 let applicationid = "";
25 return [{
26 type: 'input',
27 name: 'name',
28 default: function () {
29 if (typeof inputName !== 'string') inputName = "";
30 return inputName.trim() ? inputName.trim() : 'weiui-demo';
31 },
32 message: "请输入项目名称",
33 validate: function (value) {
34 let pass = value.match(/^[0-9a-z\-_]+$/i);
35 if (pass) {
36 return true;
37 }
38
39 return '输入格式错误,请重新输入。';
40 }
41 }, {
42 type: 'input',
43 name: 'appName',
44 default: function () {
45 return 'Weiui演示';
46 },
47 message: "请输入app名称",
48 validate: function (value) {
49 return value !== ''
50 }
51 }, {
52 type: 'input',
53 name: 'applicationID',
54 default: function () {
55 return 'cc.weiui.demo';
56 },
57 message: "请输入Android应用ID",
58 validate: function (value) {
59 let pass = value.match(/^[a-zA-Z_][a-zA-Z0-9_]*[.][a-zA-Z_][a-zA-Z0-9_]*[.][a-zA-Z_][a-zA-Z0-9_]+$/);
60 if (pass) {
61 applicationid = value;
62 return true;
63 }
64 return '输入格式错误,请重新输入。';
65 }
66 }, {
67 type: 'input',
68 name: 'bundleIdentifier',
69 default: function () {
70 return applicationid;
71 },
72 message: "请输入iOS应用Bundle ID",
73 validate: function (value) {
74 let pass = value.match(/^[a-zA-Z_][a-zA-Z0-9_]*[.][a-zA-Z_][a-zA-Z0-9_]*[.][a-zA-Z_][a-zA-Z0-9_]+$/);
75 if (pass) {
76 return true;
77 }
78 return '输入格式错误,请重新输入。';
79 }
80 }, {
81 type: 'list',
82 name: 'release',
83 message: "请选择模板版本",
84 choices: releaseLists
85 }];
86};
87
88let runQuestions = [{
89 type: 'list',
90 name: 'platform',
91 message: '您可以安装或更新Weiui SDK',
92 choices: [{
93 name: "ios",
94 value: "ios"
95 }, {
96 name: "android",
97 value: "android"
98 }
99 ]
100}];
101
102/**
103 * 创建 weiui 工程.
104 */
105function initProject(createName) {
106 let spinFetch = ora('正在下载版本列表...');
107 spinFetch.start();
108 templateRelease.fetchReleaseVersions((err, result) => {
109 spinFetch.stop();
110 if (err) {
111 logger.error(err);
112 return;
113 }
114 //
115 let lists = [];
116 result.forEach(t => {
117 if (lists.length === 0) {
118 lists.push({
119 name: t + " (Latest)",
120 value: t
121 });
122 } else if (lists.length < 5) {
123 lists.push({
124 name: t,
125 value: t
126 });
127 }
128 });
129 //
130 if (lists.length === 0) {
131 logger.error("没有找到可用的版本。");
132 return;
133 }
134 //
135 inquirer.prompt(questions(createName, lists)).then(function (answers) {
136 let _answers = JSON.parse(JSON.stringify(answers));
137 let {name, appName, release, applicationID, bundleIdentifier} = _answers;
138 let rundir = path.resolve(process.cwd(), name);
139
140 if (fs.existsSync(name)) {
141 logger.error(`目录[${name}]已经存在。`);
142 return;
143 }
144
145 templateRelease.fetchRelease(release === 'latest' ? '' : release, function (error, releasePath) {
146 if (error) {
147 logger.error(error);
148 return;
149 }
150
151 logger.weiui("正在复制模板文件...");
152 fs.copySync(releasePath, name);
153
154 changeFile(rundir + '/platforms/android/WeexWeiui/build.gradle', 'cc.weiui.playground', applicationID);
155 changeFile(rundir + '/platforms/android/WeexWeiui/app/src/main/res/values/strings.xml', 'WeexWeiui', appName);
156
157 changeFile(rundir + '/platforms/ios/WeexWeiui/WeexWeiui.xcodeproj/project.pbxproj', 'PRODUCT_BUNDLE_IDENTIFIER = cc.weiui.playground;', 'PRODUCT_BUNDLE_IDENTIFIER = ' + bundleIdentifier + ';');
158 changeFile(rundir + '/platforms/ios/WeexWeiui/WeexWeiui/Info.plist', 'WeexWeiui', appName);
159 utils.replaceDictString(rundir + '/platforms/ios/WeexWeiui/WeexWeiui/Info.plist', 'weiuiAppName', 'weiuiApp' + replaceUpperCase(bundleIdentifier));
160
161 changeAppKey(rundir);
162
163 logger.sep();
164 logger.weiui("创建项目完成。");
165 logger.sep();
166
167 let finalLog = function () {
168 logger.weiui("您可以运行一下命令开始。");
169 logger.weiui(chalk.white(`1. cd ${name}`));
170 logger.weiui(chalk.white(`2. npm install`));
171 logger.weiui(chalk.white(`3. npm run dev`));
172 };
173
174 if (shelljs.which('pod')) {
175 let spinPod = ora('正在运行pod安装...');
176 spinPod.start();
177 shelljs.cd(rundir + '/platforms/ios/WeexWeiui');
178 shelljs.exec('pod install', {silent: true}, function (code, stdout, stderr) {
179 spinPod.stop();
180 if (code !== 0) {
181 logger.warn("运行pod安装错误:" + code + ",请稍后手动运行!");
182 }
183 finalLog();
184 });
185 } else {
186 logger.warn('未检测到系统安装pod,请安装pod后手动执行pod install!');
187 finalLog();
188 }
189 });
190 });
191 });
192}
193
194/**
195 * 列出可用的模板版本
196 */
197function displayReleases() {
198 logger.info("正在获取版本信息...");
199 templateRelease.fetchReleaseVersions((err, result) => {
200 if (err) {
201 logger.error(err);
202 return;
203 }
204 console.log("可用的版本:");
205 result.forEach(t => {
206 console.log(chalk.green.underline(t));
207 });
208 })
209}
210
211/**
212 * 替换字符串
213 * @param {string} path 文件路径.
214 * @param {string} oldText
215 * @param {string} newText
216 */
217function changeFile(path, oldText, newText) {
218 if (!fs.existsSync(path)) {
219 return;
220 }
221 let result = fs.readFileSync(path, 'utf8').replace(new RegExp(oldText, "g"), newText);
222 if (result) {
223 fs.writeFileSync(path, result, 'utf8');
224 }
225}
226
227/**
228 * 生成appKey
229 * @param {string} path 文件路径.
230 */
231function changeAppKey(path) {
232 let configPath = path + "/weiui.config.js";
233 if (!fs.existsSync(configPath)) {
234 return;
235 }
236 let config = require(configPath);
237 let content = '';
238 if (config === null || typeof config !== 'object') {
239 return;
240 }
241 if (typeof config.appKey === 'undefined') {
242 return;
243 }
244 let createRand = function (len) {
245 len = len || 32;
246 let $chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678oOLl9gqVvUuI1';
247 let maxPos = $chars.length;
248 let pwd = '';
249 for (let i = 0; i < len; i++) {
250 pwd += $chars.charAt(Math.floor(Math.random() * maxPos));
251 }
252 return pwd;
253 };
254 logger.weiui("正在创建appKey...");
255 config.appKey = createRand(32);
256 content += "/**\n * 配置文件\n * 参数详细说明:https://weiui.app/guide/config.html\n */\n";
257 content += "module.exports = ";
258 content += JSON.stringify(config, null, "\t");
259 content += ";";
260 fs.writeFileSync(configPath, content, 'utf8');
261 //
262 let androidPath = path + "/platforms/android/WeexWeiui/app/src/main/assets/weiui/config.json";
263 if (fs.existsSync(androidPath)) {
264 fs.writeFileSync(androidPath, JSON.stringify(config), 'utf8');
265 }
266 let iosPath = path + "/platforms/ios/WeexWeiui/bundlejs/weiui/config.json";
267 if (fs.existsSync(androidPath)) {
268 fs.writeFileSync(iosPath, JSON.stringify(config), 'utf8');
269 }
270}
271
272/**
273 * 将点及后面的第一个字母换成大写字母,如:aaa.bbb.ccc换成AaaBbbCcc
274 * @param string
275 * @returns {*}
276 */
277function replaceUpperCase(string) {
278 try {
279 return string.replace(/^[a-z]/g, function ($1) {
280 return $1.toLocaleUpperCase()
281 }).replace(/\.+(\w)/g, function ($1) {
282 return $1.toLocaleUpperCase()
283 }).replace(/\./g, '');
284 } catch (e) {
285 return string;
286 }
287}
288
289let args = yargs
290 .command({
291 command: "create [name]",
292 desc: "创建一个weiui项目",
293 handler: function (argv) {
294 if (typeof argv.name === "string") {
295 if (fs.existsSync(argv.name)) {
296 logger.error(`目录“${argv.name}”已经存在。`);
297 return;
298 }
299 }
300 initProject(argv.name);
301 }
302 })
303 .command({
304 command: "lists",
305 desc: "列出可用的模板版本",
306 handler: function () {
307 displayReleases();
308 }
309 })
310 .command({
311 command: "vue <pageName>",
312 desc: "创建vue页面示例模板",
313 handler: function (argv) {
314 if (typeof argv.pageName === "string" && argv.pageName) {
315 let dir = path.resolve(process.cwd(), "src");
316 if (!fs.existsSync(dir)) {
317 logger.error(`目录“src”不存在。`);
318 return;
319 }
320 let filePath = dir + "/pages/" + argv.pageName + ".vue";
321 if (fs.existsSync(filePath)) {
322 logger.error(`文件“${argv.pageName}.vue”已经存在。`);
323 return;
324 }
325 let tmlPath = __dirname + "/lib/template/_template.vue";
326 if (!fs.existsSync(tmlPath)) {
327 logger.error(`模板文件不存在。`);
328 return;
329 }
330 fs.copySync(tmlPath, filePath);
331 logger.success(`模板文件“${argv.pageName}.vue”成功创建。`);
332 }
333 }
334 })
335 .command({
336 command: "plugin <command> <name> [simple]",
337 desc: "添加、删除、创建或发布插件",
338 handler: function (argv) {
339 let op = {};
340 op.name = argv.name;
341 op.dir = path.basename(process.cwd());
342 op.simple = argv.simple === true;
343 op.platform = "all";
344 switch (argv.command) {
345 case 'add':
346 case 'install':
347 case 'i':
348 plugin.add(op);
349 break;
350 case 'remove':
351 case 'uninstall':
352 case 'un':
353 plugin.remove(op);
354 break;
355 case 'create':
356 create.create(op);
357 break;
358 case 'publish':
359 publish.publish(op);
360 break;
361 }
362 }
363 })
364 .command({
365 command: "login",
366 desc: "登录云中心",
367 handler: function () {
368 utils.login((data) => {
369 logger.weiuis(data.username + ' 登录成功!');
370 });
371 }
372 })
373 .command({
374 command: "logout",
375 desc: "登出云中心",
376 handler: function () {
377 utils.logout(() => {
378 logger.weiuis('退出成功!');
379 });
380 }
381 })
382 .command({
383 command: "backup",
384 desc: "备份项目开发文件", //(含:页面、图标、启动页、weiui.config.js)
385 handler: function () {
386 backup.backup();
387 }
388 })
389 .command({
390 command: "recovery",
391 desc: "恢复项目备份文件",
392 handler: function () {
393 backup.recovery();
394 }
395 })
396 .command({
397 command: "dev",
398 desc: "调试开发",
399 handler: function () {
400 builder.dev();
401 }
402 })
403 .command({
404 command: "build",
405 desc: "编译构造",
406 handler: function () {
407 builder.build();
408 }
409 })
410 .command({
411 command: "run [platform]",
412 desc: "在你的设备上运行app (实验功能)",
413 handler: function (argv) {
414 let dir = path.basename(process.cwd());
415 if (argv.platform === "ios") {
416 runapp.runIOS({dir});
417 } else if (argv.platform === "android") {
418 runapp.runAndroid({dir});
419 } else {
420 inquirer.prompt(runQuestions).then(function (answers) {
421 let platform = JSON.parse(JSON.stringify(answers)).platform;
422 if (platform === 'ios') {
423 runapp.runIOS({dir});
424 } else if (platform === 'android') {
425 runapp.runAndroid({dir});
426 }
427 });
428 }
429 }
430 })
431 .version(require('./package.json').version)
432 .help()
433 .alias({
434 "h": "help",
435 "v": "version",
436 "s": "simple"
437 })
438 .strict(true)
439 .demandCommand()
440 .argv;
441
442//发布模块: npm publish