├── .gitignore ├── LICENSE ├── README.md ├── bin └── sfile ├── docs └── quicksearch.png ├── lib └── index.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .idea/ 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 staticfile 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | 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, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 介绍 2 | 3 | [staticfile.org](http://staticfile.org)命令行工具 4 | 5 | # 安装 6 | 7 | ``` 8 | npm install -g sfile 9 | ``` 10 | 11 | # 使用 12 | 13 | ## 快捷搜索 14 | 15 | 快速搜索关键字 16 | 17 | ``` 18 | sfile [library] 19 | ``` 20 | 21 | ![快速搜索](https://github.com/staticfile/cli/raw/master/docs/quicksearch.png) 22 | 23 | ## 搜索 24 | 25 | 搜索关键字 26 | 27 | ``` 28 | sfile search [library] 29 | 30 | Options: 31 | -s, --ssl Output HTTPS link 32 | -h, --html Output HTML 33 | -j, --jade Output Jade Markup 34 | -n, --no-link Do not show the link for latest version 35 | ``` 36 | 37 | ## 获取链接 38 | 39 | 获取一个库的所有文件链接 40 | 41 | ``` 42 | sfile get [library] 43 | 44 | Options: 45 | -s, --ssl Output HTTPS link 46 | -h, --html Output HTML 47 | -j, --jade Output Jade Markup 48 | -v, --version Use given version, leave empty if you want to see all supported version 49 | -c, --copy Copy to your system clipboard 50 | ``` 51 | 52 | ## 查看版本 53 | 54 | ``` 55 | sfile --version 56 | ``` 57 | -------------------------------------------------------------------------------- /bin/sfile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | var sfile = require('../lib') 3 | , clip = require('cliparoo') 4 | , opt = require('optimist') 5 | , argv = opt 6 | .usage("[Usage]\n\nsfile [command|library]\n\nCommands:\n\n s, search [library]\tTo search the library...\n g, get [library]\tTo get the library assets links...") 7 | .argv; 8 | 9 | switch (argv._[0]) { 10 | case 'i': 11 | case 'info': 12 | var prettyjson = require('prettyjson') 13 | var keyword = argv._[1]; 14 | if (!keyword || argv.help) { 15 | opt.showHelp(); 16 | return; 17 | } 18 | keyword = keyword.trim(); 19 | 20 | sfile.info(keyword, function (err, data) { 21 | if (err) { 22 | return sfile.error(err); 23 | } 24 | 25 | if (data.assets) { 26 | data.assets = [data.assets[0]] 27 | } 28 | 29 | console.log(prettyjson.render(data)); 30 | }) 31 | break; 32 | case 'search': 33 | case 's': 34 | argv = opt 35 | .usage("sfile " + argv._[0] + " [library]") 36 | .alias('s', 'ssl') 37 | .alias('h', 'html') 38 | .alias('j', 'jade') 39 | .alias('n', 'no-link') 40 | .describe('s', 'Output HTTPS link') 41 | .describe('h', 'Output HTML') 42 | .describe('j', 'Output Jade Markup') 43 | .describe('n', 'Do not show the link for latest version') 44 | .argv; 45 | 46 | var keyword = argv._[1]; 47 | if (!keyword || argv.help) { 48 | opt.showHelp(); 49 | return; 50 | } 51 | keyword = keyword.trim(); 52 | 53 | sfile.search(keyword, function (err, data) { 54 | if (err) return sfile.error(err); 55 | 56 | if (!data.total) { 57 | return printLn("没有结果"); 58 | } 59 | 60 | printLn(("搜索 " + keyword.bold + " 共有 " + (data.total + "").bold + " 个库,当前列出 " + (data.libs.length + "").bold + " 个:")); 61 | printLn(""); 62 | 63 | data.libs.forEach(function (lib, index) { 64 | printLn(((index > 9 ? index : " " + index) + ")").grey + " " + lib.name.replace(keyword, keyword.bold) + " [" + lib.version.green + "]"); 65 | 66 | if (!argv.n) { 67 | var url = sfile.url("/" + lib.name + "/" + lib.version + "/" + lib.filename, argv.ssl); 68 | 69 | if (argv.html) { 70 | url = sfile.html(url); 71 | } else if (argv.jade) { 72 | url = sfile.jade(url); 73 | } 74 | 75 | printLn((" " + url).grey); 76 | } 77 | 78 | printLn(""); 79 | }); 80 | }); 81 | break; 82 | case "get": 83 | case "g": 84 | argv = opt 85 | .usage("sfile " + argv._[0] + " [library]") 86 | .alias('h', 'html') 87 | .alias('j', 'jade') 88 | .alias('s', 'ssl') 89 | .alias('c', 'copy') 90 | .alias('v', 'version') 91 | .describe('v', 'Use given version, leave empty if you want to see all supported version ') 92 | .describe('h', 'Output HTML') 93 | .describe('j', 'Output Jade Markup') 94 | .describe('s', 'Output HTTPS link') 95 | .describe('c', 'Copy to your system clipboard') 96 | .argv; 97 | 98 | var keyword = argv._[1]; 99 | if (!keyword || argv.help) { 100 | opt.showHelp(); 101 | return; 102 | } 103 | keyword = keyword.trim(); 104 | sfile.get(keyword, function (err, lib, suggest) { 105 | if (err) return sfile.error(err); 106 | 107 | if (!lib) { 108 | printLn("未找到库: " + keyword); 109 | // 搜索建议 110 | if (suggest.length > 0) { 111 | printLn(""); 112 | for (var i in suggest) { 113 | suggest[i] = suggest[i].underline; 114 | } 115 | printLn("你是不是要找: ".cyan + suggest.slice(0, 5).join(" ")); 116 | } 117 | return; 118 | } 119 | 120 | var version = (argv.version && argv.version !== true) ? argv.version : "" + lib.version; 121 | var matched = false; 122 | 123 | // 匹配package.json给出的版本 124 | lib.assets.forEach(function (asset) { 125 | if (asset.version == version) { 126 | if (matched) return; 127 | matched = asset; 128 | } 129 | }); 130 | 131 | // 未匹配容错 132 | if (!matched && lib.assets[0] && !argv.version) { 133 | matched = lib.assets[0]; 134 | } 135 | 136 | if (!matched) { 137 | printLn("未找到 " + keyword + " [" + (argv.version + "").red + "]"); 138 | } else { 139 | printLn("找到 " + lib.name.bold + " [" + version.green + "]:"); 140 | printLn(""); 141 | 142 | var urls = []; 143 | matched.files.forEach(function (file) { 144 | var path = "/" + lib.name + "/" + version + "/" + file; 145 | var url = sfile.url(path, argv.ssl); 146 | if (argv.html) { 147 | url = sfile.html(url); 148 | } else if (argv.jade) { 149 | url = sfile.jade(url); 150 | } 151 | 152 | url && printLn(url) && urls.push(url); 153 | }); 154 | 155 | // 复制到剪贴板 156 | if (argv.copy) { 157 | clip(urls.join(argv.html || argv.jade ? "\n" : "\\\\n"), function (err) { 158 | if (err) return sfile.error(err); 159 | 160 | printLn("✔ 已复制到剪贴板".green); 161 | }); 162 | } 163 | } 164 | printLn(""); 165 | if (argv.version) 166 | printLn("支持的版本号: ".cyan + lib.assets.map(function (asset) { 167 | return asset.version.underline 168 | }).join(" ")); 169 | }); 170 | break 171 | default: 172 | if (argv.version || argv.v) { 173 | var json = require("../package.json"); 174 | printLn(json.version); 175 | } else if (argv._[0]) { 176 | var List = require('term-list') 177 | , list = new List({ marker: '\033[36m› \033[0m', markerLength: 2 }) 178 | , styles = ['', 'html', 'jade'] 179 | , current_style_index = 0 180 | 181 | keyword = argv._[0].trim(); 182 | 183 | sfile.search(keyword, function (err, data) { 184 | if (err) return sfile.error(err); 185 | 186 | if (!data.total) { 187 | return printLn("没有结果"); 188 | } 189 | 190 | printLn(("搜索 " + keyword.bold + " 共有 " + (data.total + "").bold + " 个库,当前列出 " + (data.libs.length + "").bold + " 个:")); 191 | 192 | data.libs.forEach(function (lib, index) { 193 | var url = sfile.url("/" + lib.name + "/" + lib.version + "/" + lib.filename); 194 | lib.index = index; 195 | lib.base = lib.name.replace(keyword, keyword.bold) + " [" + lib.version.green + "] "; 196 | lib.url = url; 197 | lib.to_copy = url; 198 | lib.subLabel = lib.filename; 199 | lib.current = 'url'; 200 | list.add(lib, lib.base + lib.subLabel.grey); 201 | }); 202 | 203 | var changeStyle = function (reverse) { 204 | if (reverse) { 205 | current_style_index = current_style_index - 1 < 0 ? 2 : current_style_index - 1; 206 | } else { 207 | current_style_index = current_style_index + 1 > 2 ? 0 : current_style_index + 1; 208 | } 209 | var current_style = styles[current_style_index]; 210 | 211 | list.items.forEach(function (it, i) { 212 | var current = list.at(i); 213 | current.label = it.id.base + it.id.subLabel.grey + (current_style && (' [' + current_style + ']').red); 214 | current.id.to_copy = current_style ? sfile[current_style](it.id.url) : it.id.url; 215 | }); 216 | list.draw(); 217 | } 218 | 219 | list.start(); 220 | 221 | list.on("keypress", function (key, item) { 222 | switch (key.name) { 223 | case "return": 224 | clip(item.to_copy, function (err) { 225 | if (err) return sfile.error(err); 226 | 227 | printLn("✔ 已复制到剪贴板".green); 228 | }); 229 | list.stop(); 230 | break; 231 | case "left": 232 | changeStyle(true); 233 | break; 234 | case "right": 235 | changeStyle(false); 236 | break; 237 | } 238 | }); 239 | 240 | list.on('empty', function () { 241 | list.stop(); 242 | }); 243 | }); 244 | } else { 245 | opt.showHelp(); 246 | } 247 | } 248 | 249 | function printLn() { 250 | var args = Array.prototype.slice.call(arguments, 0); 251 | args[0] = " " + args[0]; 252 | console.log.apply(this, args); 253 | return true; 254 | } 255 | -------------------------------------------------------------------------------- /docs/quicksearch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staticfile/cli/4c8ee8728a0b817d187130a28df93e1a19b1405a/docs/quicksearch.png -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | var request = require('request') 2 | , colors = require('colors') 3 | , url = "http://api.staticfile.org/v1/search?count=10&q=" 4 | , show_url = "http://api.staticfile.org/v1/packages/" 5 | 6 | exports.search = function (keyword, cb) { 7 | request.get({url: url + encodeURIComponent(keyword), json: true}, function (err, response, data) { 8 | return cb(err, data); 9 | }); 10 | }; 11 | 12 | exports.get = function (keyword, cb) { 13 | request.get({url: url + encodeURIComponent(keyword), json: true}, function (err, response, data) { 14 | if (err) return cb(err); 15 | 16 | if (!data.libs) return cb(null, false); 17 | 18 | var matched_lib = false; 19 | var suggest = []; 20 | 21 | data.libs.forEach(function (lib) { 22 | if (lib.name.toLowerCase() == keyword.toLowerCase()) matched_lib = lib; 23 | suggest.push(lib.name); 24 | }); 25 | 26 | return cb(null, matched_lib, suggest); 27 | }); 28 | }; 29 | 30 | exports.info = function (keyword, cb) { 31 | request.get({url: show_url + encodeURIComponent(keyword), json: true}, function (err, response, data) { 32 | if (err) return cb(err); 33 | 34 | if (data.hasOwnProperty('success') && !data.success) return cb(new Error("Package '" + keyword + "' not exist")); 35 | 36 | return cb(null, data); 37 | }); 38 | } 39 | 40 | exports.error = function (e) { 41 | console.log("错误".redBG + " " + (e instanceof Object ? e.message : e)); 42 | }; 43 | 44 | exports.loading = function () { 45 | console.log("加载中...".grey); 46 | }; 47 | 48 | exports.html = function (file) { 49 | var ext = exports.ext(file); 50 | switch (ext) { 51 | case "js": 52 | return ''; 53 | break; 54 | case 'css': 55 | return ''; 56 | break; 57 | default: 58 | return false; 59 | } 60 | }; 61 | 62 | exports.jade = function (file) { 63 | var ext = exports.ext(file); 64 | switch (ext) { 65 | case "js": 66 | return 'script(type="text/javascript" src="' + file + '")' 67 | break; 68 | case 'css': 69 | return 'link(type="text/css" rel="stylesheet" href="' + file + '")'; 70 | break; 71 | default: 72 | return false; 73 | } 74 | }; 75 | 76 | exports.ext = function (filename) { 77 | var i = filename.lastIndexOf('.'); 78 | return (i < 0) ? '' : filename.substr(i + 1); 79 | }; 80 | 81 | exports.url = function (path, ssl) { 82 | ssl = ssl || false; 83 | 84 | return (ssl ? '//dn-staticfile.qbox.me' : 'http://cdn.staticfile.org') + path; 85 | }; 86 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sfile", 3 | "version": "0.1.2", 4 | "description": "The static library search and cli for staticfile.org.", 5 | "author": "hfcorriez ", 6 | "licenses": [ 7 | { 8 | "type": "MIT", 9 | "url": "https://github.com/staticfile/cli/blob/master/LICENSE" 10 | } 11 | ], 12 | "homepage": "http://staticfile.org", 13 | "engines": { 14 | "node": "*" 15 | }, 16 | "dependencies": { 17 | "optimist": "0.6.0", 18 | "colors": "0.6.2", 19 | "request": "2.27.0", 20 | "cliparoo": "1.0.0", 21 | "term-list": "0.2.0", 22 | "prettyjson": "~0.12.0" 23 | }, 24 | "bin": { 25 | "sfile": "bin/sfile" 26 | } 27 | } 28 | --------------------------------------------------------------------------------