├── .eslintignore ├── lib ├── create │ ├── template │ │ ├── koa │ │ │ ├── models │ │ │ │ └── index.js │ │ │ ├── schema │ │ │ │ └── index.js │ │ │ ├── services │ │ │ │ └── index.js │ │ │ ├── config │ │ │ │ └── index.js │ │ │ ├── pm2.json │ │ │ ├── routes │ │ │ │ └── index.js │ │ │ ├── controllers │ │ │ │ └── index.js │ │ │ ├── app.js │ │ │ └── package.json │ │ ├── vue │ │ │ ├── .browserslistrc │ │ │ ├── postcss.config.js │ │ │ ├── babel.config.js │ │ │ ├── public │ │ │ │ ├── favicon.ico │ │ │ │ └── index.html │ │ │ ├── src │ │ │ │ ├── assets │ │ │ │ │ └── logo.png │ │ │ │ ├── views │ │ │ │ │ ├── About.vue │ │ │ │ │ └── Home.vue │ │ │ │ ├── store │ │ │ │ │ └── index.js │ │ │ │ ├── main.js │ │ │ │ ├── App.vue │ │ │ │ ├── router │ │ │ │ │ └── index.js │ │ │ │ └── components │ │ │ │ │ └── HelloWorld.vue │ │ │ ├── .gitignore │ │ │ ├── README.md │ │ │ └── package.json │ │ ├── react │ │ │ ├── public │ │ │ │ ├── robots.txt │ │ │ │ ├── favicon.ico │ │ │ │ ├── logo192.png │ │ │ │ ├── logo512.png │ │ │ │ ├── manifest.json │ │ │ │ └── index.html │ │ │ ├── src │ │ │ │ ├── App.test.js │ │ │ │ ├── App.css │ │ │ │ ├── index.css │ │ │ │ ├── index.js │ │ │ │ ├── App.js │ │ │ │ ├── serviceWorker.js │ │ │ │ └── logo.svg │ │ │ ├── .gitignore │ │ │ └── package.json │ │ └── active-page │ │ │ ├── js │ │ │ ├── index.js │ │ │ ├── rem.js │ │ │ └── zepto.min.js │ │ │ ├── styles │ │ │ ├── index.css │ │ │ └── reset.css │ │ │ └── index.html │ ├── select.js │ ├── install.js │ ├── index.js │ ├── create-active-page.js │ ├── create-koa.js │ ├── create-react.js │ ├── create-vue.js │ ├── fileServer.js │ └── verify.js ├── youdao │ ├── config.js │ ├── index.js │ └── parser.js ├── open │ └── index.js ├── regex │ ├── index.js │ └── list.js ├── day │ └── index.js ├── search │ ├── sites.js │ └── index.js ├── qrcode │ └── index.js ├── random │ └── index.js ├── fetch │ └── index.js ├── dec │ └── index.js ├── serve │ ├── tools.js │ └── index.js ├── enc │ └── index.js ├── performance │ └── index.js └── compress │ └── index.js ├── docs ├── guide │ ├── use.md │ ├── open.md │ ├── qrcode.md │ ├── random.md │ ├── install.md │ ├── fetch.md │ ├── compress.md │ ├── introduce.md │ ├── create.md │ ├── regex.md │ ├── serve.md │ ├── day.md │ ├── performance.md │ ├── search.md │ ├── dec.md │ ├── enc.md │ └── youdao.md ├── .vuepress │ ├── public │ │ ├── aes.gif │ │ ├── day.gif │ │ ├── enc.gif │ │ ├── fetch.gif │ │ ├── la-m.png │ │ ├── null.png │ │ ├── regex.gif │ │ ├── serve.gif │ │ ├── compress.gif │ │ ├── qrcode.gif │ │ ├── random.gif │ │ ├── star-m.png │ │ ├── youdao.gif │ │ ├── create-koa.gif │ │ ├── null-star.png │ │ ├── null-command.png │ │ └── performance.gif │ └── config.js └── README.md ├── .gitignore ├── .prettierrc.json ├── .editorconfig ├── test ├── random.test.js ├── regex.test.js ├── html │ ├── compress.html │ └── body.html ├── day.test.js ├── dec.test.js ├── compress.test.js ├── youdao.test.js └── enc.test.js ├── .npmignore ├── .eslintrc.js ├── utils ├── logger.js └── spinner.js ├── README.md ├── LICENSE ├── CHANGELOG.md ├── package.json └── bin └── null.js /.eslintignore: -------------------------------------------------------------------------------- 1 | *.html 2 | lib/create/template -------------------------------------------------------------------------------- /lib/create/template/koa/models/index.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/create/template/koa/schema/index.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/create/template/koa/services/index.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/create/template/vue/.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | -------------------------------------------------------------------------------- /docs/guide/use.md: -------------------------------------------------------------------------------- 1 | # 使用 2 | 3 | ![use](/null-cli/null-command.png) 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | package-lock.json 3 | docs/dist 4 | coverage 5 | .nyc_output -------------------------------------------------------------------------------- /docs/guide/open.md: -------------------------------------------------------------------------------- 1 | # 打开浏览器 2 | 3 | > 通过你的默认浏览器打开指定的 url 4 | 5 | ```shell 6 | $ null open 7 | ``` 8 | -------------------------------------------------------------------------------- /lib/create/template/react/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | -------------------------------------------------------------------------------- /docs/.vuepress/public/aes.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webfansplz/null-cli/HEAD/docs/.vuepress/public/aes.gif -------------------------------------------------------------------------------- /docs/.vuepress/public/day.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webfansplz/null-cli/HEAD/docs/.vuepress/public/day.gif -------------------------------------------------------------------------------- /docs/.vuepress/public/enc.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webfansplz/null-cli/HEAD/docs/.vuepress/public/enc.gif -------------------------------------------------------------------------------- /docs/.vuepress/public/fetch.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webfansplz/null-cli/HEAD/docs/.vuepress/public/fetch.gif -------------------------------------------------------------------------------- /docs/.vuepress/public/la-m.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webfansplz/null-cli/HEAD/docs/.vuepress/public/la-m.png -------------------------------------------------------------------------------- /docs/.vuepress/public/null.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webfansplz/null-cli/HEAD/docs/.vuepress/public/null.png -------------------------------------------------------------------------------- /docs/.vuepress/public/regex.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webfansplz/null-cli/HEAD/docs/.vuepress/public/regex.gif -------------------------------------------------------------------------------- /docs/.vuepress/public/serve.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webfansplz/null-cli/HEAD/docs/.vuepress/public/serve.gif -------------------------------------------------------------------------------- /docs/.vuepress/public/compress.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webfansplz/null-cli/HEAD/docs/.vuepress/public/compress.gif -------------------------------------------------------------------------------- /docs/.vuepress/public/qrcode.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webfansplz/null-cli/HEAD/docs/.vuepress/public/qrcode.gif -------------------------------------------------------------------------------- /docs/.vuepress/public/random.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webfansplz/null-cli/HEAD/docs/.vuepress/public/random.gif -------------------------------------------------------------------------------- /docs/.vuepress/public/star-m.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webfansplz/null-cli/HEAD/docs/.vuepress/public/star-m.png -------------------------------------------------------------------------------- /docs/.vuepress/public/youdao.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webfansplz/null-cli/HEAD/docs/.vuepress/public/youdao.gif -------------------------------------------------------------------------------- /lib/create/template/vue/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | autoprefixer: {} 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /docs/.vuepress/public/create-koa.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webfansplz/null-cli/HEAD/docs/.vuepress/public/create-koa.gif -------------------------------------------------------------------------------- /docs/.vuepress/public/null-star.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webfansplz/null-cli/HEAD/docs/.vuepress/public/null-star.png -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "semi": true, 3 | "singleQuote": true, 4 | "trailingComma": "all", 5 | "proseWrap": "never" 6 | } 7 | -------------------------------------------------------------------------------- /docs/.vuepress/public/null-command.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webfansplz/null-cli/HEAD/docs/.vuepress/public/null-command.png -------------------------------------------------------------------------------- /docs/.vuepress/public/performance.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webfansplz/null-cli/HEAD/docs/.vuepress/public/performance.gif -------------------------------------------------------------------------------- /lib/create/template/active-page/js/index.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function() { 2 | $('#content').text('Hello Active-page'); 3 | }); 4 | -------------------------------------------------------------------------------- /lib/create/template/vue/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /lib/create/template/react/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webfansplz/null-cli/HEAD/lib/create/template/react/public/favicon.ico -------------------------------------------------------------------------------- /lib/create/template/react/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webfansplz/null-cli/HEAD/lib/create/template/react/public/logo192.png -------------------------------------------------------------------------------- /lib/create/template/react/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webfansplz/null-cli/HEAD/lib/create/template/react/public/logo512.png -------------------------------------------------------------------------------- /lib/create/template/vue/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webfansplz/null-cli/HEAD/lib/create/template/vue/public/favicon.ico -------------------------------------------------------------------------------- /lib/create/template/vue/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webfansplz/null-cli/HEAD/lib/create/template/vue/src/assets/logo.png -------------------------------------------------------------------------------- /lib/create/template/vue/src/views/About.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /docs/guide/qrcode.md: -------------------------------------------------------------------------------- 1 | # 生成二维码 2 | 3 | > 生成指定 url 的二维码 4 | 5 | ```shell 6 | $ null qrcode 7 | ``` 8 | 9 | ![qrcode](/null-cli/qrcode.gif) 10 | -------------------------------------------------------------------------------- /docs/guide/random.md: -------------------------------------------------------------------------------- 1 | # 生成随机数 2 | 3 | > 生成指定长度的随机数 4 | 5 | ```shell 6 | $ null random 7 | ``` 8 | 9 | ![random](/null-cli/random.gif) 10 | -------------------------------------------------------------------------------- /lib/create/template/koa/config/index.js: -------------------------------------------------------------------------------- 1 | const config = { 2 | // host 3 | host: "localhost", 4 | // 端口 5 | port: 2222 6 | }; 7 | module.exports = config; 8 | -------------------------------------------------------------------------------- /lib/create/template/active-page/styles/index.css: -------------------------------------------------------------------------------- 1 | #content { 2 | width: 100%; 3 | height: 1rem; 4 | line-height: 1rem; 5 | font-size: 0.2rem; 6 | text-align: center; 7 | } 8 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | home: true 3 | heroImage: /null.png 4 | actionText: 开始使用 5 | actionLink: /guide/install.html 6 | 7 | footer: MIT Licensed | Copyright © 2019-present null 8 | --- 9 | -------------------------------------------------------------------------------- /docs/guide/install.md: -------------------------------------------------------------------------------- 1 | # 安装 2 | 3 | **NPM** 4 | 5 | ```shell 6 | $ npm install null-cli -g 7 | ``` 8 | 9 | **YARN** 10 | 11 | ```shell 12 | $ yarn global add null-cli 13 | ``` 14 | -------------------------------------------------------------------------------- /docs/guide/fetch.md: -------------------------------------------------------------------------------- 1 | # 网络请求 2 | 3 | > 发送 http 请求,目前只支持无头 get 请求 ~ (在命令行拼 header,body 感觉很繁琐,不如 postman 便捷) 4 | 5 | ```shell 6 | $ null fetch 7 | ``` 8 | 9 | ![fetch](/null-cli/fetch.gif) 10 | -------------------------------------------------------------------------------- /test/random.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava'); 2 | const random = require('../lib/random'); 3 | 4 | test('random api', async t => { 5 | const res = await random(16); 6 | t.deepEqual(res.length, 16); 7 | }); 8 | -------------------------------------------------------------------------------- /docs/guide/compress.md: -------------------------------------------------------------------------------- 1 | # 压缩文件 2 | 3 | > 压缩指定文件,file 文件类型可以是文件夹或者单个文件路径,文件夹路径会自动压缩该文件夹所有的 html/css/js 文件(支持文件类型 : html/css/js)。 4 | 5 | ```shell 6 | $ null compress 7 | ``` 8 | 9 | ![compress](/null-cli/compress.gif) 10 | -------------------------------------------------------------------------------- /lib/create/template/koa/pm2.json: -------------------------------------------------------------------------------- 1 | { 2 | "apps": [ 3 | { 4 | "name": "<%= projectName %>", 5 | "cwd": "./", 6 | "script": "./app.js", 7 | "watch": true, 8 | "ignore_watch": ["node_modules"] 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /lib/youdao/config.js: -------------------------------------------------------------------------------- 1 | const isChinese = require('is-chinese'); 2 | 3 | function getUrl(word) { 4 | return isChinese(word) 5 | ? 'https://dict.youdao.com/w/eng/' 6 | : 'https://dict.youdao.com/w/'; 7 | } 8 | 9 | module.exports = getUrl; 10 | -------------------------------------------------------------------------------- /test/regex.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava'); 2 | const { list } = require('../lib/regex/list'); 3 | 4 | test('regex api', t => { 5 | list.choices.forEach(({ value, example }) => { 6 | t.deepEqual(new RegExp(value).test(example), true); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /lib/create/template/vue/src/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | 4 | Vue.use(Vuex) 5 | 6 | export default new Vuex.Store({ 7 | state: { 8 | }, 9 | mutations: { 10 | }, 11 | actions: { 12 | }, 13 | modules: { 14 | } 15 | }) 16 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | 2 | # OSX 3 | .DS_Store 4 | 5 | # IDE 6 | .idea 7 | 8 | # npm 9 | node_modules 10 | yarn.lock 11 | package-lock.json 12 | 13 | # jest 14 | coverage 15 | 16 | #doc 17 | CONTRIBUTING.md 18 | docs 19 | 20 | #other 21 | .travis.yml 22 | karma.sauce.conf.js 23 | .github -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['plugin:prettier/recommended'], 3 | globals: { 4 | name: 'off', 5 | }, 6 | plugins: ['prettier'], 7 | parserOptions: { 8 | ecmaVersion: 8, 9 | }, 10 | rules: { 11 | 'prettier/prettier': 'error', 12 | }, 13 | }; 14 | -------------------------------------------------------------------------------- /lib/open/index.js: -------------------------------------------------------------------------------- 1 | const browser = require('open'); 2 | const { parse } = require('url'); 3 | 4 | async function open(url) { 5 | const { protocol } = parse(url); 6 | const website = protocol ? url : `http://${url}`; 7 | await browser(website); 8 | } 9 | module.exports = open; 10 | -------------------------------------------------------------------------------- /lib/create/template/vue/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | import router from './router' 4 | import store from './store' 5 | 6 | Vue.config.productionTip = false 7 | 8 | new Vue({ 9 | router, 10 | store, 11 | render: h => h(App) 12 | }).$mount('#app') 13 | -------------------------------------------------------------------------------- /docs/guide/introduce.md: -------------------------------------------------------------------------------- 1 | # 介绍 2 | 3 | Are you tired of repetitive work :question: 4 | 5 | Are you still looking for features in different applications :question: 6 | 7 | Please download :star2: null-cli :star2: to make it easier :exclamation: 8 | 9 | :fire: We hope ,A command makes you more efficient。 :tada: 10 | -------------------------------------------------------------------------------- /lib/create/template/react/src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | ReactDOM.unmountComponentAtNode(div); 9 | }); 10 | -------------------------------------------------------------------------------- /docs/guide/create.md: -------------------------------------------------------------------------------- 1 | # 创建模版工程 2 | 3 | ```shell 4 | $ null create 5 | ``` 6 | 7 | ![create](/null-cli/create-koa.gif) 8 | 9 | ## 参数 10 | 11 | - -f --force (Overwrite target directory if it exists) 12 | 13 | ## 模版类型 14 | 15 | v1 提供了以下 4 类基础模版 16 | 17 | - vue 18 | 19 | - react 20 | 21 | - koa 22 | 23 | - active-page 24 | -------------------------------------------------------------------------------- /lib/create/template/koa/routes/index.js: -------------------------------------------------------------------------------- 1 | const Router = require("koa-router"); 2 | const { list, create } = require("../controllers/index"); 3 | const Routers = new Router({ 4 | prefix: "/api/v1" 5 | }); 6 | /** 7 | * 接口 8 | */ 9 | Routers.get("/index", list); 10 | Routers.post("/index/create", create); 11 | 12 | module.exports = Routers; 13 | -------------------------------------------------------------------------------- /lib/create/template/vue/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | *.suo 18 | *.ntvs* 19 | *.njsproj 20 | *.sln 21 | *.sw? 22 | -------------------------------------------------------------------------------- /docs/guide/regex.md: -------------------------------------------------------------------------------- 1 | # 正则表达式 2 | 3 | > 常用正则表达式 4 | 5 | ```shell 6 | $ null regex 7 | ``` 8 | 9 | ![regex](/null-cli/regex.gif) 10 | 11 | ## 表达式列表 12 | 13 | - 纯数字 14 | 15 | - 纯汉字 16 | 17 | - 纯英文字母 18 | 19 | - 中文/英文/数字 20 | 21 | - 日期格式(例:2019-11-11) 22 | 23 | - 6-16 位数字字母组合 24 | 25 | - 邮箱地址(email) 26 | 27 | - ip 地址(v4) 28 | 29 | - 邮政编码 30 | -------------------------------------------------------------------------------- /docs/guide/serve.md: -------------------------------------------------------------------------------- 1 | # 启动 web 服务器 2 | 3 | > 指定工程启动 web 服务器 4 | 5 | ```shell 6 | null serve 7 | ``` 8 | 9 | ![serve](/null-cli/serve.gif) 10 | 11 | ## 参数 12 | 13 | | name | alias | 默认值 | 说明 | 14 | | :--: | :----: | :----: | :----------------: | 15 | | -p | --port | 8000 | 指定端口号 | 16 | | -o | --open | false | 是否自动打开浏览器 | 17 | -------------------------------------------------------------------------------- /lib/regex/index.js: -------------------------------------------------------------------------------- 1 | const inquirer = require('inquirer'); 2 | const { clearConsole } = require('../../utils/logger'); 3 | const { list } = require('./list'); 4 | 5 | async function regex() { 6 | await clearConsole(); 7 | const { action } = await inquirer.prompt([list]); 8 | console.log(`/${action}/`); 9 | return action; 10 | } 11 | 12 | module.exports = regex; 13 | -------------------------------------------------------------------------------- /lib/day/index.js: -------------------------------------------------------------------------------- 1 | const dayjs = require('dayjs'); 2 | 3 | function day(time, { type, format }) { 4 | if (type === 'string') { 5 | const res = dayjs(Number(time)).format(format); 6 | console.log(res); 7 | return res; 8 | } 9 | if (type === 'unix') { 10 | const res = dayjs(time).valueOf(); 11 | console.log(res); 12 | return res; 13 | } 14 | } 15 | module.exports = day; 16 | -------------------------------------------------------------------------------- /lib/create/template/react/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | height: 40vmin; 7 | } 8 | 9 | .App-header { 10 | background-color: #282c34; 11 | min-height: 100vh; 12 | display: flex; 13 | flex-direction: column; 14 | align-items: center; 15 | justify-content: center; 16 | font-size: calc(10px + 2vmin); 17 | color: white; 18 | } 19 | 20 | .App-link { 21 | color: #09d3ac; 22 | } 23 | -------------------------------------------------------------------------------- /lib/create/template/vue/src/views/Home.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 19 | -------------------------------------------------------------------------------- /lib/create/template/koa/controllers/index.js: -------------------------------------------------------------------------------- 1 | class Index { 2 | static list(ctx) { 3 | ctx.response.status = 200 4 | ctx.body = { 5 | code: 0, 6 | msg: 'Hello Null-cli', 7 | data: [], 8 | } 9 | } 10 | 11 | static create(ctx) { 12 | ctx.response.status = 200 13 | ctx.body = { 14 | code: 0, 15 | msg: 'Hello Null-cli', 16 | data: [], 17 | } 18 | } 19 | } 20 | module.exports = Index 21 | -------------------------------------------------------------------------------- /lib/create/template/react/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /lib/create/template/react/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", 4 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /lib/search/sites.js: -------------------------------------------------------------------------------- 1 | const google = 'https://www.google.com/search?q='; 2 | const github = 'https://github.com/search?q='; 3 | const baidu = 'https://www.baidu.com/s?wd='; 4 | const stackoverflow = 'https://stackoverflow.com/search?q='; 5 | const npm = 'https://www.npmjs.com/search?q='; 6 | const wiki = 'https://en.wikipedia.org/wiki/'; 7 | 8 | module.exports = { 9 | default: google, 10 | github, 11 | baidu, 12 | stackoverflow, 13 | npm, 14 | wiki, 15 | }; 16 | -------------------------------------------------------------------------------- /test/html/compress.html: -------------------------------------------------------------------------------- 1 |
hello,null-cli
-------------------------------------------------------------------------------- /utils/logger.js: -------------------------------------------------------------------------------- 1 | const readline = require('readline'); 2 | const chalk = require('chalk'); 3 | 4 | exports.clearConsole = () => { 5 | if (process.stdout.isTTY) { 6 | const blank = '\n'.repeat(process.stdout.rows); 7 | console.log(blank); 8 | readline.cursorTo(process.stdout, 0, 0); 9 | readline.clearScreenDown(process.stdout); 10 | const { version } = require('../package.json'); 11 | console.log(chalk.bold.blue(`🌟️ Null CLI v${version}`)); 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /lib/qrcode/index.js: -------------------------------------------------------------------------------- 1 | const chalk = require('chalk'); 2 | const QRCode = require('qrcode'); 3 | const { parse } = require('url'); 4 | 5 | function qrcode(url) { 6 | const { protocol } = parse(url); 7 | const website = protocol ? url : `http://${url}`; 8 | QRCode.toString(website, (err, str) => { 9 | if (err) { 10 | console.log(`Generate qrcode error: ${chalk.red(err)}.`); 11 | return; 12 | } 13 | console.log(str); 14 | }); 15 | } 16 | module.exports = qrcode; 17 | -------------------------------------------------------------------------------- /test/day.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const day = require('../lib/day') 3 | 4 | test('day api for string type', t => { 5 | t.deepEqual( 6 | day(1574670690000, { 7 | type: 'string', 8 | format: 'YYYY-MM-DD HH:mm:ss', 9 | }), 10 | '2019-11-25 16:31:30', 11 | ) 12 | }) 13 | 14 | test('day api for unix type', t => { 15 | t.deepEqual( 16 | day('2020-01-01 18:18:18', { 17 | type: 'unix', 18 | }), 19 | 1577873898000, 20 | ) 21 | }) 22 | -------------------------------------------------------------------------------- /docs/guide/day.md: -------------------------------------------------------------------------------- 1 | # 日期格式转换 2 | 3 | > 日期格式转换,时间戳和字符串互相转换 4 | 5 | ```shell 6 | $ null day 7 | ``` 8 | 9 | ![day](/null-cli/day.gif) 10 | 11 | ## 参数 12 | 13 | | name | alias | 默认值 | 可选值 | 14 | | :-: | :-: | :-: | :-: | 15 | | -f | --format | YYYY-MM-DD HH:mm:ss | 同 moment.js | 16 | | -t | --type | string | string(13 位时间戳->字符串),unix(字符串->13 位时间戳) | 17 | 18 | ```shell 19 | null day 1574765068684 # 2019-11-26 18:44:28 20 | 21 | null day "2020-01-01 18:18:18" -t unix # 1577873898000 22 | ``` 23 | -------------------------------------------------------------------------------- /lib/create/template/react/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import * as serviceWorker from './serviceWorker'; 6 | 7 | ReactDOM.render(, document.getElementById('root')); 8 | 9 | // If you want your app to work offline and load faster, you can change 10 | // unregister() to register() below. Note this comes with some pitfalls. 11 | // Learn more about service workers: https://bit.ly/CRA-PWA 12 | serviceWorker.unregister(); 13 | -------------------------------------------------------------------------------- /lib/search/index.js: -------------------------------------------------------------------------------- 1 | const open = require('open'); 2 | const sites = require('./sites'); 3 | 4 | async function search(keyword, options) { 5 | const keys = Object.keys(options); 6 | let froms = keys.length > 0 ? keys : ['default']; 7 | 8 | if (keys.includes('all')) { 9 | froms = Object.keys(sites); 10 | } 11 | 12 | await Promise.all( 13 | froms.map(async from => { 14 | const searchUri = `${sites[from]}${keyword}`; 15 | await open(searchUri); 16 | }), 17 | ); 18 | } 19 | 20 | module.exports = search; 21 | -------------------------------------------------------------------------------- /lib/create/template/active-page/js/rem.js: -------------------------------------------------------------------------------- 1 | (function(doc, win) { 2 | var docEl = doc.documentElement; 3 | var resizeEvt = 4 | 'orientationchange' in window ? 'orientationchange' : 'resize'; 5 | var recalc = function() { 6 | var ele = docEl.getBoundingClientRect(); 7 | if (!ele.width) return; 8 | docEl.style.fontSize = 100 * (ele.width / 375) + 'px'; 9 | }; 10 | if (!doc.addEventListener) return; 11 | win.addEventListener(resizeEvt, recalc, false); 12 | doc.addEventListener('DOMContentLoaded', recalc, false); 13 | })(document, window); 14 | -------------------------------------------------------------------------------- /lib/random/index.js: -------------------------------------------------------------------------------- 1 | const chalk = require('chalk'); 2 | const crypto = require('crypto'); 3 | 4 | async function random(len) { 5 | if (!/^[+]{0,1}(\d+)$/.test(len)) { 6 | console.log(`Not a valid length ${chalk.yellow(len)}.`); 7 | return; 8 | } 9 | const buf = crypto.randomBytes(Number(len)); 10 | const res = buf.toString('hex'); 11 | const start = Math.floor(Math.random() * (res.length / 2)); 12 | console.log(res.slice(start, start + Number(len))); 13 | return res.slice(start, start + Number(len)); 14 | } 15 | module.exports = random; 16 | -------------------------------------------------------------------------------- /lib/create/template/vue/README.md: -------------------------------------------------------------------------------- 1 | # <%= projectName %> 2 | 3 | ## Project setup 4 | 5 | ``` 6 | npm install 7 | ``` 8 | 9 | ### Compiles and hot-reloads for development 10 | 11 | ``` 12 | npm run serve 13 | ``` 14 | 15 | ### Compiles and minifies for production 16 | 17 | ``` 18 | npm run build 19 | ``` 20 | 21 | ### Run your tests 22 | 23 | ``` 24 | npm run test 25 | ``` 26 | 27 | ### Lints and fixes files 28 | 29 | ``` 30 | npm run lint 31 | ``` 32 | 33 | ### Customize configuration 34 | 35 | See [Configuration Reference](https://cli.vuejs.org/config/). 36 | -------------------------------------------------------------------------------- /lib/create/template/vue/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "<%= projectName %>", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build" 8 | }, 9 | "dependencies": { 10 | "core-js": "^3.3.2", 11 | "vue": "^2.6.10", 12 | "vue-router": "^3.1.3", 13 | "vuex": "^3.0.1" 14 | }, 15 | "devDependencies": { 16 | "@vue/cli-plugin-babel": "^4.0.0", 17 | "@vue/cli-service": "^4.0.0", 18 | "less": "^3.0.4", 19 | "less-loader": "^5.0.0", 20 | "vue-template-compiler": "^2.6.10" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lib/create/template/react/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /lib/create/select.js: -------------------------------------------------------------------------------- 1 | const inquirer = require('inquirer'); 2 | const { clearConsole } = require('../../utils/logger'); 3 | 4 | async function select() { 5 | await clearConsole(); 6 | const { action } = await inquirer.prompt([ 7 | { 8 | name: 'action', 9 | type: 'list', 10 | message: '📄 Please select a template you want to generate', 11 | choices: [ 12 | { name: 'vue', value: 'vue' }, 13 | { name: 'react', value: 'react' }, 14 | { name: 'koa', value: 'koa' }, 15 | { name: 'active-page', value: 'activePage' }, 16 | ], 17 | }, 18 | ]); 19 | return action; 20 | } 21 | 22 | module.exports = select; 23 | -------------------------------------------------------------------------------- /lib/create/install.js: -------------------------------------------------------------------------------- 1 | const execa = require('execa'); 2 | 3 | function install(cwd) { 4 | const command = 'npm'; 5 | const args = [ 6 | 'install', 7 | '--loglevel', 8 | 'error', 9 | '--registry', 10 | 'https://registry.npm.taobao.org', 11 | ]; 12 | return new Promise((resolve, reject) => { 13 | const child = execa(command, args, { 14 | cwd, 15 | stdio: ['inherit', 'inherit', 'inherit'], 16 | }); 17 | child.on('close', code => { 18 | if (code !== 0) { 19 | reject(`command failed: ${command} ${args.join(' ')}`); 20 | return; 21 | } 22 | resolve(); 23 | }); 24 | }); 25 | } 26 | 27 | module.exports = install; 28 | -------------------------------------------------------------------------------- /lib/create/template/react/src/App.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import logo from './logo.svg'; 3 | import './App.css'; 4 | 5 | function App() { 6 | return ( 7 |
8 |
9 | logo 10 |

11 | Edit src/App.js and save to reload. 12 |

13 | 19 | Learn React 20 | 21 |
22 |
23 | ); 24 | } 25 | 26 | export default App; 27 | -------------------------------------------------------------------------------- /test/dec.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const dec = require('../lib/dec') 3 | 4 | test('dec api for base64', t => { 5 | t.deepEqual( 6 | dec('aGVsbG8td29ybGQ=', { 7 | method: 'base64', 8 | }), 9 | 'hello-world', 10 | ) 11 | }) 12 | 13 | test('dec api for hex', t => { 14 | t.deepEqual( 15 | dec('68656c6c6f2d776f726c64', { 16 | method: 'hex', 17 | }), 18 | 'hello-world', 19 | ) 20 | }) 21 | 22 | test('dec api for aes', t => { 23 | t.deepEqual( 24 | dec('cea47c666b605fdb0fd23223476d4ed7', { 25 | method: 'aes', 26 | key: '20201111nullbest', 27 | iv: 'webbestlangworld', 28 | }), 29 | 'hello-world', 30 | ) 31 | }) 32 | -------------------------------------------------------------------------------- /lib/create/template/vue/src/App.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 33 | -------------------------------------------------------------------------------- /lib/create/template/vue/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | <%= projectName %> 9 | 10 | 11 | 17 |
18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /lib/create/index.js: -------------------------------------------------------------------------------- 1 | const verify = require('./verify'); 2 | const select = require('./select'); 3 | const createVue = require('./create-vue'); 4 | const createReact = require('./create-react'); 5 | const createKoa = require('./create-koa'); 6 | const createActivePage = require('./create-active-page'); 7 | 8 | async function create(name, options) { 9 | const result = await verify.start(name, options); 10 | if (!result) return false; 11 | const template = await select(); 12 | const task = { 13 | vue: createVue, 14 | react: createReact, 15 | koa: createKoa, 16 | activePage: createActivePage, 17 | }[template]; 18 | await task(result.name, result.context); 19 | } 20 | 21 | module.exports = (...args) => create(...args); 22 | -------------------------------------------------------------------------------- /lib/fetch/index.js: -------------------------------------------------------------------------------- 1 | const chalk = require('chalk'); 2 | const request = require('request'); 3 | const { logWithSpinner, stopSpinner } = require('../../utils/spinner'); 4 | 5 | function fetch(url) { 6 | logWithSpinner('Requesting...'); 7 | request( 8 | { 9 | url, 10 | method: 'get', 11 | }, 12 | (err, res) => { 13 | stopSpinner('Request finish'); 14 | if (err) { 15 | console.log(`Http request ${chalk.red(err)}.`); 16 | return; 17 | } 18 | if (res.statusCode === 200) { 19 | console.log(JSON.parse(res.body)); 20 | } else { 21 | console.log(`Http request Error : ${chalk.red(res.statusCode)}.`); 22 | } 23 | }, 24 | ); 25 | } 26 | 27 | module.exports = fetch; 28 | -------------------------------------------------------------------------------- /lib/create/template/vue/src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import VueRouter from 'vue-router' 3 | import Home from '../views/Home.vue' 4 | 5 | Vue.use(VueRouter) 6 | 7 | const routes = [ 8 | { 9 | path: '/', 10 | name: 'home', 11 | component: Home 12 | }, 13 | { 14 | path: '/about', 15 | name: 'about', 16 | // route level code-splitting 17 | // this generates a separate chunk (about.[hash].js) for this route 18 | // which is lazy-loaded when the route is visited. 19 | component: () => import(/* webpackChunkName: "about" */ '../views/About.vue') 20 | } 21 | ] 22 | 23 | const router = new VueRouter({ 24 | mode: 'history', 25 | base: process.env.BASE_URL, 26 | routes 27 | }) 28 | 29 | export default router 30 | -------------------------------------------------------------------------------- /lib/create/template/react/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "<%= projectName %>", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "react": "^16.12.0", 7 | "react-dom": "^16.12.0", 8 | "react-scripts": "3.2.0" 9 | }, 10 | "scripts": { 11 | "start": "react-scripts start", 12 | "build": "react-scripts build", 13 | "test": "react-scripts test", 14 | "eject": "react-scripts eject" 15 | }, 16 | "eslintConfig": { 17 | "extends": "react-app" 18 | }, 19 | "browserslist": { 20 | "production": [ 21 | ">0.2%", 22 | "not dead", 23 | "not op_mini all" 24 | ], 25 | "development": [ 26 | "last 1 chrome version", 27 | "last 1 firefox version", 28 | "last 1 safari version" 29 | ] 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /docs/guide/performance.md: -------------------------------------------------------------------------------- 1 | # 性能分析 2 | 3 | > 通过 PerformanceTiming API 获取与浏览器性能有关的时间数据,分析 web 前端性能 4 | 5 | ```shell 6 | $ null perf 7 | ``` 8 | 9 | ## 性能指标 10 | 11 | | name | value | 12 | | :------------: | :----------------------------------------: | 13 | | DNS 查询耗时 | domainLookupEnd - domainLookupStart | 14 | | TCP 连接耗时 | connectEnd - connectStart | 15 | | 页面请求耗时 | responseEnd - responseStart | 16 | | 白屏耗时 | responseStart - navigationStart | 17 | | DOM 解析耗时 | domComplete - domInteractive | 18 | | DOM Ready 耗时 | domContentLoadedEventEnd - navigationStart | 19 | | 页面加载总耗时 | loadEventEnd - navigationStart | 20 | 21 | ![performance](/null-cli/performance.gif) 22 | -------------------------------------------------------------------------------- /lib/create/template/koa/app.js: -------------------------------------------------------------------------------- 1 | const Koa = require("koa"); 2 | const app = new Koa(); 3 | const bodyParser = require("koa-bodyparser"); 4 | const onerror = require("koa-onerror"); 5 | const logger = require("koa-logger"); 6 | const cors = require("koa-cors"); 7 | const json = require("koa-json"); 8 | const Routers = require("./routes/index"); 9 | const config = require("./config/index"); 10 | 11 | // cors 12 | app.use(cors()); 13 | 14 | //error handler 15 | onerror(app); 16 | 17 | app.use( 18 | bodyParser({ 19 | formLimit: "1mb" 20 | }) 21 | ); 22 | 23 | //JSON response 24 | app.use(json()); 25 | 26 | //logger 27 | app.use(logger()); 28 | 29 | //路由 30 | app.use(Routers.routes()); 31 | 32 | app.listen(config.port); 33 | 34 | console.log(`🚀 server listen on ${config.host}:${config.port}`); 35 | -------------------------------------------------------------------------------- /lib/create/template/active-page/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 11 | 12 | 13 | <%= projectName %> 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /lib/create/template/koa/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "<%= projectName %>", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "cross-env NODE_ENV=development nodemon ./app.js", 8 | "server": "cross-env NODE_ENV=production pm2 start ./pm2.json" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC", 13 | "dependencies": { 14 | "koa": "^2.11.0", 15 | "koa-bodyparser": "^4.2.1", 16 | "koa-convert": "^1.2.0", 17 | "koa-cors": "0.0.16", 18 | "koa-json": "^2.0.2", 19 | "koa-jwt": "^3.6.0", 20 | "koa-logger": "^3.2.1", 21 | "koa-onerror": "^4.1.0", 22 | "koa-router": "^7.4.0", 23 | "koa-static": "^5.0.0" 24 | }, 25 | "devDependencies": { 26 | "cross-env": "^6.0.3", 27 | "nodemon": "^2.0.1" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /docs/guide/search.md: -------------------------------------------------------------------------------- 1 | # 快捷搜索 2 | 3 | > 通过默认浏览器快捷搜索, 默认使用Google, 支持多网址同时打开 4 | 5 | ```shell 6 | $ null search // search by google 7 | $ null search -g -n // search by github & npm 8 | $ null search -a // search by all sites(npm, google, stackoverflow, wiki, baidu, github) 9 | ``` 10 | 11 | ## 参数 12 | 13 | | name | alias | describe | 14 | | :--: | :-------------: | :---------------------: | 15 | | -d | --default | search by google | 16 | | -n | --npm | search by npm | 17 | | -s | --stackoverflow | search by stackoverflow | 18 | | -w | --wiki | search by wiki | 19 | | -b | --baidu | search by baidu | 20 | | -g | --github | search by github | 21 | | -a | --all | search by all site | 22 | 23 | 24 | -------------------------------------------------------------------------------- /docs/guide/dec.md: -------------------------------------------------------------------------------- 1 | # 字符串解码/AES 解密 2 | 3 | ```shell 4 | null dec 5 | ``` 6 | 7 | ![enc](/null-cli/enc.gif) 8 | 9 | ![aes](/null-cli/aes.gif) 10 | 11 | ## 字符串解码 参数 12 | 13 | | name | alias | 默认值 | 可选值 | 14 | | :--: | :------: | :----: | :--------: | 15 | | -m | --method | base64 | base64,hex | 16 | 17 | ```shell 18 | 19 | null dec bnVsbC1jbGk= # null-cli 20 | 21 | null dec 6e756c6c2d636c69 -m hex # null-cli 22 | 23 | ``` 24 | 25 | ## AES 解密 参数 26 | 27 | | name | alias | 默认值 | 可选值 | 28 | | :--: | :------: | :--------------: | :------------: | 29 | | -m | --method | base64 | aes | 30 | | -k | --key | 20201111nullbest | 任意 16 位字符 | 31 | | -i | --iv | webbestlangworld | 任意 16 位字符 | 32 | 33 | ```shell 34 | null dec b425ed8b1698de56aed3d1089ade239d -m aes # null-cli 35 | ``` 36 | -------------------------------------------------------------------------------- /test/compress.test.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const test = require('ava'); 3 | const path = require('path'); 4 | const compress = require('../lib/compress'); 5 | 6 | test('compress api for html', async t => { 7 | const filepath = path.join(__dirname, './html/compress.html'); 8 | const body = fs.readFileSync(filepath); 9 | console.log(body); 10 | const res = '
hello,null-cli
'; 11 | t.deepEqual(await compress(filepath), res); 12 | }); 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

4 | 5 |

A command makes you more efficient

6 | 7 | ## Getting Started 8 | 9 | ### Installation 10 | 11 | ```shell 12 | npm install null-cli -g 13 | # OR 14 | yarn global add null-cli 15 | ``` 16 | 17 | ### API 18 | 19 | ![api](https://raw.githubusercontent.com/webfansplz/null-cli/master/docs/.vuepress/public/null-command.png) 20 | 21 | ### Documentation 22 | 23 | 📚[Docs Guide](https://webfansplz.github.io/null-cli/) 24 | 25 | # License 26 | 27 | null-cli licensed under a [Mit License](./LICENSE). 28 | -------------------------------------------------------------------------------- /test/youdao.test.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const test = require('ava') 3 | const path = require('path') 4 | const getUrl = require('../lib/youdao/config') 5 | const Parser = require('../lib/youdao/parser') 6 | 7 | test('youdao api for getUrl', t => { 8 | t.deepEqual(getUrl('曼巴'), 'https://dict.youdao.com/w/eng/') 9 | t.deepEqual(getUrl('mamba'), 'https://dict.youdao.com/w/') 10 | }) 11 | 12 | test('youdao api for parser', t => { 13 | const body = fs.readFileSync(path.join(__dirname, './html/body.html')) 14 | console.log(body) 15 | const res = '英 [həˈləʊ] 美 [helˈō] \n\nint. 喂;哈罗\nn. 表示问候, 惊奇或唤起注意时的用语\nn. (Hello)人名;(法)埃洛\n\nHello, who\'s speaking, please?\n喂,请问你是谁呀?\nThe American walked to a telephone booth,"Hello. Is that the bank?\n那个美国人走到公用电话间旁打电话:"喂,银行吗?\nShe never passes without stopping to say hello.\n她从这儿经过时没有一次不停下来问候一番。\n' 16 | t.deepEqual(Parser.parse(false, body), res) 17 | }) 18 | -------------------------------------------------------------------------------- /lib/youdao/index.js: -------------------------------------------------------------------------------- 1 | const request = require('request'); 2 | const chalk = require('chalk'); 3 | const noCase = require('no-case'); 4 | const urlencode = require('urlencode'); 5 | const isChinese = require('is-chinese'); 6 | const Parser = require('./parser'); 7 | const { logWithSpinner, stopSpinner } = require('../../utils/spinner'); 8 | const getUrl = require('./config'); 9 | 10 | function youdao(word) { 11 | const keyword = isChinese(word) ? word : noCase(word); 12 | logWithSpinner('正在翻译中...'); 13 | request( 14 | { 15 | url: getUrl(keyword) + urlencode(keyword), 16 | }, 17 | (error, _, body) => { 18 | if (error) { 19 | stopSpinner('翻译出错'); 20 | console.log(`Translate word : ${chalk.red(error)}.`); 21 | return false; 22 | } 23 | stopSpinner('翻译完成'); 24 | console.log(Parser.parse(isChinese(word), body)); 25 | }, 26 | ); 27 | } 28 | 29 | module.exports = youdao; 30 | -------------------------------------------------------------------------------- /lib/dec/index.js: -------------------------------------------------------------------------------- 1 | const CryptoJS = require('crypto-js'); 2 | const chalk = require('chalk'); 3 | 4 | const methods = { 5 | base64: base64 => 6 | CryptoJS.enc.Base64.parse(base64).toString(CryptoJS.enc.Utf8), 7 | hex: hex => CryptoJS.enc.Hex.parse(hex).toString(CryptoJS.enc.Utf8), 8 | aes: (str, aeskey, aesiv) => { 9 | const key = CryptoJS.enc.Utf8.parse(aeskey); 10 | const iv = CryptoJS.enc.Utf8.parse(aesiv); 11 | const srcs = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Hex.parse(str)); 12 | const decrypt = CryptoJS.AES.decrypt(srcs, key, { 13 | iv, 14 | }).toString(CryptoJS.enc.Utf8); 15 | return decrypt.toString(); 16 | }, 17 | }; 18 | function dec(name, { method, key, iv }) { 19 | if (!methods[method]) { 20 | console.log(`Unknown option method ${chalk.yellow(method)}.`); 21 | return; 22 | } 23 | console.log(methods[method](name, key, iv)); 24 | return methods[method](name, key, iv); 25 | } 26 | module.exports = dec; 27 | -------------------------------------------------------------------------------- /lib/serve/tools.js: -------------------------------------------------------------------------------- 1 | const url = require('url'); 2 | const chalk = require('chalk'); 3 | const address = require('address'); 4 | const portfinder = require('portfinder'); 5 | const defaultGateway = require('default-gateway'); 6 | 7 | module.exports = { 8 | getPort(port) { 9 | return new Promise(resolve => { 10 | portfinder 11 | .getPortPromise({ 12 | port, 13 | }) 14 | .then(res => { 15 | resolve(res); 16 | }) 17 | .catch(err => { 18 | console.log(`getPort failed ${chalk.red(err)}.`); 19 | console.log(err); 20 | }); 21 | }); 22 | }, 23 | parseUrl(hostname, port, bold = true, pathname = '/') { 24 | return url.format({ 25 | protocol: 'http', 26 | hostname, 27 | port: bold ? chalk.bold(port) : port, 28 | pathname, 29 | }); 30 | }, 31 | getIp() { 32 | const result = defaultGateway.v4.sync(); 33 | return address.ip(result && result.interface); 34 | }, 35 | }; 36 | -------------------------------------------------------------------------------- /lib/serve/index.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const browser = require('open'); 3 | const chalk = require('chalk'); 4 | const express = require('express'); 5 | const { getPort, getIp, parseUrl } = require('./tools'); 6 | 7 | const app = express(); 8 | 9 | async function serve(target, { port, open }) { 10 | const serverPort = await getPort(port); 11 | const inCurrent = target === '.'; 12 | const name = inCurrent ? process.cwd() : target; 13 | const cwd = path.isAbsolute(name) ? name : path.join(process.cwd(), name); 14 | app.use(express.static(cwd)); 15 | app.listen(serverPort, async () => { 16 | console.log(); 17 | console.log(' 🎉 App running at:'); 18 | console.log( 19 | ` - Local: ${chalk.cyan(parseUrl('localhost', serverPort))}`, 20 | ); 21 | console.log(` - Network: ${chalk.cyan(parseUrl(getIp(), serverPort))}`); 22 | if (open) { 23 | await browser(parseUrl('localhost', serverPort, false)); 24 | } 25 | }); 26 | } 27 | 28 | module.exports = serve; 29 | -------------------------------------------------------------------------------- /lib/create/create-active-page.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const chalk = require('chalk'); 3 | const fileServer = require('./fileServer'); 4 | const { clearConsole } = require('../../utils/logger'); 5 | 6 | async function createActivePage(name, context) { 7 | await clearConsole(); 8 | console.log('✨', `Creating project in ${chalk.yellow(context)}.`); 9 | const templatePath = path.join(__dirname, './template/active-page'); 10 | console.log('🚀 Invoking generators...'); 11 | const files = await fileServer.read(templatePath, { 12 | list: ['index.html'], 13 | options: { 14 | projectName: name, 15 | }, 16 | }); 17 | fileServer.write(context, files); 18 | console.log(`🎉 Successfully created project ${chalk.yellow(name)}.`); 19 | console.log( 20 | `👉 Get started with the following commands:\n\n${ 21 | context === process.cwd() 22 | ? '' 23 | : chalk.cyan(` ${chalk.gray('$')} cd ${name}\n`) 24 | }${chalk.cyan(` ${chalk.gray('$')} ${'open index.html'}`)}`, 25 | ); 26 | } 27 | module.exports = createActivePage; 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 null 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 | -------------------------------------------------------------------------------- /docs/guide/enc.md: -------------------------------------------------------------------------------- 1 | # 字符串编码/AES 加密 2 | 3 | ```shell 4 | null enc 5 | ``` 6 | 7 | ![enc](/null-cli/enc.gif) 8 | 9 | ![aes](/null-cli/aes.gif) 10 | 11 | ## 字符串编码 参数 12 | 13 | | name | alias | 默认值 | 可选值 | 14 | | :--: | :------: | :----: | :---------------------------------------------: | 15 | | -m | --method | base64 | sha1,sha224,sha256,sha384,sha512,md5,base64,hex | 16 | 17 | ```shell 18 | null enc null-cli # bnVsbC1jbGk= 19 | 20 | null enc null-cli -m sha1 # a0071acf7a33712783545db8b4a7a89f0a35013d 21 | 22 | null enc null-cli -m sha256 # fe8f4fa399ff4888b4d393c8dd09ba35385db71e12d627d83cc65d89ba83fc9b 23 | 24 | null enc null-cli -m md5 # 91732209f7c84dd6119c81fd8b1a9669 25 | ``` 26 | 27 | ## AES 加密 参数 28 | 29 | | name | alias | 默认值 | 可选值 | 30 | | :--: | :------: | :--------------: | :------------: | 31 | | -m | --method | base64 | aes | 32 | | -k | --key | 20201111nullbest | 任意 16 位字符 | 33 | | -i | --iv | webbestlangworld | 任意 16 位字符 | 34 | 35 | ```shell 36 | null enc null-cli -m aes # b425ed8b1698de56aed3d1089ade239d 37 | ``` 38 | -------------------------------------------------------------------------------- /docs/guide/youdao.md: -------------------------------------------------------------------------------- 1 | # 有道翻译 2 | 3 | > 支持中英文翻译,根据传入的 word 自动识别中英文 4 | 5 | ```shell 6 | null youdao 7 | ``` 8 | 9 | ![youdao](/null-cli/youdao.gif) 10 | 11 | ```js 12 | 13 | null youdao frontend 14 | /** 15 | 16 | Frontend workflows are a different thing than backend workflows. 17 | 18 | 前端工作流不同于后端工作流。 19 | 20 | The user's client (frontend) application that wants to perform database operations. 21 | 22 | 那些需要执行数据库操作的用户的客户端(前端)应用。 23 | 24 | The design of the classes are done in such a way that they have no relationship with, or dependency on, the frontend design or platform. 25 | 26 | 设计这些类的方式使得它们不依赖于前端设计或平台。 27 | 28 | 29 | 30 | n. 前端 31 | 32 | Frontend workflows are a different thing than backend workflows. 33 | 前端工作流不同于后端工作流。 34 | The user's client (frontend) application that wants to perform database operations. 35 | 那些需要执行数据库操作的用户的客户端(前端)应用。 36 | The design of the classes are done in such a way that they have no relationship with, or dependency on, the frontend design or platform. 37 | 设计这些类的方式使得它们不依赖于前端设计或平台。 38 | **/ 39 | ``` 40 | 41 | ## 声明 42 | 43 | 这个 功能 借鉴了 [https://github.com/kenshinji/yddict](https://github.com/kenshinji/yddict)的实现。 44 | -------------------------------------------------------------------------------- /lib/enc/index.js: -------------------------------------------------------------------------------- 1 | const CryptoJS = require('crypto-js'); 2 | const chalk = require('chalk'); 3 | 4 | const methods = { 5 | sha1: str => require('crypto-js/sha1')(str).toString(), 6 | sha224: str => require('crypto-js/sha224')(str).toString(), 7 | sha256: str => require('crypto-js/sha256')(str).toString(), 8 | sha384: str => require('crypto-js/sha384')(str).toString(), 9 | sha512: str => require('crypto-js/sha512')(str).toString(), 10 | md5: str => require('crypto-js/md5')(str).toString(), 11 | base64: str => CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(str)), 12 | hex: str => CryptoJS.enc.Hex.stringify(CryptoJS.enc.Utf8.parse(str)), 13 | aes: (str, aeskey, aesiv) => { 14 | const key = CryptoJS.enc.Utf8.parse(aeskey); 15 | const iv = CryptoJS.enc.Utf8.parse(aesiv); 16 | return CryptoJS.AES.encrypt(str, key, { iv }).ciphertext.toString(); 17 | }, 18 | }; 19 | function enc(name, { method, key, iv }) { 20 | if (!methods[method]) { 21 | console.log(`Unknown option method ${chalk.yellow(method)}.`); 22 | return; 23 | } 24 | console.log(methods[method](name, key, iv)); 25 | return methods[method](name, key, iv); 26 | } 27 | module.exports = enc; 28 | -------------------------------------------------------------------------------- /lib/create/create-koa.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const chalk = require('chalk'); 3 | const install = require('./install'); 4 | const fileServer = require('./fileServer'); 5 | const { clearConsole } = require('../../utils/logger'); 6 | 7 | async function createKoa(name, context) { 8 | await clearConsole(); 9 | console.log('✨', `Creating project in ${chalk.yellow(context)}.`); 10 | const templatePath = path.join(__dirname, './template/koa'); 11 | console.log('🚀 Invoking generators...'); 12 | const files = await fileServer.read(templatePath, { 13 | list: ['package.json', 'pm2.json'], 14 | options: { 15 | projectName: name, 16 | }, 17 | }); 18 | fileServer.write(context, files); 19 | console.log('📦 Installing additional dependencies...'); 20 | await install(context); 21 | console.log(`🎉 Successfully created project ${chalk.yellow(name)}.`); 22 | console.log( 23 | `👉 Get started with the following commands:\n\n${ 24 | context === process.cwd() 25 | ? '' 26 | : chalk.cyan(` ${chalk.gray('$')} cd ${name}\n`) 27 | }${chalk.cyan(` ${chalk.gray('$')} ${'npm run start'}`)}`, 28 | ); 29 | } 30 | module.exports = createKoa; 31 | -------------------------------------------------------------------------------- /lib/create/create-react.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const chalk = require('chalk'); 3 | const install = require('./install'); 4 | const fileServer = require('./fileServer'); 5 | 6 | const { clearConsole } = require('../../utils/logger'); 7 | 8 | async function createVue(name, context) { 9 | await clearConsole(); 10 | console.log('✨', `Creating project in ${chalk.yellow(context)}.`); 11 | const templatePath = path.join(__dirname, './template/react'); 12 | console.log('🚀 Invoking generators...'); 13 | const files = await fileServer.read(templatePath, { 14 | list: ['package.json', 'public/index.html'], 15 | options: { 16 | projectName: name, 17 | }, 18 | }); 19 | fileServer.write(context, files); 20 | console.log('📦 Installing additional dependencies...'); 21 | await install(context); 22 | console.log(`🎉 Successfully created project ${chalk.yellow(name)}.`); 23 | console.log( 24 | `👉 Get started with the following commands:\n\n${ 25 | context === process.cwd() 26 | ? '' 27 | : chalk.cyan(` ${chalk.gray('$')} cd ${name}\n`) 28 | }${chalk.cyan(` ${chalk.gray('$')} ${'npm run start'}`)}`, 29 | ); 30 | } 31 | module.exports = createVue; 32 | -------------------------------------------------------------------------------- /utils/spinner.js: -------------------------------------------------------------------------------- 1 | const ora = require('ora'); 2 | const chalk = require('chalk'); 3 | 4 | const spinner = ora(); 5 | let lastMsg = null; 6 | let isPaused = false; 7 | 8 | exports.logWithSpinner = (symbol, msg) => { 9 | if (!msg) { 10 | msg = symbol; 11 | symbol = chalk.green('✔'); 12 | } 13 | if (lastMsg) { 14 | spinner.stopAndPersist({ 15 | symbol: lastMsg.symbol, 16 | text: lastMsg.text, 17 | }); 18 | } 19 | spinner.text = ` ${msg}`; 20 | lastMsg = { 21 | symbol: `${symbol} `, 22 | text: msg, 23 | }; 24 | spinner.start(); 25 | }; 26 | 27 | exports.stopSpinner = persist => { 28 | if (lastMsg && persist !== false) { 29 | spinner.stopAndPersist({ 30 | symbol: lastMsg.symbol, 31 | text: persist || lastMsg.text, 32 | }); 33 | } else { 34 | spinner.stop(); 35 | } 36 | lastMsg = null; 37 | }; 38 | 39 | exports.pauseSpinner = () => { 40 | if (spinner.isSpinning) { 41 | spinner.stop(); 42 | isPaused = true; 43 | } 44 | }; 45 | 46 | exports.resumeSpinner = () => { 47 | if (isPaused) { 48 | spinner.start(); 49 | isPaused = false; 50 | } 51 | }; 52 | 53 | exports.failSpinner = text => { 54 | spinner.fail(text); 55 | }; 56 | -------------------------------------------------------------------------------- /lib/create/create-vue.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const chalk = require('chalk'); 3 | const install = require('./install'); 4 | const fileServer = require('./fileServer'); 5 | 6 | const { clearConsole } = require('../../utils/logger'); 7 | 8 | async function createVue(name, context) { 9 | await clearConsole(); 10 | console.log('✨', `Creating project in ${chalk.yellow(context)}.`); 11 | const templatePath = path.join(__dirname, './template/vue'); 12 | console.log('🚀 Invoking generators...'); 13 | const files = await fileServer.read(templatePath, { 14 | list: ['README.md', 'package.json', 'public/index.html'], 15 | options: { 16 | projectName: name, 17 | }, 18 | }); 19 | fileServer.write(context, files); 20 | console.log('📦 Installing additional dependencies...'); 21 | await install(context); 22 | console.log(`🎉 Successfully created project ${chalk.yellow(name)}.`); 23 | console.log( 24 | `👉 Get started with the following commands:\n\n${ 25 | context === process.cwd() 26 | ? '' 27 | : chalk.cyan(` ${chalk.gray('$')} cd ${name}\n`) 28 | }${chalk.cyan(` ${chalk.gray('$')} ${'npm run serve'}`)}`, 29 | ); 30 | } 31 | module.exports = createVue; 32 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 1.0.4 (2020-01-13) 2 | 3 | ### Features 4 | 5 | - performance lib ([a209243](https://github.com/webfansplz/null-cli/commit/a209243bb7daa5b696e6343b12e978952384b0be)) 6 | 7 | ## 1.0.3 (2019-12-05) 8 | 9 | ### Bug Fixes 10 | 11 | - docs assets reference path ([6f782df](https://github.com/webfansplz/null-cli/commit/6f782df48a1096afd98bcbb5821ed06df9f131a6)) 12 | - npmignore error ([b7c365c](https://github.com/webfansplz/null-cli/commit/b7c365cd2264ac683ba7edfd89a6eb30f64e0a48)) 13 | - package name ([0ee3efe](https://github.com/webfansplz/null-cli/commit/0ee3efedfa364b21a89328143daecbf63404ce1c)) 14 | - rewrite test case ([89dff48](https://github.com/webfansplz/null-cli/commit/89dff48508d575645e8cf3314f793db626cc8096)) 15 | 16 | ### Features 17 | 18 | - **n:** compress feature ([57af1fb](https://github.com/webfansplz/null-cli/commit/57af1fbb2de4faabea5f09ba29d8960b66d25726)) 19 | - mutiple search support ([3aad578](https://github.com/webfansplz/null-cli/commit/3aad57867bbe789c6ad1dfea907f9b6f6c6e3ecc)) 20 | - search ([8f33e70](https://github.com/webfansplz/null-cli/commit/8f33e709a72a68414a5d3614ac7ec067f8fbb1ef)) 21 | - use gh-pages build docs ([73d0d45](https://github.com/webfansplz/null-cli/commit/73d0d459235177a11f2052820d242d0cbef1d905)) 22 | - v1 completed ([1bc7c30](https://github.com/webfansplz/null-cli/commit/1bc7c30393ab3a63cddf5ae49a1f63e3d62601ae)) 23 | -------------------------------------------------------------------------------- /lib/youdao/parser.js: -------------------------------------------------------------------------------- 1 | const cheerio = require('cheerio'); 2 | 3 | const parser = {}; 4 | parser.parse = function(isChinese, body) { 5 | const $ = cheerio.load(body); 6 | let result = ''; 7 | let sentenceSample = ''; 8 | if (isChinese) { 9 | $('div.trans-container > ul') 10 | .find('p.wordGroup') 11 | .each(function() { 12 | result += $(this) 13 | .text() 14 | .replace(/\s+/g, ' '); 15 | }); 16 | } else { 17 | $('div#phrsListTab > div.trans-container > ul') 18 | .find('li') 19 | .each(function() { 20 | result += `${$(this) 21 | .text() 22 | .replace(/\s+/g, ' ')}\n`; 23 | }); 24 | $('#bilingual ul li') 25 | .find('p') 26 | .each(function() { 27 | if ($(this).attr('class') !== 'example-via') { 28 | sentenceSample += `${$(this) 29 | .text() 30 | .trim()}\n`; 31 | console.log( 32 | `${$(this) 33 | .text() 34 | .trim()}\n`, 35 | ); 36 | } 37 | }); 38 | } 39 | // phrase or sentence 40 | if (result === '') { 41 | result = 42 | $('div#webPhrase > p.wordGroup').text() !== '' 43 | ? $('div#webPhrase > p.wordGroup').text() 44 | : $('div#fanyiToggle > div.trans-container > p:nth-child(2)').text(); 45 | } 46 | // phonetic 47 | result = `${$('div#phrsListTab > h2.wordbook-js > div.baav > span') 48 | .text() 49 | .replace(/\s+/g, ' ')}\n\n${result}\n${sentenceSample}`; 50 | return result; 51 | }; 52 | module.exports = parser; 53 | -------------------------------------------------------------------------------- /lib/regex/list.js: -------------------------------------------------------------------------------- 1 | const escapeFn = str => escape(str).replace(/%/g, '\\'); 2 | const list = { 3 | name: 'action', 4 | type: 'list', 5 | message: '📄 Please Select a regular expression', 6 | choices: [ 7 | { name: '纯数字', value: '^[0-9]*$', example: 20 }, 8 | { 9 | name: '纯汉字', 10 | value: `^[${escapeFn('\u4E00')}-${escapeFn('\u9FA5')}]{0,}$`, 11 | example: '我是汉字', 12 | }, 13 | { 14 | name: '纯英文字母', 15 | value: '^[a-zA-Z]+$', 16 | example: 'nullcli', 17 | }, 18 | { 19 | name: '中文、英文、数字', 20 | value: `^[${escapeFn('\u4E00')}-${escapeFn('\u9FA5')}A-Za-z0-9]+$`, 21 | example: '前端cliV1', 22 | }, 23 | 24 | { 25 | name: '日期格式(例:2019-11-11)', 26 | value: '^\\d{4}(-)(1[0-2]|0?\\d)\\1([0-2]\\d|\\d|30|31)$', 27 | example: '2020-11-11', 28 | }, 29 | { 30 | name: '6-16位数字字母组合', 31 | value: '^[a-zA-Z0-9]{6,16}$', 32 | example: '123456abcABC', 33 | }, 34 | { 35 | name: '邮箱地址(email)', 36 | value: 37 | "^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$", 38 | example: 'edg4396@qq.com', 39 | }, 40 | { 41 | name: 'ip-v4', 42 | value: 43 | '^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$', 44 | example: '127.0.0.1', 45 | }, 46 | { 47 | name: '邮政编码', 48 | value: 49 | '^(0[1-7]|1[0-356]|2[0-7]|3[0-6]|4[0-7]|5[1-7]|6[1-7]|7[0-5]|8[013-6])\\d{4}$', 50 | example: 100101, 51 | }, 52 | ], 53 | }; 54 | 55 | module.exports = { 56 | list, 57 | }; 58 | -------------------------------------------------------------------------------- /lib/create/template/active-page/styles/reset.css: -------------------------------------------------------------------------------- 1 | /* http://meyerweb.com/eric/tools/css/reset/ 2 | v2.0 | 20110126 3 | License: none (public domain) 4 | */ 5 | 6 | html, 7 | body, 8 | div, 9 | span, 10 | applet, 11 | object, 12 | iframe, 13 | h1, 14 | h2, 15 | h3, 16 | h4, 17 | h5, 18 | h6, 19 | p, 20 | blockquote, 21 | pre, 22 | a, 23 | abbr, 24 | acronym, 25 | address, 26 | big, 27 | cite, 28 | code, 29 | del, 30 | dfn, 31 | em, 32 | img, 33 | ins, 34 | kbd, 35 | q, 36 | s, 37 | samp, 38 | small, 39 | strike, 40 | strong, 41 | sub, 42 | sup, 43 | tt, 44 | var, 45 | b, 46 | u, 47 | i, 48 | center, 49 | dl, 50 | dt, 51 | dd, 52 | ol, 53 | ul, 54 | li, 55 | fieldset, 56 | form, 57 | label, 58 | legend, 59 | table, 60 | caption, 61 | tbody, 62 | tfoot, 63 | thead, 64 | tr, 65 | th, 66 | td, 67 | article, 68 | aside, 69 | canvas, 70 | details, 71 | embed, 72 | figure, 73 | figcaption, 74 | footer, 75 | header, 76 | hgroup, 77 | menu, 78 | nav, 79 | output, 80 | ruby, 81 | section, 82 | summary, 83 | time, 84 | mark, 85 | audio, 86 | video { 87 | margin: 0; 88 | padding: 0; 89 | border: 0; 90 | font-size: 100%; 91 | vertical-align: baseline; 92 | } 93 | /* HTML5 display-role reset for older browsers */ 94 | article, 95 | aside, 96 | details, 97 | figcaption, 98 | figure, 99 | footer, 100 | header, 101 | hgroup, 102 | menu, 103 | nav, 104 | section { 105 | display: block; 106 | } 107 | body { 108 | line-height: 1; 109 | } 110 | ol, 111 | ul { 112 | list-style: none; 113 | } 114 | blockquote, 115 | q { 116 | quotes: none; 117 | } 118 | blockquote:before, 119 | blockquote:after, 120 | q:before, 121 | q:after { 122 | content: ""; 123 | content: none; 124 | } 125 | table { 126 | border-collapse: collapse; 127 | border-spacing: 0; 128 | } 129 | -------------------------------------------------------------------------------- /lib/performance/index.js: -------------------------------------------------------------------------------- 1 | const ora = require('ora'); 2 | const { parse } = require('url'); 3 | const puppeteer = require('puppeteer'); 4 | 5 | async function performance(url) { 6 | const spinner = ora('Loading Info ...'); 7 | spinner.start(); 8 | const { protocol } = parse(url); 9 | const website = protocol ? url : `http://${url}`; 10 | const browser = await puppeteer.launch(); 11 | const page = await browser.newPage(); 12 | await page.goto(website); 13 | const performanceTiming = JSON.parse( 14 | await page.evaluate(() => JSON.stringify(window.performance.timing)), 15 | ); 16 | await browser.close(); 17 | spinner.stop(); 18 | const { 19 | loadEventEnd, 20 | navigationStart, 21 | domainLookupEnd, 22 | domainLookupStart, 23 | connectEnd, 24 | connectStart, 25 | responseEnd, 26 | responseStart, 27 | domComplete, 28 | domInteractive, 29 | domContentLoadedEventEnd, 30 | } = performanceTiming; 31 | 32 | // DNS查询耗时 33 | const dnsLookupTime = domainLookupEnd - domainLookupStart; 34 | // TCP连接耗时 35 | const tcpConnectTime = connectEnd - connectStart; 36 | // 页面请求耗时 37 | const downloadTime = responseEnd - responseStart; 38 | // DOM解析耗时 39 | const parseDomTime = domComplete - domInteractive; 40 | // 白屏耗时 41 | const whiteScreenTime = responseStart - navigationStart; 42 | // DOM Ready 耗时 43 | const domReadyTime = domContentLoadedEventEnd - navigationStart; 44 | // 页面加载总耗时 45 | const pageLoadTime = loadEventEnd - navigationStart; 46 | console.log({ 47 | DNS查询耗时: `${dnsLookupTime}ms`, 48 | TCP连接耗时: `${tcpConnectTime}ms`, 49 | 页面请求耗时: `${downloadTime}ms`, 50 | 白屏耗时: `${whiteScreenTime}ms`, 51 | DOM解析耗时: `${parseDomTime}ms`, 52 | DOMReady耗时: `${domReadyTime}ms`, 53 | 页面加载总耗时: `${pageLoadTime}ms`, 54 | }); 55 | } 56 | module.exports = performance; 57 | -------------------------------------------------------------------------------- /lib/create/template/react/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 14 | 15 | 24 | <%= projectName %> 25 | 26 | 27 | 28 |
29 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /docs/.vuepress/config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | base: '/null-cli/', 3 | dest: 'docs/dist', 4 | port: 3333, 5 | serviceWorker: true, 6 | locales: { 7 | '/': { 8 | lang: 'zh-CN', 9 | title: 'null-cli', 10 | description: 'A command makes you more efficient', 11 | }, 12 | }, 13 | head: [ 14 | [ 15 | 'link', 16 | { 17 | rel: 'icon', 18 | href: '/la-m.png', 19 | }, 20 | ], 21 | [ 22 | 'meta', 23 | { 24 | name: 'theme-color', 25 | content: '#3eaf7c', 26 | }, 27 | ], 28 | ], 29 | themeConfig: { 30 | repo: 'webfansplz/null-cli', 31 | editLinks: true, 32 | docsDir: 'docs', 33 | locales: { 34 | '/': { 35 | label: '简体中文', 36 | selectText: '选择语言', 37 | editLinkText: '在 GitHub 上编辑此页', 38 | lastUpdated: '上次更新', 39 | serviceWorker: { 40 | updatePopup: { 41 | message: '发现新内容可用', 42 | buttonText: '刷新', 43 | }, 44 | }, 45 | nav: [ 46 | // { 47 | // text: '文档', 48 | // link: '/API/install.html' 49 | // } 50 | ], 51 | }, 52 | }, 53 | sidebar: { 54 | '/guide/': [ 55 | { 56 | title: '使用指南', 57 | collapsable: false, 58 | children: ['install', 'introduce', 'use'], 59 | }, 60 | { 61 | title: '命令', 62 | collapsable: false, 63 | children: [ 64 | 'search', 65 | 'compress', 66 | 'fetch', 67 | 'youdao', 68 | 'performance', 69 | 'open', 70 | 'qrcode', 71 | 'regex', 72 | 'random', 73 | 'create', 74 | 'day', 75 | 'serve', 76 | 'enc', 77 | 'dec', 78 | ], 79 | }, 80 | ], 81 | }, 82 | }, 83 | }; 84 | -------------------------------------------------------------------------------- /test/enc.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const enc = require('../lib/enc') 3 | 4 | test('enc api for sha1', t => { 5 | t.deepEqual( 6 | enc('null-cli', { 7 | method: 'sha1', 8 | }), 9 | 'a0071acf7a33712783545db8b4a7a89f0a35013d', 10 | ) 11 | }) 12 | 13 | test('enc api for sha224', t => { 14 | t.deepEqual( 15 | enc('null-cli', { 16 | method: 'sha224', 17 | }), 18 | '1b0dcf9ea78c755266cf0d1d652d741fa4112770fef5889f9411c090', 19 | ) 20 | }) 21 | 22 | test('enc api for sha256', t => { 23 | t.deepEqual( 24 | enc('null-cli', { 25 | method: 'sha256', 26 | }), 27 | 'fe8f4fa399ff4888b4d393c8dd09ba35385db71e12d627d83cc65d89ba83fc9b', 28 | ) 29 | }) 30 | 31 | test('enc api for sha384', t => { 32 | t.deepEqual( 33 | enc('null-cli', { 34 | method: 'sha384', 35 | }), 36 | 'c366ef75eb44fd3839bc1edb980b3c4907d78541ec2a30f7d20d228eb7b77563aaffce492f26d84bd0a5c8cffcedebc4', 37 | ) 38 | }) 39 | 40 | test('enc api for sha512', t => { 41 | t.deepEqual( 42 | enc('null-cli', { 43 | method: 'sha512', 44 | }), 45 | '72d921a66c4d2ed07a282cc9be1a804e4409a12bf77acefd9977d8b9d170556b70546769944d3c853a5e788999495742109940935f8463eeac6aba7507ac2883', 46 | ) 47 | }) 48 | 49 | test('enc api for md5', t => { 50 | t.deepEqual( 51 | enc('null-cli', { 52 | method: 'md5', 53 | }), 54 | '91732209f7c84dd6119c81fd8b1a9669', 55 | ) 56 | }) 57 | 58 | test('enc api for base64', t => { 59 | t.deepEqual( 60 | enc('null-cli', { 61 | method: 'base64', 62 | }), 63 | 'bnVsbC1jbGk=', 64 | ) 65 | }) 66 | 67 | test('enc api for hex', t => { 68 | t.deepEqual( 69 | enc('null-cli', { 70 | method: 'hex', 71 | }), 72 | '6e756c6c2d636c69', 73 | ) 74 | }) 75 | 76 | test('enc api for aes', t => { 77 | t.deepEqual( 78 | enc('null-cli', { 79 | method: 'aes', 80 | key: '20201111nullbest', 81 | iv: 'webbestlangworld', 82 | }), 83 | 'b425ed8b1698de56aed3d1089ade239d', 84 | ) 85 | }) 86 | -------------------------------------------------------------------------------- /lib/create/fileServer.js: -------------------------------------------------------------------------------- 1 | const ejs = require('ejs'); 2 | const path = require('path'); 3 | const slash = require('slash'); 4 | const fs = require('fs-extra'); 5 | const globby = require('globby'); 6 | const rimraf = require('rimraf'); 7 | const { isBinaryFileSync } = require('isbinaryfile'); 8 | 9 | const fileServer = { 10 | normalizeFilePaths(files) { 11 | Object.keys(files).forEach(file => { 12 | const normalized = slash(file); 13 | if (file !== normalized) { 14 | files[normalized] = files[file]; 15 | delete files[file]; 16 | } 17 | }); 18 | return files; 19 | }, 20 | async delete(directory, files) { 21 | await rimraf.sync(`${directory}/*`); 22 | return Promise.all( 23 | files.map(async filename => { 24 | await rimraf.sync(`${directory}/${filename}`); 25 | }), 26 | ); 27 | }, 28 | async list(context) { 29 | const options = { 30 | cwd: context, 31 | onlyFiles: true, 32 | gitignore: true, 33 | dot: true, 34 | ignore: ['**/node_modules/**', '**/.git/**'], 35 | }; 36 | const files = await globby(['**'], options); 37 | return files; 38 | }, 39 | async read(context, rewrite) { 40 | const res = {}; 41 | const files = await this.list(context); 42 | for (const file of files) { 43 | const name = path.resolve(context, file); 44 | res[file] = isBinaryFileSync(name) 45 | ? fs.readFileSync(name) 46 | : fs.readFileSync(name, 'utf-8'); 47 | } 48 | if (rewrite) { 49 | Object.keys(res).forEach(file => { 50 | if (rewrite.list.includes(file)) { 51 | res[file] = ejs.render(res[file], rewrite.options); 52 | } 53 | }); 54 | } 55 | return this.normalizeFilePaths(res); 56 | }, 57 | write(dir, files) { 58 | Object.keys(files).forEach(name => { 59 | const filePath = path.join(dir, name); 60 | fs.ensureDirSync(path.dirname(filePath)); 61 | fs.writeFileSync(filePath, files[name]); 62 | }); 63 | }, 64 | }; 65 | 66 | module.exports = fileServer; 67 | -------------------------------------------------------------------------------- /lib/compress/index.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | const globby = require('globby'); 4 | const CleanCSS = require('clean-css'); 5 | const UglifyJS = require('uglify-js'); 6 | const { minify } = require('html-minifier'); 7 | const chalk = require('chalk'); 8 | 9 | const methods = { 10 | html(data) { 11 | const result = minify(data, { 12 | removeComments: true, 13 | collapseWhitespace: true, 14 | minifyJS: true, 15 | minifyCSS: true, 16 | }); 17 | return result; 18 | }, 19 | js(data) { 20 | const { code } = UglifyJS.minify(data); 21 | return code; 22 | }, 23 | 24 | css(data) { 25 | const { styles } = new CleanCSS().minify(data); 26 | return styles; 27 | }, 28 | }; 29 | function rewrite(filename, type) { 30 | const data = fs.readFileSync(filename, 'utf8'); 31 | const result = methods[type](data); 32 | if (result) { 33 | fs.writeFileSync(filename, result); 34 | return result; 35 | } 36 | console.log(); 37 | console.log(chalk.red.dim(` Warning: ${filename} can't be compress`)); 38 | console.log(); 39 | } 40 | async function compress(target) { 41 | console.log('🚀 Start Compress'); 42 | const inCurrent = target === '.'; 43 | const name = inCurrent ? process.cwd() : target; 44 | const cwd = path.isAbsolute(name) ? name : path.join(process.cwd(), name); 45 | const isDirectory = fs.statSync(cwd).isDirectory(); 46 | const files = isDirectory 47 | ? await globby(['**'], { 48 | cwd, 49 | onlyFiles: true, 50 | gitignore: true, 51 | dot: false, 52 | ignore: ['**/node_modules/**', '**/.git/**'], 53 | }) 54 | : [cwd]; 55 | let result; 56 | files.forEach(file => { 57 | const postfix = /\w+$/g.exec(file)[0]; 58 | const compressType = ['js', 'css', 'html']; 59 | if (compressType.includes(postfix)) { 60 | result = rewrite(isDirectory ? path.join(cwd, file) : cwd, postfix); 61 | } 62 | }); 63 | console.log('🎉 Finish Compress'); 64 | return result; 65 | } 66 | 67 | module.exports = compress; 68 | -------------------------------------------------------------------------------- /lib/create/template/vue/src/components/HelloWorld.vue: -------------------------------------------------------------------------------- 1 | 31 | 32 | 40 | 41 | 42 | 58 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "null-cli", 3 | "version": "1.0.4", 4 | "description": "One line of command increases your productivity", 5 | "main": "index.js", 6 | "bin": { 7 | "null": "bin/null.js" 8 | }, 9 | "scripts": { 10 | "cz": "commitizen init cz-conventional-changelog --save --save-exact", 11 | "version": "conventional-changelog -p angular -i CHANGELOG.md -s", 12 | "lint": "eslint --fix lib/**/*.js bin/*.js utils/*.js", 13 | "test": "nyc ava", 14 | "docs:dev": "vuepress dev docs", 15 | "docs:build": "vuepress build docs", 16 | "deploy": "gh-pages -d docs/dist" 17 | }, 18 | "ava": { 19 | "files": [ 20 | "test/**/*.js" 21 | ] 22 | }, 23 | "pre-commit": [ 24 | "lint", 25 | "test" 26 | ], 27 | "repository": { 28 | "type": "git", 29 | "url": "git+https://github.com/webfansplz/null-cli.git" 30 | }, 31 | "keywords": [], 32 | "author": "null", 33 | "license": "MIT", 34 | "bugs": { 35 | "url": "https://github.com/webfansplz/null-cli/issues" 36 | }, 37 | "homepage": "https://github.com/webfansplz/null-cli#readme", 38 | "dependencies": { 39 | "address": "^1.1.2", 40 | "chalk": "^3.0.0", 41 | "cheerio": "^1.0.0-rc.3", 42 | "commander": "^4.0.1", 43 | "crypto-js": "^3.1.9-1", 44 | "dayjs": "^1.8.17", 45 | "default-gateway": "^5.0.5", 46 | "ejs": "^2.7.4", 47 | "execa": "^3.3.0", 48 | "express": "^4.17.1", 49 | "fs-extra": "^8.1.0", 50 | "globby": "^10.0.1", 51 | "html-minifier": "^4.0.0", 52 | "inquirer": "^7.0.0", 53 | "is-chinese": "^1.2.9", 54 | "isbinaryfile": "^4.0.2", 55 | "minimist": "^1.2.0", 56 | "no-case": "^2.3.2", 57 | "open": "^7.0.0", 58 | "ora": "^4.0.3", 59 | "portfinder": "^1.0.25", 60 | "puppeteer": "^2.0.0", 61 | "qrcode": "^1.4.4", 62 | "readline": "^1.3.0", 63 | "request": "^2.88.0", 64 | "rimraf": "^3.0.0", 65 | "semver": "^6.3.0", 66 | "slash": "^3.0.0", 67 | "uglify-js": "^3.7.0", 68 | "urlencode": "^1.1.0", 69 | "valid-url": "^1.0.9", 70 | "validate-npm-package-name": "^3.0.0" 71 | }, 72 | "devDependencies": { 73 | "ava": "^2.4.0", 74 | "clean-css": "^4.2.1", 75 | "cz-conventional-changelog": "^3.0.2", 76 | "eslint": "^6.7.1", 77 | "eslint-config-prettier": "^6.9.0", 78 | "eslint-plugin-import": "^2.18.2", 79 | "eslint-plugin-prettier": "^3.1.2", 80 | "gh-pages": "^2.1.1", 81 | "nyc": "^14.1.1", 82 | "pre-commit": "^1.2.2", 83 | "prettier": "^1.19.1", 84 | "vuepress": "^1.2.0" 85 | }, 86 | "engines": { 87 | "node": ">=8.9" 88 | }, 89 | "config": { 90 | "commitizen": { 91 | "path": "./node_modules/cz-conventional-changelog" 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /lib/create/verify.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const chalk = require('chalk'); 3 | const fs = require('fs-extra'); 4 | 5 | const inquirer = require('inquirer'); 6 | const validateProjectName = require('validate-npm-package-name'); 7 | const fileServer = require('./fileServer'); 8 | const { clearConsole } = require('../../utils/logger'); 9 | const { logWithSpinner, stopSpinner } = require('../../utils/spinner'); 10 | // 验证文件名 11 | const verify = { 12 | async exists(options, { targetDir, inCurrent }) { 13 | if (options.force) { 14 | await fs.remove(targetDir); 15 | } else { 16 | await clearConsole(); 17 | if (inCurrent) { 18 | const { ok } = await inquirer.prompt([ 19 | { 20 | name: 'ok', 21 | type: 'confirm', 22 | message: 'Generate project in current directory?', 23 | }, 24 | ]); 25 | if (!ok) { 26 | return false; 27 | } 28 | } 29 | const files = await fileServer.list(targetDir); 30 | if (files.length) { 31 | const { action } = await inquirer.prompt([ 32 | { 33 | name: 'action', 34 | type: 'list', 35 | message: `Target directory ${chalk.cyan( 36 | targetDir, 37 | )} already exists. Pick an action:`, 38 | choices: [ 39 | { 40 | name: 'Overwrite', 41 | value: 'overwrite', 42 | }, 43 | { 44 | name: 'Merge', 45 | value: 'merge', 46 | }, 47 | { 48 | name: 'Cancel', 49 | value: false, 50 | }, 51 | ], 52 | }, 53 | ]); 54 | if (!action) { 55 | return false; 56 | } 57 | if (action === 'overwrite') { 58 | logWithSpinner(`Removing ${chalk.bold(targetDir)}...`); 59 | if (inCurrent) { 60 | await fileServer.delete(targetDir, files); 61 | } else { 62 | await fs.remove(targetDir); 63 | } 64 | stopSpinner(); 65 | } 66 | } 67 | } 68 | return true; 69 | }, 70 | invalid(name, { errors, warnings }) { 71 | console.error(chalk.red(`Invalid project name: "${name}"`)); 72 | errors && 73 | errors.forEach(err => { 74 | console.error(chalk.red.dim(`Error: ${err}`)); 75 | }); 76 | warnings && 77 | warnings.forEach(warn => { 78 | console.error(chalk.red.dim(`Warning: ${warn}`)); 79 | }); 80 | process.exit(1); 81 | }, 82 | async start(projectName, options) { 83 | const cwd = options.cwd || process.cwd(); 84 | const inCurrent = projectName === '.'; 85 | const name = inCurrent ? path.relative('../', cwd) : projectName; 86 | const targetDir = path.resolve(cwd, projectName || '.'); 87 | const { validForNewPackages, errors, warnings } = validateProjectName(name); 88 | // 项目名格式无效 89 | !validForNewPackages && this.invalid(name, { errors, warnings }); 90 | // 项目名存在 91 | if (fs.existsSync(targetDir)) { 92 | const action = await this.exists(options, { targetDir, inCurrent }); 93 | if (!action) return false; 94 | } 95 | return { 96 | name, 97 | context: targetDir, 98 | }; 99 | }, 100 | }; 101 | 102 | module.exports = verify; 103 | -------------------------------------------------------------------------------- /lib/create/template/react/src/serviceWorker.js: -------------------------------------------------------------------------------- 1 | // This optional code is used to register a service worker. 2 | // register() is not called by default. 3 | 4 | // This lets the app load faster on subsequent visits in production, and gives 5 | // it offline capabilities. However, it also means that developers (and users) 6 | // will only see deployed updates on subsequent visits to a page, after all the 7 | // existing tabs open on the page have been closed, since previously cached 8 | // resources are updated in the background. 9 | 10 | // To learn more about the benefits of this model and instructions on how to 11 | // opt-in, read https://bit.ly/CRA-PWA 12 | 13 | const isLocalhost = Boolean( 14 | window.location.hostname === 'localhost' || 15 | // [::1] is the IPv6 localhost address. 16 | window.location.hostname === '[::1]' || 17 | // 127.0.0.1/8 is considered localhost for IPv4. 18 | window.location.hostname.match( 19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ 20 | ) 21 | ); 22 | 23 | export function register(config) { 24 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 25 | // The URL constructor is available in all browsers that support SW. 26 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href); 27 | if (publicUrl.origin !== window.location.origin) { 28 | // Our service worker won't work if PUBLIC_URL is on a different origin 29 | // from what our page is served on. This might happen if a CDN is used to 30 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374 31 | return; 32 | } 33 | 34 | window.addEventListener('load', () => { 35 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; 36 | 37 | if (isLocalhost) { 38 | // This is running on localhost. Let's check if a service worker still exists or not. 39 | checkValidServiceWorker(swUrl, config); 40 | 41 | // Add some additional logging to localhost, pointing developers to the 42 | // service worker/PWA documentation. 43 | navigator.serviceWorker.ready.then(() => { 44 | console.log( 45 | 'This web app is being served cache-first by a service ' + 46 | 'worker. To learn more, visit https://bit.ly/CRA-PWA' 47 | ); 48 | }); 49 | } else { 50 | // Is not localhost. Just register service worker 51 | registerValidSW(swUrl, config); 52 | } 53 | }); 54 | } 55 | } 56 | 57 | function registerValidSW(swUrl, config) { 58 | navigator.serviceWorker 59 | .register(swUrl) 60 | .then(registration => { 61 | registration.onupdatefound = () => { 62 | const installingWorker = registration.installing; 63 | if (installingWorker == null) { 64 | return; 65 | } 66 | installingWorker.onstatechange = () => { 67 | if (installingWorker.state === 'installed') { 68 | if (navigator.serviceWorker.controller) { 69 | // At this point, the updated precached content has been fetched, 70 | // but the previous service worker will still serve the older 71 | // content until all client tabs are closed. 72 | console.log( 73 | 'New content is available and will be used when all ' + 74 | 'tabs for this page are closed. See https://bit.ly/CRA-PWA.' 75 | ); 76 | 77 | // Execute callback 78 | if (config && config.onUpdate) { 79 | config.onUpdate(registration); 80 | } 81 | } else { 82 | // At this point, everything has been precached. 83 | // It's the perfect time to display a 84 | // "Content is cached for offline use." message. 85 | console.log('Content is cached for offline use.'); 86 | 87 | // Execute callback 88 | if (config && config.onSuccess) { 89 | config.onSuccess(registration); 90 | } 91 | } 92 | } 93 | }; 94 | }; 95 | }) 96 | .catch(error => { 97 | console.error('Error during service worker registration:', error); 98 | }); 99 | } 100 | 101 | function checkValidServiceWorker(swUrl, config) { 102 | // Check if the service worker can be found. If it can't reload the page. 103 | fetch(swUrl) 104 | .then(response => { 105 | // Ensure service worker exists, and that we really are getting a JS file. 106 | const contentType = response.headers.get('content-type'); 107 | if ( 108 | response.status === 404 || 109 | (contentType != null && contentType.indexOf('javascript') === -1) 110 | ) { 111 | // No service worker found. Probably a different app. Reload the page. 112 | navigator.serviceWorker.ready.then(registration => { 113 | registration.unregister().then(() => { 114 | window.location.reload(); 115 | }); 116 | }); 117 | } else { 118 | // Service worker found. Proceed as normal. 119 | registerValidSW(swUrl, config); 120 | } 121 | }) 122 | .catch(() => { 123 | console.log( 124 | 'No internet connection found. App is running in offline mode.' 125 | ); 126 | }); 127 | } 128 | 129 | export function unregister() { 130 | if ('serviceWorker' in navigator) { 131 | navigator.serviceWorker.ready.then(registration => { 132 | registration.unregister(); 133 | }); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /bin/null.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | const program = require('commander'); 3 | const minimist = require('minimist'); 4 | const chalk = require('chalk'); 5 | const semver = require('semver'); 6 | const requiredVersion = require('../package.json').engines.node; 7 | 8 | function checkNodeVersion(wanted, id) { 9 | if (!semver.satisfies(process.version, wanted)) { 10 | console.log( 11 | chalk.red( 12 | `You are using Node ${process.version}, but this version of ${id} requires Node ${wanted} '.\nPlease upgrade your Node version.'`, 13 | ), 14 | ); 15 | process.exit(1); 16 | } 17 | } 18 | 19 | checkNodeVersion(requiredVersion, 'null-cli'); 20 | 21 | if (semver.satisfies(process.version, '9.x')) { 22 | console.log( 23 | chalk.red( 24 | `You are using Node ${process.version}.\n` + 25 | 'Node.js 9.x has already reached end-of-life and will not be supported in future major releases.\n' + 26 | "It's strongly recommended to use an active LTS version instead.", 27 | ), 28 | ); 29 | } 30 | 31 | function camelize(str) { 32 | return str.replace(/-(\w)/g, (_, c) => (c ? c.toUpperCase() : '')); 33 | } 34 | 35 | function cleanArgs(cmd) { 36 | const args = {}; 37 | cmd.options.forEach(o => { 38 | const key = camelize(o.long.replace(/^--/, '')); 39 | if (typeof cmd[key] !== 'function' && typeof cmd[key] !== 'undefined') { 40 | args[key] = cmd[key]; 41 | } 42 | }); 43 | return args; 44 | } 45 | 46 | program 47 | .version(`null-cli ${require('../package.json').version}`) 48 | .usage(' [options]'); 49 | 50 | function verifyArgs(name) { 51 | if (minimist(process.argv.slice(3))._.length > 1) { 52 | console.log( 53 | chalk.yellow( 54 | `\n Info: You provided more than one argument. The first one will be used as the ${name}, the rest are ignored.`, 55 | ), 56 | ); 57 | } 58 | } 59 | program 60 | .command('perf ') 61 | .description('web performance') 62 | .action(name => { 63 | verifyArgs('Url'); 64 | require('../lib/performance')(name); 65 | }); 66 | program 67 | .command('compress ') 68 | .description('Compress file') 69 | .action(name => { 70 | verifyArgs('File'); 71 | require('../lib/compress')(name); 72 | }); 73 | program 74 | .command('fetch ') 75 | .description('Send network request') 76 | .action((name, cmd) => { 77 | const options = cleanArgs(cmd); 78 | verifyArgs('Url'); 79 | require('../lib/fetch')(name, options); 80 | }); 81 | program 82 | .command('youdao ') 83 | .description('Chinese-english translation') 84 | .action(name => { 85 | verifyArgs('Word'); 86 | require('../lib/youdao')(name); 87 | }); 88 | program 89 | .command('open ') 90 | .description('Open brower') 91 | .action((name, cmd) => { 92 | const options = cleanArgs(cmd); 93 | verifyArgs('Url'); 94 | require('../lib/open')(name, options); 95 | }); 96 | program 97 | .command('qrcode ') 98 | .description('Generate qrcode') 99 | .action(name => { 100 | verifyArgs('Url'); 101 | require('../lib/qrcode')(name); 102 | }); 103 | program 104 | .command('regex') 105 | .description('List of regex expressions') 106 | .action(() => { 107 | require('../lib/regex')(); 108 | }); 109 | program 110 | .command('random ') 111 | .description('Generate random number') 112 | .action(name => { 113 | verifyArgs('Length'); 114 | require('../lib/random')(name); 115 | }); 116 | program 117 | .command('create ') 118 | .description('Create a new probject by null-cli') 119 | .option('-f, --force', 'Overwrite target directory if it exists') 120 | .action((name, cmd) => { 121 | const options = cleanArgs(cmd); 122 | verifyArgs('App Name'); 123 | require('../lib/create')(name, options); 124 | }); 125 | program 126 | .command('day ') 127 | .description('Parsing the date') 128 | .option('-f, --format ', ' How to format ', 'YYYY-MM-DD HH:mm:ss') 129 | .option('-t, --type ', 'Format type', 'string') 130 | .action((name, cmd) => { 131 | const options = cleanArgs(cmd); 132 | verifyArgs('date'); 133 | require('../lib/day')(name, options); 134 | }); 135 | program 136 | .command('serve ') 137 | .description('Start web serve') 138 | .option('-p, --port ', ' Which port to use ', 8000) 139 | .option('-o, --open', 'Auto open browser') 140 | .action((name, cmd) => { 141 | const options = cleanArgs(cmd); 142 | verifyArgs('Path'); 143 | require('../lib/serve')(name, options); 144 | }); 145 | 146 | program 147 | .command('enc ') 148 | .description('Enc string') 149 | .option('-m, --method ', ' Which method to use ', 'base64') 150 | .option('-k, --key ', ' Aes encryption key ', '20201111nullbest') 151 | .option('-i, --iv ', ' Aes encryption iv ', 'webbestlangworld') 152 | .action((name, cmd) => { 153 | const options = cleanArgs(cmd); 154 | verifyArgs('String'); 155 | require('../lib/enc')(name, options); 156 | }); 157 | 158 | program 159 | .command('dec ') 160 | .description('Dec string') 161 | .option('-m, --method ', ' Which method to use ', 'base64') 162 | .option('-k, --key ', ' Aes decryption key ', '20201111nullbest') 163 | .option('-i, --iv ', ' Aes decryption iv ', 'webbestlangworld') 164 | .action((name, cmd) => { 165 | const options = cleanArgs(cmd); 166 | verifyArgs('String'); 167 | require('../lib/dec')(name, options); 168 | }); 169 | 170 | program 171 | .command('search ') 172 | .option('-n, --npm', 'search by npm') 173 | .option('-s, --stackoverflow', 'search by stackoverflow') 174 | .option('-w, --wiki', 'search by wiki') 175 | .option('-b, --baidu', 'search by baidu') 176 | .option('-g, --github', 'search by github') 177 | .option('-d, --default', 'search by google') 178 | .option('-a, --all', 'search by all sites') 179 | .description('quick search single or mutiple') 180 | .action((name, cmd) => { 181 | const options = cleanArgs(cmd); 182 | verifyArgs('Keyword'); 183 | require('../lib/search')(name, options); 184 | }); 185 | 186 | // add some useful info on help 187 | program.on('--help', () => { 188 | console.log(); 189 | console.log( 190 | ` Run ${chalk.cyan( 191 | 'null --help', 192 | )} for detailed usage of given command.`, 193 | ); 194 | console.log(); 195 | }); 196 | 197 | program.commands.forEach(c => c.on('--help', () => console.log())); 198 | 199 | function enhanceErrorMessages(methodName, log) { 200 | program.Command.prototype[methodName] = function(...args) { 201 | if (methodName === 'unknownOption' && this._allowUnknownOption) { 202 | return; 203 | } 204 | this.outputHelp(); 205 | console.log(` ${chalk.red(log(...args))}`); 206 | console.log(); 207 | process.exit(1); 208 | }; 209 | } 210 | 211 | enhanceErrorMessages( 212 | 'missingArgument', 213 | argName => `Missing required argument ${chalk.yellow(`<${argName}>`)}.`, 214 | ); 215 | 216 | enhanceErrorMessages( 217 | 'unknownOption', 218 | optionName => `Unknown option ${chalk.yellow(optionName)}.`, 219 | ); 220 | 221 | enhanceErrorMessages( 222 | 'optionMissingArgument', 223 | (option, flag) => 224 | `Missing required argument for option ${chalk.yellow(option.flags)}${ 225 | flag ? `, got ${chalk.yellow(flag)}` : '' 226 | }`, 227 | ); 228 | 229 | program.parse(process.argv); 230 | 231 | if (!process.argv.slice(2).length) { 232 | program.outputHelp(); 233 | } 234 | -------------------------------------------------------------------------------- /lib/create/template/react/src/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/create/template/active-page/js/zepto.min.js: -------------------------------------------------------------------------------- 1 | /* Zepto v1.2.0 - zepto event ajax form ie - zeptojs.com/license */ 2 | !function (t, e) { "function" == typeof define && define.amd ? define(function () { return e(t) }) : e(t) }(this, function (t) { var e = function () { function $(t) { return null == t ? String(t) : S[C.call(t)] || "object" } function F(t) { return "function" == $(t) } function k(t) { return null != t && t == t.window } function M(t) { return null != t && t.nodeType == t.DOCUMENT_NODE } function R(t) { return "object" == $(t) } function Z(t) { return R(t) && !k(t) && Object.getPrototypeOf(t) == Object.prototype } function z(t) { var e = !!t && "length" in t && t.length, n = r.type(t); return "function" != n && !k(t) && ("array" == n || 0 === e || "number" == typeof e && e > 0 && e - 1 in t) } function q(t) { return a.call(t, function (t) { return null != t }) } function H(t) { return t.length > 0 ? r.fn.concat.apply([], t) : t } function I(t) { return t.replace(/::/g, "/").replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2").replace(/([a-z\d])([A-Z])/g, "$1_$2").replace(/_/g, "-").toLowerCase() } function V(t) { return t in l ? l[t] : l[t] = new RegExp("(^|\\s)" + t + "(\\s|$)") } function _(t, e) { return "number" != typeof e || h[I(t)] ? e : e + "px" } function B(t) { var e, n; return c[t] || (e = f.createElement(t), f.body.appendChild(e), n = getComputedStyle(e, "").getPropertyValue("display"), e.parentNode.removeChild(e), "none" == n && (n = "block"), c[t] = n), c[t] } function U(t) { return "children" in t ? u.call(t.children) : r.map(t.childNodes, function (t) { return 1 == t.nodeType ? t : void 0 }) } function X(t, e) { var n, r = t ? t.length : 0; for (n = 0; r > n; n++)this[n] = t[n]; this.length = r, this.selector = e || "" } function J(t, r, i) { for (n in r) i && (Z(r[n]) || L(r[n])) ? (Z(r[n]) && !Z(t[n]) && (t[n] = {}), L(r[n]) && !L(t[n]) && (t[n] = []), J(t[n], r[n], i)) : r[n] !== e && (t[n] = r[n]) } function W(t, e) { return null == e ? r(t) : r(t).filter(e) } function Y(t, e, n, r) { return F(e) ? e.call(t, n, r) : e } function G(t, e, n) { null == n ? t.removeAttribute(e) : t.setAttribute(e, n) } function K(t, n) { var r = t.className || "", i = r && r.baseVal !== e; return n === e ? i ? r.baseVal : r : void (i ? r.baseVal = n : t.className = n) } function Q(t) { try { return t ? "true" == t || ("false" == t ? !1 : "null" == t ? null : +t + "" == t ? +t : /^[\[\{]/.test(t) ? r.parseJSON(t) : t) : t } catch (e) { return t } } function tt(t, e) { e(t); for (var n = 0, r = t.childNodes.length; r > n; n++)tt(t.childNodes[n], e) } var e, n, r, i, O, P, o = [], s = o.concat, a = o.filter, u = o.slice, f = t.document, c = {}, l = {}, h = { "column-count": 1, columns: 1, "font-weight": 1, "line-height": 1, opacity: 1, "z-index": 1, zoom: 1 }, p = /^\s*<(\w+|!)[^>]*>/, d = /^<(\w+)\s*\/?>(?:<\/\1>|)$/, m = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi, g = /^(?:body|html)$/i, v = /([A-Z])/g, y = ["val", "css", "html", "text", "data", "width", "height", "offset"], x = ["after", "prepend", "before", "append"], b = f.createElement("table"), E = f.createElement("tr"), j = { tr: f.createElement("tbody"), tbody: b, thead: b, tfoot: b, td: E, th: E, "*": f.createElement("div") }, w = /complete|loaded|interactive/, T = /^[\w-]*$/, S = {}, C = S.toString, N = {}, A = f.createElement("div"), D = { tabindex: "tabIndex", readonly: "readOnly", "for": "htmlFor", "class": "className", maxlength: "maxLength", cellspacing: "cellSpacing", cellpadding: "cellPadding", rowspan: "rowSpan", colspan: "colSpan", usemap: "useMap", frameborder: "frameBorder", contenteditable: "contentEditable" }, L = Array.isArray || function (t) { return t instanceof Array }; return N.matches = function (t, e) { if (!e || !t || 1 !== t.nodeType) return !1; var n = t.matches || t.webkitMatchesSelector || t.mozMatchesSelector || t.oMatchesSelector || t.matchesSelector; if (n) return n.call(t, e); var r, i = t.parentNode, o = !i; return o && (i = A).appendChild(t), r = ~N.qsa(i, e).indexOf(t), o && A.removeChild(t), r }, O = function (t) { return t.replace(/-+(.)?/g, function (t, e) { return e ? e.toUpperCase() : "" }) }, P = function (t) { return a.call(t, function (e, n) { return t.indexOf(e) == n }) }, N.fragment = function (t, n, i) { var o, s, a; return d.test(t) && (o = r(f.createElement(RegExp.$1))), o || (t.replace && (t = t.replace(m, "<$1>")), n === e && (n = p.test(t) && RegExp.$1), n in j || (n = "*"), a = j[n], a.innerHTML = "" + t, o = r.each(u.call(a.childNodes), function () { a.removeChild(this) })), Z(i) && (s = r(o), r.each(i, function (t, e) { y.indexOf(t) > -1 ? s[t](e) : s.attr(t, e) })), o }, N.Z = function (t, e) { return new X(t, e) }, N.isZ = function (t) { return t instanceof N.Z }, N.init = function (t, n) { var i; if (!t) return N.Z(); if ("string" == typeof t) if (t = t.trim(), "<" == t[0] && p.test(t)) i = N.fragment(t, RegExp.$1, n), t = null; else { if (n !== e) return r(n).find(t); i = N.qsa(f, t) } else { if (F(t)) return r(f).ready(t); if (N.isZ(t)) return t; if (L(t)) i = q(t); else if (R(t)) i = [t], t = null; else if (p.test(t)) i = N.fragment(t.trim(), RegExp.$1, n), t = null; else { if (n !== e) return r(n).find(t); i = N.qsa(f, t) } } return N.Z(i, t) }, r = function (t, e) { return N.init(t, e) }, r.extend = function (t) { var e, n = u.call(arguments, 1); return "boolean" == typeof t && (e = t, t = n.shift()), n.forEach(function (n) { J(t, n, e) }), t }, N.qsa = function (t, e) { var n, r = "#" == e[0], i = !r && "." == e[0], o = r || i ? e.slice(1) : e, s = T.test(o); return t.getElementById && s && r ? (n = t.getElementById(o)) ? [n] : [] : 1 !== t.nodeType && 9 !== t.nodeType && 11 !== t.nodeType ? [] : u.call(s && !r && t.getElementsByClassName ? i ? t.getElementsByClassName(o) : t.getElementsByTagName(e) : t.querySelectorAll(e)) }, r.contains = f.documentElement.contains ? function (t, e) { return t !== e && t.contains(e) } : function (t, e) { for (; e && (e = e.parentNode);)if (e === t) return !0; return !1 }, r.type = $, r.isFunction = F, r.isWindow = k, r.isArray = L, r.isPlainObject = Z, r.isEmptyObject = function (t) { var e; for (e in t) return !1; return !0 }, r.isNumeric = function (t) { var e = Number(t), n = typeof t; return null != t && "boolean" != n && ("string" != n || t.length) && !isNaN(e) && isFinite(e) || !1 }, r.inArray = function (t, e, n) { return o.indexOf.call(e, t, n) }, r.camelCase = O, r.trim = function (t) { return null == t ? "" : String.prototype.trim.call(t) }, r.uuid = 0, r.support = {}, r.expr = {}, r.noop = function () { }, r.map = function (t, e) { var n, i, o, r = []; if (z(t)) for (i = 0; i < t.length; i++)n = e(t[i], i), null != n && r.push(n); else for (o in t) n = e(t[o], o), null != n && r.push(n); return H(r) }, r.each = function (t, e) { var n, r; if (z(t)) { for (n = 0; n < t.length; n++)if (e.call(t[n], n, t[n]) === !1) return t } else for (r in t) if (e.call(t[r], r, t[r]) === !1) return t; return t }, r.grep = function (t, e) { return a.call(t, e) }, t.JSON && (r.parseJSON = JSON.parse), r.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function (t, e) { S["[object " + e + "]"] = e.toLowerCase() }), r.fn = { constructor: N.Z, length: 0, forEach: o.forEach, reduce: o.reduce, push: o.push, sort: o.sort, splice: o.splice, indexOf: o.indexOf, concat: function () { var t, e, n = []; for (t = 0; t < arguments.length; t++)e = arguments[t], n[t] = N.isZ(e) ? e.toArray() : e; return s.apply(N.isZ(this) ? this.toArray() : this, n) }, map: function (t) { return r(r.map(this, function (e, n) { return t.call(e, n, e) })) }, slice: function () { return r(u.apply(this, arguments)) }, ready: function (t) { return w.test(f.readyState) && f.body ? t(r) : f.addEventListener("DOMContentLoaded", function () { t(r) }, !1), this }, get: function (t) { return t === e ? u.call(this) : this[t >= 0 ? t : t + this.length] }, toArray: function () { return this.get() }, size: function () { return this.length }, remove: function () { return this.each(function () { null != this.parentNode && this.parentNode.removeChild(this) }) }, each: function (t) { return o.every.call(this, function (e, n) { return t.call(e, n, e) !== !1 }), this }, filter: function (t) { return F(t) ? this.not(this.not(t)) : r(a.call(this, function (e) { return N.matches(e, t) })) }, add: function (t, e) { return r(P(this.concat(r(t, e)))) }, is: function (t) { return this.length > 0 && N.matches(this[0], t) }, not: function (t) { var n = []; if (F(t) && t.call !== e) this.each(function (e) { t.call(this, e) || n.push(this) }); else { var i = "string" == typeof t ? this.filter(t) : z(t) && F(t.item) ? u.call(t) : r(t); this.forEach(function (t) { i.indexOf(t) < 0 && n.push(t) }) } return r(n) }, has: function (t) { return this.filter(function () { return R(t) ? r.contains(this, t) : r(this).find(t).size() }) }, eq: function (t) { return -1 === t ? this.slice(t) : this.slice(t, +t + 1) }, first: function () { var t = this[0]; return t && !R(t) ? t : r(t) }, last: function () { var t = this[this.length - 1]; return t && !R(t) ? t : r(t) }, find: function (t) { var e, n = this; return e = t ? "object" == typeof t ? r(t).filter(function () { var t = this; return o.some.call(n, function (e) { return r.contains(e, t) }) }) : 1 == this.length ? r(N.qsa(this[0], t)) : this.map(function () { return N.qsa(this, t) }) : r() }, closest: function (t, e) { var n = [], i = "object" == typeof t && r(t); return this.each(function (r, o) { for (; o && !(i ? i.indexOf(o) >= 0 : N.matches(o, t));)o = o !== e && !M(o) && o.parentNode; o && n.indexOf(o) < 0 && n.push(o) }), r(n) }, parents: function (t) { for (var e = [], n = this; n.length > 0;)n = r.map(n, function (t) { return (t = t.parentNode) && !M(t) && e.indexOf(t) < 0 ? (e.push(t), t) : void 0 }); return W(e, t) }, parent: function (t) { return W(P(this.pluck("parentNode")), t) }, children: function (t) { return W(this.map(function () { return U(this) }), t) }, contents: function () { return this.map(function () { return this.contentDocument || u.call(this.childNodes) }) }, siblings: function (t) { return W(this.map(function (t, e) { return a.call(U(e.parentNode), function (t) { return t !== e }) }), t) }, empty: function () { return this.each(function () { this.innerHTML = "" }) }, pluck: function (t) { return r.map(this, function (e) { return e[t] }) }, show: function () { return this.each(function () { "none" == this.style.display && (this.style.display = ""), "none" == getComputedStyle(this, "").getPropertyValue("display") && (this.style.display = B(this.nodeName)) }) }, replaceWith: function (t) { return this.before(t).remove() }, wrap: function (t) { var e = F(t); if (this[0] && !e) var n = r(t).get(0), i = n.parentNode || this.length > 1; return this.each(function (o) { r(this).wrapAll(e ? t.call(this, o) : i ? n.cloneNode(!0) : n) }) }, wrapAll: function (t) { if (this[0]) { r(this[0]).before(t = r(t)); for (var e; (e = t.children()).length;)t = e.first(); r(t).append(this) } return this }, wrapInner: function (t) { var e = F(t); return this.each(function (n) { var i = r(this), o = i.contents(), s = e ? t.call(this, n) : t; o.length ? o.wrapAll(s) : i.append(s) }) }, unwrap: function () { return this.parent().each(function () { r(this).replaceWith(r(this).children()) }), this }, clone: function () { return this.map(function () { return this.cloneNode(!0) }) }, hide: function () { return this.css("display", "none") }, toggle: function (t) { return this.each(function () { var n = r(this); (t === e ? "none" == n.css("display") : t) ? n.show() : n.hide() }) }, prev: function (t) { return r(this.pluck("previousElementSibling")).filter(t || "*") }, next: function (t) { return r(this.pluck("nextElementSibling")).filter(t || "*") }, html: function (t) { return 0 in arguments ? this.each(function (e) { var n = this.innerHTML; r(this).empty().append(Y(this, t, e, n)) }) : 0 in this ? this[0].innerHTML : null }, text: function (t) { return 0 in arguments ? this.each(function (e) { var n = Y(this, t, e, this.textContent); this.textContent = null == n ? "" : "" + n }) : 0 in this ? this.pluck("textContent").join("") : null }, attr: function (t, r) { var i; return "string" != typeof t || 1 in arguments ? this.each(function (e) { if (1 === this.nodeType) if (R(t)) for (n in t) G(this, n, t[n]); else G(this, t, Y(this, r, e, this.getAttribute(t))) }) : 0 in this && 1 == this[0].nodeType && null != (i = this[0].getAttribute(t)) ? i : e }, removeAttr: function (t) { return this.each(function () { 1 === this.nodeType && t.split(" ").forEach(function (t) { G(this, t) }, this) }) }, prop: function (t, e) { return t = D[t] || t, 1 in arguments ? this.each(function (n) { this[t] = Y(this, e, n, this[t]) }) : this[0] && this[0][t] }, removeProp: function (t) { return t = D[t] || t, this.each(function () { delete this[t] }) }, data: function (t, n) { var r = "data-" + t.replace(v, "-$1").toLowerCase(), i = 1 in arguments ? this.attr(r, n) : this.attr(r); return null !== i ? Q(i) : e }, val: function (t) { return 0 in arguments ? (null == t && (t = ""), this.each(function (e) { this.value = Y(this, t, e, this.value) })) : this[0] && (this[0].multiple ? r(this[0]).find("option").filter(function () { return this.selected }).pluck("value") : this[0].value) }, offset: function (e) { if (e) return this.each(function (t) { var n = r(this), i = Y(this, e, t, n.offset()), o = n.offsetParent().offset(), s = { top: i.top - o.top, left: i.left - o.left }; "static" == n.css("position") && (s.position = "relative"), n.css(s) }); if (!this.length) return null; if (f.documentElement !== this[0] && !r.contains(f.documentElement, this[0])) return { top: 0, left: 0 }; var n = this[0].getBoundingClientRect(); return { left: n.left + t.pageXOffset, top: n.top + t.pageYOffset, width: Math.round(n.width), height: Math.round(n.height) } }, css: function (t, e) { if (arguments.length < 2) { var i = this[0]; if ("string" == typeof t) { if (!i) return; return i.style[O(t)] || getComputedStyle(i, "").getPropertyValue(t) } if (L(t)) { if (!i) return; var o = {}, s = getComputedStyle(i, ""); return r.each(t, function (t, e) { o[e] = i.style[O(e)] || s.getPropertyValue(e) }), o } } var a = ""; if ("string" == $(t)) e || 0 === e ? a = I(t) + ":" + _(t, e) : this.each(function () { this.style.removeProperty(I(t)) }); else for (n in t) t[n] || 0 === t[n] ? a += I(n) + ":" + _(n, t[n]) + ";" : this.each(function () { this.style.removeProperty(I(n)) }); return this.each(function () { this.style.cssText += ";" + a }) }, index: function (t) { return t ? this.indexOf(r(t)[0]) : this.parent().children().indexOf(this[0]) }, hasClass: function (t) { return t ? o.some.call(this, function (t) { return this.test(K(t)) }, V(t)) : !1 }, addClass: function (t) { return t ? this.each(function (e) { if ("className" in this) { i = []; var n = K(this), o = Y(this, t, e, n); o.split(/\s+/g).forEach(function (t) { r(this).hasClass(t) || i.push(t) }, this), i.length && K(this, n + (n ? " " : "") + i.join(" ")) } }) : this }, removeClass: function (t) { return this.each(function (n) { if ("className" in this) { if (t === e) return K(this, ""); i = K(this), Y(this, t, n, i).split(/\s+/g).forEach(function (t) { i = i.replace(V(t), " ") }), K(this, i.trim()) } }) }, toggleClass: function (t, n) { return t ? this.each(function (i) { var o = r(this), s = Y(this, t, i, K(this)); s.split(/\s+/g).forEach(function (t) { (n === e ? !o.hasClass(t) : n) ? o.addClass(t) : o.removeClass(t) }) }) : this }, scrollTop: function (t) { if (this.length) { var n = "scrollTop" in this[0]; return t === e ? n ? this[0].scrollTop : this[0].pageYOffset : this.each(n ? function () { this.scrollTop = t } : function () { this.scrollTo(this.scrollX, t) }) } }, scrollLeft: function (t) { if (this.length) { var n = "scrollLeft" in this[0]; return t === e ? n ? this[0].scrollLeft : this[0].pageXOffset : this.each(n ? function () { this.scrollLeft = t } : function () { this.scrollTo(t, this.scrollY) }) } }, position: function () { if (this.length) { var t = this[0], e = this.offsetParent(), n = this.offset(), i = g.test(e[0].nodeName) ? { top: 0, left: 0 } : e.offset(); return n.top -= parseFloat(r(t).css("margin-top")) || 0, n.left -= parseFloat(r(t).css("margin-left")) || 0, i.top += parseFloat(r(e[0]).css("border-top-width")) || 0, i.left += parseFloat(r(e[0]).css("border-left-width")) || 0, { top: n.top - i.top, left: n.left - i.left } } }, offsetParent: function () { return this.map(function () { for (var t = this.offsetParent || f.body; t && !g.test(t.nodeName) && "static" == r(t).css("position");)t = t.offsetParent; return t }) } }, r.fn.detach = r.fn.remove, ["width", "height"].forEach(function (t) { var n = t.replace(/./, function (t) { return t[0].toUpperCase() }); r.fn[t] = function (i) { var o, s = this[0]; return i === e ? k(s) ? s["inner" + n] : M(s) ? s.documentElement["scroll" + n] : (o = this.offset()) && o[t] : this.each(function (e) { s = r(this), s.css(t, Y(this, i, e, s[t]())) }) } }), x.forEach(function (n, i) { var o = i % 2; r.fn[n] = function () { var n, a, s = r.map(arguments, function (t) { var i = []; return n = $(t), "array" == n ? (t.forEach(function (t) { return t.nodeType !== e ? i.push(t) : r.zepto.isZ(t) ? i = i.concat(t.get()) : void (i = i.concat(N.fragment(t))) }), i) : "object" == n || null == t ? t : N.fragment(t) }), u = this.length > 1; return s.length < 1 ? this : this.each(function (e, n) { a = o ? n : n.parentNode, n = 0 == i ? n.nextSibling : 1 == i ? n.firstChild : 2 == i ? n : null; var c = r.contains(f.documentElement, a); s.forEach(function (e) { if (u) e = e.cloneNode(!0); else if (!a) return r(e).remove(); a.insertBefore(e, n), c && tt(e, function (e) { if (!(null == e.nodeName || "SCRIPT" !== e.nodeName.toUpperCase() || e.type && "text/javascript" !== e.type || e.src)) { var n = e.ownerDocument ? e.ownerDocument.defaultView : t; n.eval.call(n, e.innerHTML) } }) }) }) }, r.fn[o ? n + "To" : "insert" + (i ? "Before" : "After")] = function (t) { return r(t)[n](this), this } }), N.Z.prototype = X.prototype = r.fn, N.uniq = P, N.deserializeValue = Q, r.zepto = N, r }(); return t.Zepto = e, void 0 === t.$ && (t.$ = e), function (e) { function h(t) { return t._zid || (t._zid = n++) } function p(t, e, n, r) { if (e = d(e), e.ns) var i = m(e.ns); return (a[h(t)] || []).filter(function (t) { return t && (!e.e || t.e == e.e) && (!e.ns || i.test(t.ns)) && (!n || h(t.fn) === h(n)) && (!r || t.sel == r) }) } function d(t) { var e = ("" + t).split("."); return { e: e[0], ns: e.slice(1).sort().join(" ") } } function m(t) { return new RegExp("(?:^| )" + t.replace(" ", " .* ?") + "(?: |$)") } function g(t, e) { return t.del && !f && t.e in c || !!e } function v(t) { return l[t] || f && c[t] || t } function y(t, n, i, o, s, u, f) { var c = h(t), p = a[c] || (a[c] = []); n.split(/\s/).forEach(function (n) { if ("ready" == n) return e(document).ready(i); var a = d(n); a.fn = i, a.sel = s, a.e in l && (i = function (t) { var n = t.relatedTarget; return !n || n !== this && !e.contains(this, n) ? a.fn.apply(this, arguments) : void 0 }), a.del = u; var c = u || i; a.proxy = function (e) { if (e = T(e), !e.isImmediatePropagationStopped()) { e.data = o; var n = c.apply(t, e._args == r ? [e] : [e].concat(e._args)); return n === !1 && (e.preventDefault(), e.stopPropagation()), n } }, a.i = p.length, p.push(a), "addEventListener" in t && t.addEventListener(v(a.e), a.proxy, g(a, f)) }) } function x(t, e, n, r, i) { var o = h(t); (e || "").split(/\s/).forEach(function (e) { p(t, e, n, r).forEach(function (e) { delete a[o][e.i], "removeEventListener" in t && t.removeEventListener(v(e.e), e.proxy, g(e, i)) }) }) } function T(t, n) { return (n || !t.isDefaultPrevented) && (n || (n = t), e.each(w, function (e, r) { var i = n[e]; t[e] = function () { return this[r] = b, i && i.apply(n, arguments) }, t[r] = E }), t.timeStamp || (t.timeStamp = Date.now()), (n.defaultPrevented !== r ? n.defaultPrevented : "returnValue" in n ? n.returnValue === !1 : n.getPreventDefault && n.getPreventDefault()) && (t.isDefaultPrevented = b)), t } function S(t) { var e, n = { originalEvent: t }; for (e in t) j.test(e) || t[e] === r || (n[e] = t[e]); return T(n, t) } var r, n = 1, i = Array.prototype.slice, o = e.isFunction, s = function (t) { return "string" == typeof t }, a = {}, u = {}, f = "onfocusin" in t, c = { focus: "focusin", blur: "focusout" }, l = { mouseenter: "mouseover", mouseleave: "mouseout" }; u.click = u.mousedown = u.mouseup = u.mousemove = "MouseEvents", e.event = { add: y, remove: x }, e.proxy = function (t, n) { var r = 2 in arguments && i.call(arguments, 2); if (o(t)) { var a = function () { return t.apply(n, r ? r.concat(i.call(arguments)) : arguments) }; return a._zid = h(t), a } if (s(n)) return r ? (r.unshift(t[n], t), e.proxy.apply(null, r)) : e.proxy(t[n], t); throw new TypeError("expected function") }, e.fn.bind = function (t, e, n) { return this.on(t, e, n) }, e.fn.unbind = function (t, e) { return this.off(t, e) }, e.fn.one = function (t, e, n, r) { return this.on(t, e, n, r, 1) }; var b = function () { return !0 }, E = function () { return !1 }, j = /^([A-Z]|returnValue$|layer[XY]$|webkitMovement[XY]$)/, w = { preventDefault: "isDefaultPrevented", stopImmediatePropagation: "isImmediatePropagationStopped", stopPropagation: "isPropagationStopped" }; e.fn.delegate = function (t, e, n) { return this.on(e, t, n) }, e.fn.undelegate = function (t, e, n) { return this.off(e, t, n) }, e.fn.live = function (t, n) { return e(document.body).delegate(this.selector, t, n), this }, e.fn.die = function (t, n) { return e(document.body).undelegate(this.selector, t, n), this }, e.fn.on = function (t, n, a, u, f) { var c, l, h = this; return t && !s(t) ? (e.each(t, function (t, e) { h.on(t, n, a, e, f) }), h) : (s(n) || o(u) || u === !1 || (u = a, a = n, n = r), (u === r || a === !1) && (u = a, a = r), u === !1 && (u = E), h.each(function (r, o) { f && (c = function (t) { return x(o, t.type, u), u.apply(this, arguments) }), n && (l = function (t) { var r, s = e(t.target).closest(n, o).get(0); return s && s !== o ? (r = e.extend(S(t), { currentTarget: s, liveFired: o }), (c || u).apply(s, [r].concat(i.call(arguments, 1)))) : void 0 }), y(o, t, u, a, n, l || c) })) }, e.fn.off = function (t, n, i) { var a = this; return t && !s(t) ? (e.each(t, function (t, e) { a.off(t, n, e) }), a) : (s(n) || o(i) || i === !1 || (i = n, n = r), i === !1 && (i = E), a.each(function () { x(this, t, i, n) })) }, e.fn.trigger = function (t, n) { return t = s(t) || e.isPlainObject(t) ? e.Event(t) : T(t), t._args = n, this.each(function () { t.type in c && "function" == typeof this[t.type] ? this[t.type]() : "dispatchEvent" in this ? this.dispatchEvent(t) : e(this).triggerHandler(t, n) }) }, e.fn.triggerHandler = function (t, n) { var r, i; return this.each(function (o, a) { r = S(s(t) ? e.Event(t) : t), r._args = n, r.target = a, e.each(p(a, t.type || t), function (t, e) { return i = e.proxy(r), r.isImmediatePropagationStopped() ? !1 : void 0 }) }), i }, "focusin focusout focus blur load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select keydown keypress keyup error".split(" ").forEach(function (t) { e.fn[t] = function (e) { return 0 in arguments ? this.bind(t, e) : this.trigger(t) } }), e.Event = function (t, e) { s(t) || (e = t, t = e.type); var n = document.createEvent(u[t] || "Events"), r = !0; if (e) for (var i in e) "bubbles" == i ? r = !!e[i] : n[i] = e[i]; return n.initEvent(t, r, !0), T(n) } }(e), function (e) { function p(t, n, r) { var i = e.Event(n); return e(t).trigger(i, r), !i.isDefaultPrevented() } function d(t, e, n, i) { return t.global ? p(e || r, n, i) : void 0 } function m(t) { t.global && 0 === e.active++ && d(t, null, "ajaxStart") } function g(t) { t.global && !--e.active && d(t, null, "ajaxStop") } function v(t, e) { var n = e.context; return e.beforeSend.call(n, t, e) === !1 || d(e, n, "ajaxBeforeSend", [t, e]) === !1 ? !1 : void d(e, n, "ajaxSend", [t, e]) } function y(t, e, n, r) { var i = n.context, o = "success"; n.success.call(i, t, o, e), r && r.resolveWith(i, [t, o, e]), d(n, i, "ajaxSuccess", [e, n, t]), b(o, e, n) } function x(t, e, n, r, i) { var o = r.context; r.error.call(o, n, e, t), i && i.rejectWith(o, [n, e, t]), d(r, o, "ajaxError", [n, r, t || e]), b(e, n, r) } function b(t, e, n) { var r = n.context; n.complete.call(r, e, t), d(n, r, "ajaxComplete", [e, n]), g(n) } function E(t, e, n) { if (n.dataFilter == j) return t; var r = n.context; return n.dataFilter.call(r, t, e) } function j() { } function w(t) { return t && (t = t.split(";", 2)[0]), t && (t == c ? "html" : t == f ? "json" : a.test(t) ? "script" : u.test(t) && "xml") || "text" } function T(t, e) { return "" == e ? t : (t + "&" + e).replace(/[&?]{1,2}/, "?") } function S(t) { t.processData && t.data && "string" != e.type(t.data) && (t.data = e.param(t.data, t.traditional)), !t.data || t.type && "GET" != t.type.toUpperCase() && "jsonp" != t.dataType || (t.url = T(t.url, t.data), t.data = void 0) } function C(t, n, r, i) { return e.isFunction(n) && (i = r, r = n, n = void 0), e.isFunction(r) || (i = r, r = void 0), { url: t, data: n, success: r, dataType: i } } function O(t, n, r, i) { var o, s = e.isArray(n), a = e.isPlainObject(n); e.each(n, function (n, u) { o = e.type(u), i && (n = r ? i : i + "[" + (a || "object" == o || "array" == o ? n : "") + "]"), !i && s ? t.add(u.name, u.value) : "array" == o || !r && "object" == o ? O(t, u, r, n) : t.add(n, u) }) } var i, o, n = +new Date, r = t.document, s = /)<[^<]*)*<\/script>/gi, a = /^(?:text|application)\/javascript/i, u = /^(?:text|application)\/xml/i, f = "application/json", c = "text/html", l = /^\s*$/, h = r.createElement("a"); h.href = t.location.href, e.active = 0, e.ajaxJSONP = function (i, o) { if (!("type" in i)) return e.ajax(i); var c, p, s = i.jsonpCallback, a = (e.isFunction(s) ? s() : s) || "Zepto" + n++, u = r.createElement("script"), f = t[a], l = function (t) { e(u).triggerHandler("error", t || "abort") }, h = { abort: l }; return o && o.promise(h), e(u).on("load error", function (n, r) { clearTimeout(p), e(u).off().remove(), "error" != n.type && c ? y(c[0], h, i, o) : x(null, r || "error", h, i, o), t[a] = f, c && e.isFunction(f) && f(c[0]), f = c = void 0 }), v(h, i) === !1 ? (l("abort"), h) : (t[a] = function () { c = arguments }, u.src = i.url.replace(/\?(.+)=\?/, "?$1=" + a), r.head.appendChild(u), i.timeout > 0 && (p = setTimeout(function () { l("timeout") }, i.timeout)), h) }, e.ajaxSettings = { type: "GET", beforeSend: j, success: j, error: j, complete: j, context: null, global: !0, xhr: function () { return new t.XMLHttpRequest }, accepts: { script: "text/javascript, application/javascript, application/x-javascript", json: f, xml: "application/xml, text/xml", html: c, text: "text/plain" }, crossDomain: !1, timeout: 0, processData: !0, cache: !0, dataFilter: j }, e.ajax = function (n) { var u, f, s = e.extend({}, n || {}), a = e.Deferred && e.Deferred(); for (i in e.ajaxSettings) void 0 === s[i] && (s[i] = e.ajaxSettings[i]); m(s), s.crossDomain || (u = r.createElement("a"), u.href = s.url, u.href = u.href, s.crossDomain = h.protocol + "//" + h.host != u.protocol + "//" + u.host), s.url || (s.url = t.location.toString()), (f = s.url.indexOf("#")) > -1 && (s.url = s.url.slice(0, f)), S(s); var c = s.dataType, p = /\?.+=\?/.test(s.url); if (p && (c = "jsonp"), s.cache !== !1 && (n && n.cache === !0 || "script" != c && "jsonp" != c) || (s.url = T(s.url, "_=" + Date.now())), "jsonp" == c) return p || (s.url = T(s.url, s.jsonp ? s.jsonp + "=?" : s.jsonp === !1 ? "" : "callback=?")), e.ajaxJSONP(s, a); var P, d = s.accepts[c], g = {}, b = function (t, e) { g[t.toLowerCase()] = [t, e] }, C = /^([\w-]+:)\/\//.test(s.url) ? RegExp.$1 : t.location.protocol, N = s.xhr(), O = N.setRequestHeader; if (a && a.promise(N), s.crossDomain || b("X-Requested-With", "XMLHttpRequest"), b("Accept", d || "*/*"), (d = s.mimeType || d) && (d.indexOf(",") > -1 && (d = d.split(",", 2)[0]), N.overrideMimeType && N.overrideMimeType(d)), (s.contentType || s.contentType !== !1 && s.data && "GET" != s.type.toUpperCase()) && b("Content-Type", s.contentType || "application/x-www-form-urlencoded"), s.headers) for (o in s.headers) b(o, s.headers[o]); if (N.setRequestHeader = b, N.onreadystatechange = function () { if (4 == N.readyState) { N.onreadystatechange = j, clearTimeout(P); var t, n = !1; if (N.status >= 200 && N.status < 300 || 304 == N.status || 0 == N.status && "file:" == C) { if (c = c || w(s.mimeType || N.getResponseHeader("content-type")), "arraybuffer" == N.responseType || "blob" == N.responseType) t = N.response; else { t = N.responseText; try { t = E(t, c, s), "script" == c ? (1, eval)(t) : "xml" == c ? t = N.responseXML : "json" == c && (t = l.test(t) ? null : e.parseJSON(t)) } catch (r) { n = r } if (n) return x(n, "parsererror", N, s, a) } y(t, N, s, a) } else x(N.statusText || null, N.status ? "error" : "abort", N, s, a) } }, v(N, s) === !1) return N.abort(), x(null, "abort", N, s, a), N; var A = "async" in s ? s.async : !0; if (N.open(s.type, s.url, A, s.username, s.password), s.xhrFields) for (o in s.xhrFields) N[o] = s.xhrFields[o]; for (o in g) O.apply(N, g[o]); return s.timeout > 0 && (P = setTimeout(function () { N.onreadystatechange = j, N.abort(), x(null, "timeout", N, s, a) }, s.timeout)), N.send(s.data ? s.data : null), N }, e.get = function () { return e.ajax(C.apply(null, arguments)) }, e.post = function () { var t = C.apply(null, arguments); return t.type = "POST", e.ajax(t) }, e.getJSON = function () { var t = C.apply(null, arguments); return t.dataType = "json", e.ajax(t) }, e.fn.load = function (t, n, r) { if (!this.length) return this; var a, i = this, o = t.split(/\s/), u = C(t, n, r), f = u.success; return o.length > 1 && (u.url = o[0], a = o[1]), u.success = function (t) { i.html(a ? e("
").html(t.replace(s, "")).find(a) : t), f && f.apply(i, arguments) }, e.ajax(u), this }; var N = encodeURIComponent; e.param = function (t, n) { var r = []; return r.add = function (t, n) { e.isFunction(n) && (n = n()), null == n && (n = ""), this.push(N(t) + "=" + N(n)) }, O(r, t, n), r.join("&").replace(/%20/g, "+") } }(e), function (t) { t.fn.serializeArray = function () { var e, n, r = [], i = function (t) { return t.forEach ? t.forEach(i) : void r.push({ name: e, value: t }) }; return this[0] && t.each(this[0].elements, function (r, o) { n = o.type, e = o.name, e && "fieldset" != o.nodeName.toLowerCase() && !o.disabled && "submit" != n && "reset" != n && "button" != n && "file" != n && ("radio" != n && "checkbox" != n || o.checked) && i(t(o).val()) }), r }, t.fn.serialize = function () { var t = []; return this.serializeArray().forEach(function (e) { t.push(encodeURIComponent(e.name) + "=" + encodeURIComponent(e.value)) }), t.join("&") }, t.fn.submit = function (e) { if (0 in arguments) this.bind("submit", e); else if (this.length) { var n = t.Event("submit"); this.eq(0).trigger(n), n.isDefaultPrevented() || this.get(0).submit() } return this } }(e), function () { try { getComputedStyle(void 0) } catch (e) { var n = getComputedStyle; t.getComputedStyle = function (t, e) { try { return n(t, e) } catch (r) { return null } } } }(), e }); -------------------------------------------------------------------------------- /test/html/body.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 【hello】什么意思_英语hello的翻译_音标_读音_用法_例句_在线翻译_有道词典 15 | 16 | 17 | 18 | 19 | 21 | 22 | 24 | 25 | 26 | 27 | 28 | 29 |
30 |
31 |
32 | 40 |
41 | 42 | 43 | 46 |
47 |
48 |
49 | 50 |
51 |
52 | 中英 53 | 54 |
55 | 56 | 58 | 59 | 60 | 61 | 62 |
63 |
64 |
65 | 66 | 67 | 68 | 69 |
70 |
71 |
72 |
73 |
74 |
75 | 88 |
89 |
90 | 当前查询结果是否对您有帮助 91 |
92 |
93 | 97 | 100 |
101 |
102 | go top 103 |
104 | 105 |
106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 |
115 |

116 | hello 117 |
118 | 英 119 | [həˈləʊ] 120 | 122 | 123 | 美 124 | [helˈō] 125 | 127 | 128 |
129 |

130 |
131 | 132 |
    133 |
  • int. 喂;哈罗
  • 134 |
  • n. 表示问候, 惊奇或唤起注意时的用语
  • 135 |
  • n. (Hello)人名;(法)埃洛
  • 136 |
137 |

[ 138 | 复数 139 | hellos或helloes 140 | 过去式 141 | helloed 142 | 过去分词 143 | helloed 144 | 现在分词 145 | helloing 146 | ]

147 |
148 |
149 | 150 | 151 | 152 | 153 | 154 |
155 |

156 | 157 | 158 | 159 | 160 | 网络释义英英释义 161 | 162 | 163 |

164 | 165 | 166 |
167 |
168 | 169 | 170 |
171 |
172 |   173 | 174 | 你好 175 |
176 |

177 | ...月一次都没赢的记实,当然,斗地主单靠技术没有任何用处(Usefulness),斗地主(Landlords)这款游戏完全就是赌博,上天对你好(Hello)即使技术比不过超级高手,你还是会赢…… 178 |

179 |

基于1195个网页-相关网页

182 |
183 |
184 |
185 |   186 | 187 | 您好 188 |
189 |

190 | 我只是问下,是不是有这么个规定(Provision)Nikco: 您好(Hello),如果(If)联赛的盘口出现错误,我们是会取消该赛事的投注的是的,身份证: 191 | 我没有说盘口的缺点是的,身份证(ID): 就是说原来甲级...

192 |

基于733个网页-相关网页

195 |
196 |
197 |
198 |   199 | 200 | 哈啰 201 |
202 |

203 | 中国好声音金池曾遭车祸 金池台湾老公资料 金池生活照曝光 金池,歌声里有十年的音乐故事。 ... Against All Odds(不计成败) Hello哈啰) 204 | Remember The Time(铭记此刻) ...

205 |

基于292个网页-相关网页

208 |
209 |
210 |
211 |   212 | 213 | 喂 214 |
215 |

216 | Hello,哈罗) Hello是英语中颇具代表性的招呼语,也是在国外打电话时的通用语。

217 |

基于152个网页-相关网页

220 |
221 |
222 |
短语
223 |

224 | 225 | Hello Kitty 227 | 凯蒂猫 228 | ; 229 | 昵称 230 | ; 231 | 匿称 232 | ; 233 | 最想当的商品代言人 234 |

235 |

236 | 237 | Hello Bebe 239 | 哈乐哈乐 240 | ; 241 | 乐扣乐扣 242 |

243 |

244 | 245 | Hello Android 247 | 创建 248 | ; 249 | 创立 250 | ; 251 | 建立 252 |

253 |

254 | 255 | Hello English 257 | 新纪元小学英语 258 | ; 259 | 学英语 260 | ; 261 | 律动欢唱学英语 262 | ; 263 | 海勒国际英语 264 |

265 |

266 | 267 | Hello Schoolgirl 269 | 纯情漫画 270 | ; 271 | 纯真漫画 272 | ; 273 | 韩国唯美爱情故事 274 |

275 |

276 | 277 | Hello Yellow 279 | 浅草黄 280 | ; 281 | 这草黄色 282 |

283 |

284 | 285 | Hello Franceska 287 | 绋兰西斯卡 288 |

289 |

290 | 291 | Hello Booky 293 | 布奇乐乐园 294 |

295 |

296 | 297 | Hello Murder 299 | 愉快的杀人者 300 |

301 | 302 |
 更多收起网络短语
304 |
305 |
306 |
307 |
308 | 309 |

310 | hello 311 | [ he'ləu, hə- ] 312 |

313 |
    314 | 315 | 316 |
  • 317 | n. 318 | 319 | 320 | an expression of greeting 321 | 322 | 323 |

    "every morning they exchanged polite hellos"

    324 | 325 |

    同义词: 326 | hullo 327 | hi 328 | howdy 329 | how-do-you-do 330 |

    331 |
  • 332 |
333 |

334 | 以上来源于: 335 | WordNet 337 |

338 | 339 |
340 |
341 |
342 |
343 | 344 |
345 |
346 | 347 |
348 |

349 | 350 | 相关文章 351 | 352 | 353 |

354 |
355 |
356 | 357 |
358 |

359 | 360 | 21世纪大英汉词典 柯林斯英汉双解大词典  362 | 363 | 364 |

365 |
366 | 367 | 368 |
369 | 370 |

371 | hello 372 | [he'ləu; hə-] 373 |

374 | 375 | 376 |
    377 | 378 | 379 | 380 | 381 |
  • 382 | interj. 383 |
      384 | 385 |
    • 386 | [表示问候、用以唤起别人注意或打电话时的招呼语]喂,哈啰 387 | 388 | 389 | 390 | 391 |
    • 392 |
    • 393 | [表示惊讶、得意等]嘿 394 | 395 | 396 | 397 | 398 |
    • 399 |
    400 |
  • 401 |
  • 402 | n. 403 |
      404 |
    • “喂”的招呼声,表示问候的叫声;打招呼
    • 405 | 406 | 407 | 408 | 409 | 410 |
    411 |
  • 412 |
  • 413 | vi. 414 |
      415 |
    • 发“喂”的喊声,大声招呼,呼唤:
    • 416 | 417 |
    • 418 | 发“喂”的喊声,大声招呼,呼唤: 419 | 420 |

      It surprised me that she was helloing at me when I passed her on the way 421 | to my office.

      422 |

      她在我去办公室的路上向我打招呼,这一点令我感到奇怪。

      423 | 424 | 425 | 426 |
    • 427 |
    428 |
  • 429 |
  • 430 | vt. 431 |
      432 |
    • 向…喊“喂”,向…打招呼:
    • 433 | 434 |
    • 435 | 向…喊“喂”,向…打招呼: 436 | 437 |

      He told me that I would not hello the manager if he hadn't helloed me. 438 |

      439 |

      他告诉我,如果经理不向我招呼,我就不应向他问好。

      440 | 441 | 442 |
    • 443 |
    444 |
  • 445 | 446 | 447 | 448 |
  • 449 | 461 |
  • 462 | 463 | 464 |
465 | 466 | 467 |
  468 | 更多收起结果 469 |
470 |
471 | 以上来源于:《21世纪大英汉词典》 472 |
473 |
474 |
475 |
476 |
477 |
478 |
479 |

480 | hello 481 | /hɛˈləʊ/ 482 | 483 | (also hullo) 484 | 485 | CET4 TEM4 486 | 487 | ( 488 | hellos 489 | ) 490 | 491 |

492 | 493 | 494 | 495 | 496 | 497 | 498 |
    499 | 500 |
  • 501 |
    502 | 1.  503 |

    504 | CONVENTION 505 | You say "Hello" to someone when you meet them. 你好 (打招呼用语) 506 | 507 | [套语] 508 |

    509 |
    510 |
    511 | 例: 512 |
    513 |

    Hello, Trish. I won't shake hands, because I'm filthy.

    514 |

    你好,特里斯。我就不握手了,我的手好脏。

    515 |
    516 |
    517 |
  • 518 | 519 |
  • 520 |
    521 | 2.  522 |

    523 | N-COUNT 524 | Hello is also a noun. 招呼 525 | 526 |

    527 |
    528 |
    529 | 例: 530 |
    531 |

    The salesperson greeted me with a warm hello.

    532 |

    那位推销员向我打了个热情的招呼。

    533 |
    534 |
    535 |
  • 536 | 537 |
  • 538 |
    539 | 3.  540 |

    541 | CONVENTION 542 | You say "Hello" to someone at the beginning of a telephone conversation, either 543 | when you answer the phone or before you give your name or say why you are phoning. 喂 544 | (打电话时的招呼语) 545 | 546 | [套语] 547 |

    548 |
    549 |
    550 | 例: 551 |
    552 |

    A moment later, Cohen picked up the phone. "Hello?"

    553 |

    一会儿之后,科恩拿起电话。“喂?”

    554 |
    555 |
    556 |
  • 557 | 558 |
  • 559 |
    560 | 4.  561 |

    562 | CONVENTION 563 | You can call "hello" to attract someone's attention. 喂 (用于唤起别人注意) 564 | 565 |

    566 |
    567 |
    568 | 例: 569 |
    570 |

    Very softly, she called out: "Hello? Who's there?"

    571 |

    她很轻柔地喊道:“喂?谁在那儿?”

    572 |
    573 |
    574 |
  • 575 |
576 |
577 |
578 |
579 |
580 |
581 |
582 |
583 |
584 |

585 | 586 | 词组短语同近义词 587 | 588 | 589 |

590 |
591 |
592 |

593 | say hello 595 | 打招呼;问好 596 |

597 |

598 | hello everyone 600 | 大家好 601 |

602 |

603 | hello and welcome 605 | 欢迎莅临 606 |

607 |

608 | hello again 610 | 回魂妻(电影名称) 611 |

612 |
613 |
614 |
    615 |
  • int. 喂;哈罗
  • 616 |

    617 | 618 | hallo 619 | , 620 | 621 | 622 | holloo 623 | 624 |

    625 |
626 |
627 |
628 |
629 | 630 | 631 |
632 |

633 | 634 | 双语例句原声例句权威例句 636 | 637 | 638 |

639 |
640 |
641 |
    642 | 643 | 644 |
  • 645 |

    Hello, who's speaking, please? 651 | 653 |

    654 | 655 |

    请问你是呀? 661 |

    662 |

    663 | 《新英汉大辞典》 664 |

    665 |
  • 666 | 667 | 668 |
  • 669 |

    The American walked to a telephone booth,"Hello. Is that the bank? 682 | 685 |

    686 | 687 |

    那个美国人公用电话间旁打电话:",银行吗? 701 |

    702 |

    703 | www.englishtang.com 705 |

    706 |
  • 707 | 708 | 709 |
  • 710 |

    She never passes without stopping to say hello. 720 | 723 |

    724 | 725 |

    从这儿经过没有一次停下来问候一番。 737 |

    738 |

    739 | dj.iciba.com 740 |

    741 |
  • 742 |
743 | 更多双语例句 745 |
746 | 747 | 748 |
749 | 750 |
    751 | 752 |
  • 753 |

    And see? I'm close enough to say, 'Hello, good looking!'" Actress Betty Furness was 754 | commercial spokeswoman for Westinghouse. 755 | 758 |

    759 |

    760 | VOA: special.2011.07.21 761 |

    762 |
  • 763 | 764 | 765 | 766 |
  • 767 |

    So if you haven't already, just glance at the person next to you, or say hello if you 768 | don't know them.

    769 |

    如果你还没有做好,那就看看你旁边的人,如果你不认识他们就跟他们打个招呼。

    770 | 771 |
    772 | 774 | 哈佛公开课中出现hello的视频截图 776 | 778 | 779 | 780 |
    781 |

    哈佛公开课 - 计算机科学课程节选

    783 |
  • 784 | 785 | 786 |
  • 787 |

    But I think the more you meet people, here it's, the more you say hello, the more it's 788 | familiar.

    789 |

    但我想,你见的人越多,你说的“你好”越多,你就会越发熟悉这一切的。

    790 | 791 |
    792 | 794 | 和纽约的留学生中出现hello的视频截图 796 | 798 | 799 | 800 |
    801 |

    和纽约的留学生 - SpeakingMax英语口语达人

    803 |
  • 804 |
805 | 更多原声例句 807 |
808 | 809 | 810 |
811 | 843 | 更多权威例句 845 |
846 |
847 |
848 | 849 | 850 |
851 |
852 | 853 | 854 |
855 |
856 |

词组短语

857 |
858 |

859 | say hello 861 | 打招呼;问好 862 |

863 |

864 | hello everyone 866 | 大家好 867 |

868 |

869 | hello and welcome 871 | 欢迎莅临 872 |

873 |

874 | hello again 876 | 回魂妻(电影名称) 877 |

878 |
879 |
880 |
881 | 882 | 888 |
889 | 890 | 899 |
900 |
901 |
902 | $firstVoiceSent 903 |
- 来自原声例句
904 |
905 |
906 |
907 |
908 |
909 |
910 | 911 | 912 | 927 |
928 |
929 | 935 |
936 | 937 | 945 | 946 |
947 |
小调查
948 |
949 | 请问您想要如何调整此模块? 950 |

951 |

952 |

953 |
感谢您的反馈,我们会尽快进行适当修改!
954 | 进来说说原因吧 956 | 确定 957 |
958 |
959 | 960 |
961 |
小调查
962 |
963 | 请问您想要如何调整此模块? 964 |

965 |

966 |

967 |
感谢您的反馈,我们会尽快进行适当修改!
968 | 进来说说原因吧 970 | 确定 971 |
972 |
973 | 974 | 994 | 995 | 996 | 1019 | 1020 | 1021 | 1027 | 1028 | 1029 | 1030 | 1034 | 1035 | 1036 | 1037 | --------------------------------------------------------------------------------