├── .gitignore ├── .gitkeep ├── LICENSE ├── README.md ├── bin └── moon ├── package.json └── src └── loader.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.gitkeep: -------------------------------------------------------------------------------- 1 | template/dist 2 | template/.gitignore 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Kabir Shah (kabir.ml) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Moon Cli 2 | 3 | ## NOTE: This repo is outdated. The current source and documentation are available in [the Moon monorepo](https://github.com/kbrsh/moon/tree/master/packages/moon-cli). 4 | 5 | :sparkles: A CLI to scaffold Moon applications 6 | 7 | ### Installation 8 | 9 | Install with npm: 10 | 11 | ```sh 12 | $ npm install moon-cli -g 13 | ``` 14 | 15 | ### Getting Started 16 | 17 | Create your first project with: 18 | 19 | ```sh 20 | $ moon 21 | ``` 22 | 23 | `` is the name of your application, and Moon will proceed to create the directory and install the template there. 24 | 25 | Next, move into the directory, install the dependencies, and run a dev server! 26 | 27 | ```sh 28 | $ cd 29 | $ npm install 30 | $ npm run dev 31 | ``` 32 | 33 | ### Production 34 | 35 | To build a minified bundle, run: 36 | 37 | ```sh 38 | $ npm run build 39 | ``` 40 | 41 | All html, css, and javascript will be minified and bundled accordingly. 42 | 43 | ### License 44 | 45 | Licensed under the [MIT License](https://kbrsh.github.io/license) by [Kabir Shah](https://kabir.ml) 46 | -------------------------------------------------------------------------------- /bin/moon: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | "use strict"; 4 | 5 | var hexu = require("hexu"); 6 | var Handlebars = require("handlebars"); 7 | const download = require("download-git-repo"); 8 | var async = require("async"); 9 | var fs = require("fs"); 10 | var path = require('path'); 11 | var readline = require('readline'); 12 | var exec = require("child_process").execSync; 13 | var pkg = require("../package.json"); 14 | var load = require("../src/loader.js"); 15 | 16 | const cwd = process.cwd(); 17 | 18 | var command = process.argv.slice(2); 19 | 20 | const rl = readline.createInterface({ 21 | input: process.stdin, 22 | output: process.stdout 23 | }); 24 | 25 | load.defineRl(rl); 26 | 27 | const space = (num) => { 28 | return "\n".repeat(num); 29 | } 30 | 31 | const intro = () => { 32 | console.log(hexu.blue("======= MOON =======") + space(1)); 33 | } 34 | 35 | const help = () => { 36 | console.log(" Usage: moon [options]"); 37 | console.log(space(1)); 38 | console.log(" Commands: "); 39 | console.log(" init\tgenerates a new project"); 40 | console.log(" help\tdisplays this help message"); 41 | console.log(space(1)); 42 | console.log(" Options: "); 43 | console.log(" -h, --help\tdisplays this help message"); 44 | console.log(" -v, --version\tdisplays current Moon version"); 45 | exit(); 46 | } 47 | 48 | const version = () => { 49 | console.log(pkg.version); 50 | exit(); 51 | } 52 | 53 | const err = (msg) => { 54 | console.log(" Moon " + hexu.red("ERR") + " " + msg); 55 | exit(); 56 | } 57 | 58 | const exit = () => { 59 | rl.close(); 60 | } 61 | 62 | const sep = path.sep; 63 | let mkdirp = (dir) => { 64 | const parts = dir.split(sep); 65 | let subdir = sep; 66 | 67 | for(let i = 1; i < parts.length; i++) { 68 | subdir += parts[i] + sep; 69 | if(fs.existsSync(subdir) === false) { 70 | fs.mkdirSync(subdir); 71 | } 72 | } 73 | } 74 | 75 | const del = (dir) => { 76 | if(fs.lstatSync(dir).isFile()) { 77 | fs.unlinkSync(dir); 78 | return; 79 | } 80 | const files = fs.readdirSync(dir); 81 | for(var i = 0; i < files.length; i++) { 82 | let filePath = path.join(dir, files[i]); 83 | if(fs.existsSync(filePath)) { 84 | del(filePath); 85 | } else { 86 | fs.unlinkSync(filePath); 87 | } 88 | } 89 | } 90 | 91 | const info = (cb) => { 92 | var name = JSON.stringify(exec('git config --get user.name').toString().trim()).slice(1, -1); 93 | var answers = ask({ 94 | "Author": { 95 | def: name, 96 | key: "author" 97 | }, 98 | "Description": { 99 | def: "A Moon App", 100 | key: "description" 101 | }, 102 | "Moon Version": { 103 | def: exec("npm show moonjs version").toString().slice(0, -1), 104 | key: "version" 105 | } 106 | }, function(answers) { 107 | cb(answers); 108 | }); 109 | } 110 | 111 | const ask = (questions, cb) => { 112 | // Utility to Ask Question 113 | var prompt, answers = {}; 114 | async.eachSeries(Object.keys(questions), function(question, done) { 115 | var def = questions[question].def; 116 | if(def) { 117 | prompt = " " + hexu.green("[?]") + " " + question + hexu.grey(" (" + def + ") "); 118 | } else { 119 | prompt = " " + hexu.green("[?]") + " " + question + " "; 120 | } 121 | rl.question(prompt, (answer) => { 122 | if(!answer) answer = def; 123 | readline.moveCursor(rl, 0, -1); 124 | rl.write("\n"); 125 | readline.moveCursor(rl, 0, -2); 126 | rl.write(` ${hexu.green("[?]")} ${question} ${hexu.cyan(answer)}\n\n`); 127 | readline.moveCursor(rl, 0, -1); 128 | rl.write(" ".repeat(prompt.length) + "\n"); 129 | answers[questions[question].key] = answer; 130 | done(null); 131 | }); 132 | }, function() { 133 | cb(answers) 134 | }); 135 | } 136 | 137 | var read = function(file, cb) { 138 | fs.readFile(file, 'utf8', function(err, content) { 139 | cb(file, content); 140 | }); 141 | } 142 | 143 | const compile = (file, opts) => { 144 | return Handlebars.compile(fs.readFileSync(file).toString())(opts); 145 | } 146 | 147 | const init = (name) => { 148 | // Initialize App 149 | // Get Info 150 | info(function(opts) { 151 | // Create Loader 152 | var templateLoader = new load(hexu.blue("generating") + " template"); 153 | 154 | // Create directory 155 | const projectDir = path.join(cwd, name); 156 | mkdirp(projectDir); 157 | 158 | // Download Template 159 | const templatePath = path.join(__dirname, "/../template"); 160 | if(fs.existsSync(templatePath)) { 161 | del(templatePath); 162 | } 163 | download("KingPixil/moon-template", templatePath, () => { 164 | const configPath = path.join(templatePath, "config.json"); 165 | const config = JSON.parse(fs.readFileSync(configPath)); 166 | const files = config.files; 167 | 168 | for(var i = 0; i < files.length; i++) { 169 | let source = path.join(templatePath, files[i]); 170 | let target = path.join(projectDir, files[i]); 171 | 172 | mkdirp(path.dirname(target)); 173 | 174 | opts.name = name; 175 | fs.writeFileSync(target, compile(source, opts)); 176 | } 177 | 178 | rl.on('close', function() { 179 | console.log("\n"); 180 | console.log(`${hexu.green("success")} generated ${hexu.grey(`'${name}'`)} ✨`); 181 | console.log("\n") 182 | console.log("To Start, Run:"); 183 | console.log(hexu.grey(` cd ${name} 184 | npm install 185 | npm run dev`)); 186 | }); 187 | templateLoader.done(function() { 188 | // Close Interface when Done 189 | rl.close(); 190 | }); 191 | }); 192 | }); 193 | } 194 | 195 | intro(); 196 | switch (command[0]) { 197 | case "--help": 198 | case "help": 199 | case undefined: 200 | help(); 201 | break; 202 | case "-h": 203 | help(); 204 | break; 205 | case "-v": 206 | version(); 207 | break; 208 | case "--version": 209 | version(); 210 | break; 211 | case "init": 212 | if(command[1]) { 213 | init(command[1]); 214 | } else { 215 | err("Please provide an app name"); 216 | } 217 | break; 218 | default: 219 | err("Command Not Found"); 220 | } 221 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "moon-cli", 3 | "version": "0.1.1", 4 | "description": "Client for generating Moon applications.", 5 | "main": "bin/moon", 6 | "bin": { 7 | "moon": "./bin/moon" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/kbrsh/moon-cli.git" 12 | }, 13 | "author": "Kabir Shah", 14 | "license": "MIT", 15 | "bugs": { 16 | "url": "https://github.com/kbrsh/moon-cli/issues" 17 | }, 18 | "homepage": "https://github.com/kbrsh/moon-cli#readme", 19 | "dependencies": { 20 | "async": "^2.1.5", 21 | "download-git-repo": "^0.2.1", 22 | "handlebars": "^4.0.6", 23 | "hexu": "^1.0.0" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/loader.js: -------------------------------------------------------------------------------- 1 | var readline = require('readline'); 2 | var rl; 3 | 4 | var sequence = "⣾⣽⣻⢿⡿⣟⣯⣷".split(""); 5 | function spinner() { 6 | this.index = 0; 7 | this.current = sequence[this.index % sequence.length]; 8 | this.next = function() { 9 | this.index++; 10 | this.current = sequence[this.index % sequence.length]; 11 | } 12 | } 13 | var spin = new spinner(); 14 | function load(text, opts) { 15 | this.text = text; 16 | this.int = setInterval(function() { 17 | rl.clearLine(); 18 | readline.moveCursor(rl, 0, -1); 19 | rl.write(" \x1b[36m" + spin.current + "\x1b[0m " + text + " "); 20 | spin.next(); 21 | }, 100); 22 | } 23 | 24 | load.prototype.done = function(cb) { 25 | var self = this; 26 | setTimeout(function() { 27 | clearInterval(self.int); 28 | rl.clearLine(); 29 | readline.moveCursor(rl, 0, -1); 30 | rl.write(" \x1b[32m" + "✓" + "\x1b[0m " + self.text + " \n"); 31 | cb(); 32 | }, 1000); 33 | } 34 | // Expose loader 35 | module.exports = load; 36 | module.exports.defineRl = (instance) => { 37 | rl = instance; 38 | } 39 | --------------------------------------------------------------------------------