From 1b083a900c7517f4ccb6ba683c2956dc3511ccf7 Mon Sep 17 00:00:00 2001 From: Jb Landry Date: Fri, 24 Mar 2017 16:36:57 -0400 Subject: [PATCH] Initial --- .editorconfig | 22 +++ .eslintrc.yaml | 351 +++++++++++++++++++++++++++++++++++++ .gitignore | 1 + .npmignore | 7 + .sublimelinterrc | 10 ++ .travis.yml | 3 + cli-helper.sublime-project | 21 +++ index.js | 160 +++++++++++++++++ license | 21 +++ package.json | 29 +++ readme.md | 11 ++ test/.eslintrc.yaml | 5 + test/index.js | 8 + 13 files changed, 649 insertions(+) create mode 100644 .editorconfig create mode 100644 .eslintrc.yaml create mode 100644 .gitignore create mode 100644 .npmignore create mode 100644 .sublimelinterrc create mode 100644 .travis.yml create mode 100644 cli-helper.sublime-project create mode 100644 index.js create mode 100644 license create mode 100644 package.json create mode 100644 readme.md create mode 100644 test/.eslintrc.yaml create mode 100644 test/index.js diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..15fa769 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,22 @@ +# http://editorconfig.org + +root = true + +[*.js] +indent_style = tab +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +indent_style = tab +charset = utf-8 +trim_trailing_whitespace = false +insert_final_newline = true + +[{.editorconfig,.gitignore,.npmignore,package.json,.travis.yml}] +indent_style = space +indent_size = 2 +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true diff --git a/.eslintrc.yaml b/.eslintrc.yaml new file mode 100644 index 0000000..fb4d590 --- /dev/null +++ b/.eslintrc.yaml @@ -0,0 +1,351 @@ +# http://eslint.org/docs/rules/ + +# Extends - Extend other config +# extends: + + +# Parser Options +root: true +parser: espree +parserOptions: + ecmaVersion: 2017 + sourceType: script + ecmaFeatures: + globalReturn: false + impliedStrict: false + jsx: false + experimentalObjectRestSpread: true + + +# Environments +env: + es6: true + node: true + + +# Globals +globals: [] + + +# Plugins - Additional plugins +# plugins: + + +# Settings - Shared Settings +# settings: + + +# Rules +rules: + + # Possible Errors + no-await-in-loop: [error] + no-compare-neg-zero: [error] + no-cond-assign: [error, always] + no-console: [warn] + no-constant-condition: [error] + no-control-regex: [error] + no-debugger: [warn] + no-dupe-args: [error] + no-dupe-keys: [error] + no-duplicate-case: [error] + no-empty-character-class: [error] + no-empty: [error, {allowEmptyCatch: false}] + no-ex-assign: [error] + no-extra-boolean-cast: [error] + no-extra-parens: [error, all, {nestedBinaryExpressions: false, ignoreJSX: 'all'}] + no-extra-semi: [error] + no-func-assign: [error] + no-inner-declarations: [error, both] + no-invalid-regexp: [error] + no-irregular-whitespace: [error] + no-obj-calls: [error] + no-prototype-builtins: [error] + no-regex-spaces: [error] + no-sparse-arrays: [error] + no-template-curly-in-string: [error] + no-unexpected-multiline: [error] + no-unreachable: [error] + no-unsafe-finally: [error] + no-unsafe-negation: [error] + use-isnan: [error] + valid-jsdoc: [off] + valid-typeof: [error, {requireStringLiterals: true}] + + + # Best Practices + accessor-pairs: [error, {setWithoutGet: true, getWithoutSet: true}] + array-callback-return: [error] + block-scoped-var: [error] + class-methods-use-this: [error] + complexity: [off] + consistent-return: [error] + curly: [error, all] + default-case: [error] + dot-location: [error, property] + dot-notation: [error, {allowKeywords: true}] + eqeqeq: [error, always] + guard-for-in: [error] + no-alert: [warn] + no-caller: [error] + no-case-declarations: [error] + no-div-regex: [error] + no-else-return: [error] + no-empty-function: [error] + no-empty-pattern: [error] + no-eq-null: [error] + no-eval: [error] + no-extend-native: [error] + no-extra-bind: [error] + no-extra-label: [error] + no-fallthrough: [error] + no-floating-decimal: [error] + no-global-assign: [error] + no-implicit-coercion: [error] + no-implicit-globals: [error] + no-implied-eval: [error] + no-invalid-this: [off] + no-iterator: [error] + no-labels: [error] + no-lone-blocks: [error] + no-loop-func: [error] + no-magic-numbers: [off] + no-multi-spaces: [off] + no-multi-str: [error] + no-new-func: [error] + no-new-wrappers: [error] + no-new: [error] + no-octal-escape: [error] + no-octal: [error] + no-param-reassign: [error] + no-proto: [error] + no-redeclare: [error, {builtinGlobals: true}] + no-return-assign: [error, always] + no-return-await: [error] + no-script-url: [error] + no-self-assign: [error, {props: true}] + no-self-compare: [error] + no-sequences: [error] + no-throw-literal: [error] + no-unmodified-loop-condition: [error] + no-unused-expressions: [error] + no-unused-labels: [error] + no-useless-call: [error] + no-useless-concat: [error] + no-useless-escape: [error] + no-useless-return: [error] + no-void: [error] + no-warning-comments: [warn, {location: anywhere}] + no-with: [error] + prefer-promise-reject-errors: [error] + radix: [error, always] + require-await: [error] + vars-on-top: [error] + wrap-iife: [error, inside, {functionPrototypeMethods: true}] + yoda: [error, never] + + + # Strict Mode + strict: [error, global] + + + # Variables + init-declarations: [off] + no-catch-shadow: [error] + no-delete-var: [error] + no-label-var: [error] + no-restricted-globals: [error, window] + no-shadow-restricted-names: [error] + no-shadow: [error, {builtinGlobals: false, hoist: all}] + no-undef-init: [error] + no-undef: [error] + no-undefined: [off] + no-unused-vars: [error] + no-use-before-define: [error] + + + # Node.js and CommonJS + callback-return: [error] + global-require: [error] + handle-callback-err: [error] + no-mixed-requires: [error] + no-new-require: [error] + no-path-concat: [error] + no-process-env: [error] + no-process-exit: [error] + no-restricted-modules: [off] + no-restricted-properties: [off] + no-sync: [off] + + + # Stylistic Issues + array-bracket-spacing: [error, never] + block-spacing: [error, always] + brace-style: [error, 1tbs, {allowSingleLine: true}] + camelcase: [error, {properties: always}] + capitalized-comments: [off] + comma-dangle: [error, never] #always-multiline + comma-spacing: [error, {before: false, after: true}] + comma-style: [error, last] + computed-property-spacing: [error, never] + consistent-this: [error, self] + eol-last: [error, always] + func-call-spacing: [error, never] + func-name-matching: [error] + func-names: [error, never] + func-style: [error, expression] + id-blacklist: [off] + id-length: [off] + id-match: [off] + indent: [error, tab, {SwitchCase: 1, VariableDeclarator: 1, outerIIFEBody: 1, CallExpression: {arguments: 1}, ArrayExpression: 1, ObjectExpression: 1}] + jsx-quotes: [error, prefer-double] + key-spacing: + - error + - singleLine: + beforeColon: false + afterColon: false + multiLine: + beforeColon: false + afterColon: true + align: + beforeColon: false + afterColon: true + on: value + mode: minimum + keyword-spacing: [error, {before: true, after: true}] + line-comment-position: [off] + linebreak-style: [error, unix] + lines-around-comment: [error, {beforeBlockComment: true, afterBlockComment: false, beforeLineComment: false, afterLineComment: false}] + lines-around-directive: [error, {before: never, after: always}] + max-depth: [off] + max-len: [off] + max-lines: [off] + max-nested-callbacks: [off] + max-params: [off] + max-statements-per-line: [error, {max: 2}] + max-statements: [off] + multiline-ternary: [off] + new-cap: [error, {newIsCap: true, capIsNew: true, properties: false}] + new-parens: [error] + newline-after-var: [off] + newline-before-return: [error] + newline-per-chained-call: [off] + no-array-constructor: [error] + no-bitwise: [error] + no-continue: [error] + no-inline-comments: [off] + no-lonely-if: [error] + no-mixed-operators: [error, {allowSamePrecedence: true}] + no-mixed-spaces-and-tabs: [error] + no-multi-assign: [error] + no-multiple-empty-lines: [error, {max: 100, maxEOF: 1, maxBOF: 0}] + no-negated-condition: [off] + no-nested-ternary: [off] + no-new-object: [error] + no-plusplus: [off] + no-restricted-syntax: [off] + no-tabs: [off] + no-ternary: [off] + no-trailing-spaces: [error, {skipBlankLines: false}] + no-underscore-dangle: [off] + no-unneeded-ternary: [error, {defaultAssignment: false}] + no-whitespace-before-property: [error] + nonblock-statement-body-position: [error, beside] + object-curly-newline: [error, {multiline: true, minProperties: 5}] + object-curly-spacing: [error, always] + object-property-newline: [off] + one-var-declaration-per-line: [error, always] + one-var: [error, never] + operator-assignment: [error, always] + operator-linebreak: [error, after, {overrides: {'?': before, ':': before}}] + padded-blocks: [error, {classes: always, switches: always}] + quote-props: [error, consistent-as-needed, {keywords: true}] + quotes: [error, single, {avoidEscape: true, allowTemplateLiterals: true}] + require-jsdoc: [off] # toco:chceck + semi-spacing: [error, {before: false, after: true}] + semi: [error, always] + sort-keys: [off] + sort-vars: [off] + space-before-blocks: [error, always] + space-before-function-paren: [error, never] + space-in-parens: [error, never] + space-infix-ops: [error, {int32Hint: false}] + space-unary-ops: [error, {words: true, nonwords: false}] + spaced-comment: + - error + - always + - exceptions: ['-', '*'] + markers: ['=', '--'] + block: + balanced: true + template-tag-spacing: [error, never] + unicode-bom: [error, never] + wrap-regex: [error] + + + # ECMAScript 6 + arrow-body-style: [error, always] + arrow-parens: [error, always] + arrow-spacing: [error, {before: true, after: true}] + constructor-super: [error] + generator-star-spacing: [error, before] + no-class-assign: [error] + no-confusing-arrow: [error] + no-const-assign: [error] + no-dupe-class-members: [error] + no-duplicate-imports: [error] + no-new-symbol: [error] + no-restricted-imports: + - error + - assert + - buffer + - child_process + - cluster + - crypto + - dgram + - dns + - domain + - events + - freelist + - fs + - http + - https + - module + - net + - os + - path + - punycode + - querystring + - readline + - repl + - smalloc + - stream + - string_decoder + - sys + - timers + - tls + - tracing + - tty + - url + - util + - vm + - zlib + no-this-before-super: [error] + no-useless-computed-key: [error] + no-useless-constructor: [error] + no-useless-rename: [error] + no-var: [error] + object-shorthand: [error, consistent] + prefer-arrow-callback: [error] + prefer-const: [error, {destructuring: any, ignoreReadBeforeAssign: false}] + prefer-destructuring: [error, {array: true, object: true}, {enforceForRenamedProperties: false}] + prefer-numeric-literals: [error] + prefer-rest-params: [error] + prefer-spread: [error] + prefer-template: [error] + require-yield: [error] + rest-spread-spacing: [error, never] + symbol-description: [error] + sort-imports: [off] + template-curly-spacing: [error, never] + yield-star-spacing: [error, before] diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3c3629e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..14f267e --- /dev/null +++ b/.npmignore @@ -0,0 +1,7 @@ +test +.editorconfig +.eslintrc.yaml +.gitignore +.sublimelinterrc +.travis.yml +cli-helper.sublime-project diff --git a/.sublimelinterrc b/.sublimelinterrc new file mode 100644 index 0000000..fe03e4f --- /dev/null +++ b/.sublimelinterrc @@ -0,0 +1,10 @@ +{ + "linters": { + "jshint": { + "@disable": true + }, + "jscs": { + "@disable": true + } + } +} diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..e11f993 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,3 @@ +language: node_js +node_js: + - "7.7.3" diff --git a/cli-helper.sublime-project b/cli-helper.sublime-project new file mode 100644 index 0000000..1b62a1e --- /dev/null +++ b/cli-helper.sublime-project @@ -0,0 +1,21 @@ +{ + "folders": + [ + { + "follow_symlinks": true, + "path": ".", + "folder_exclude_patterns": [ + "node_modules" + ], + "file_exclude_patterns": [ + "*.sublime-project", + ".editorconfig", + ".eslintrc.yaml", + ".gitignore", + ".npmignore", + ".sublimelinterrc", + ".travis.yml" + ] + } + ] +} diff --git a/index.js b/index.js new file mode 100644 index 0000000..e5eb045 --- /dev/null +++ b/index.js @@ -0,0 +1,160 @@ +//-------------------------------------------------------- +//-- CLI helper +//-------------------------------------------------------- +'use strict'; + +const echo = console.log; // eslint-disable-line no-console + +const os = require('os'); +const path = require('path'); +const readPkgUp = require('read-pkg-up'); +const chalk = require('chalk'); +const pad = require('pad'); + +delete require.cache[__filename]; +const pkgPath = path.dirname(module.parent.filename); +const { pkg } = readPkgUp.sync({ cwd:pkgPath }); + + + + + + +//-- Static properties +const STATIC = global.___AbsolunetCLIHelper___ ? global.___AbsolunetCLIHelper___ : global.___AbsolunetCLIHelper___ = { + commands: {}, + taskWidth: {}, + fullUsage: {}, + baseWidth: 0 +}; + + +//-- Command usage +const printCmd = (cmd, width = STATIC.baseWidth, spacer = 1) => { + const [task, subtask] = cmd.split(' '); + const [name, desc, delta = 0] = subtask ? STATIC.commands[task][subtask] : STATIC.commands[task]; + + return `${pad(chalk.yellow(name), width + delta)}${' '.repeat(spacer)}${desc}`; +}; + + + + + + + +module.exports = class CLIHelper { + + //-- Usager helpers + static get PLACEHOLDER() { + return 10; + } + + static get OPTIONALPLACEHOLDER() { + return 26; + } + + static get placeholder() { + return chalk.green; + } + + static optionalPlaceholder(name) { + return `${chalk.reset('[')}${CLIHelper.placeholder(name)}${chalk.reset(']')}`; + } + + + //-- Set tasks + static setUsageTasks(commands, taskWidth) { + STATIC.commands = commands; + STATIC.taskWidth = taskWidth; + } + + + //-- Set full usage + static setFullUsage(fullUsage, baseWidth) { + STATIC.fullUsage = fullUsage; + STATIC.baseWidth = baseWidth; + } + + + //-- Get full usage + static get fullUsage() { + let usage = `Usage: ${chalk.yellow(pkg.name)} ${chalk.cyan('')}\n`; + + Object.keys(STATIC.fullUsage).forEach((group) => { + usage += `\n${chalk.underline(group)}\n`; + + STATIC.fullUsage[group].forEach((task) => { + usage += `${printCmd(task)}\n`; + }); + }); + + usage += `\n${pkg.name}@${pkg.version} ${pkgPath}`; + + return usage; + } + + + //-- Get task usage + static getTaskUsage(task) { + const subs = !Array.isArray(STATIC.commands[task]); + + let usage = ` ${chalk.underline('Usage:')}\n`; + if (subs) { + Object.values(STATIC.commands[task]).forEach((item) => { + usage += ` ${chalk.yellow(`${pkg.name} ${task}`)} ${printCmd(`${task} ${item[0]}`, STATIC.taskWidth[task])}\n`; + }); + } else { + usage += ` ${chalk.yellow(pkg.name)} ${printCmd(task, 0, 3)}\n`; + } + + return usage; + } + + + //-- Show task usage and die + static showTaskUsage(cli) { + echo(`\n${CLIHelper.getTaskUsage(cli.input[0])}`); + process.exit(2); // eslint-disable-line no-process-exit + } + + + + + + + //-- Raw arguments + static get rawArguments() { + const args = process.argv.slice(2); + args.shift(); + + return args.join(' '); + } + + //-- Refuse flags + static refuseFlags(cli) { + if (Object.keys(cli.flags).length) { + CLIHelper.showTaskUsage(cli); + } + } + + //-- Refuse flags & arguments + static refuseFlagsAndArguments(cli) { + if (cli.input.length > 1 || Object.keys(cli.flags).length) { + CLIHelper.showTaskUsage(cli); + } + } + + + + + + + //-- Is root + static isRoot() { + const user = os.userInfo(); + + return user.uid === 0 || user.gid === 0 || user.username === 'root'; + } + +}; diff --git a/license b/license new file mode 100644 index 0000000..763d80c --- /dev/null +++ b/license @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2011-2017 Absolunet, http://absolunet.com + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..088755d --- /dev/null +++ b/package.json @@ -0,0 +1,29 @@ + { + "name": "@absolunet/cli-helper", + "version": "0.0.1", + "description": "CLI helper", + "definition": "", + "homepage": "https://github.com/absolunet/cli-helper", + "author": { "name": "Absolunet", "url": "http://absolunet.com/" }, + + "license": "MIT", + "repository": { "url": "git://github.com/absolunet/cli-helper.git", "type":"git" }, + "bugs": { "url": "https://github.com/absolunet/cli-helper/issues" }, + + "engines": { "node": ">= 7.7.3" }, + "scripts": { + "test": "mocha" + }, + + "devDependencies": { + "eslint": "3.18.0", + "mocha": "3.2.0", + "mocha-eslint": "3.0.1" + }, + + "dependencies": { + "chalk": "^1.1.3", + "pad": "^1.1.0", + "read-pkg-up": "^2.0.0" + } +} diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..68e51da --- /dev/null +++ b/readme.md @@ -0,0 +1,11 @@ +# @absolunet/cli-helper + +[![NPM version](https://img.shields.io/npm/v/@absolunet/cli-helper.svg)](https://www.npmjs.com/package/@absolunet/cli-helper) +[![Travis build](https://api.travis-ci.org/absolunet/cli-helper.svg?branch=master)](https://travis-ci.org/absolunet/cli-helper/builds) +[![Dependencies](https://david-dm.org/absolunet/cli-helper/status.svg)](https://david-dm.org/absolunet/cli-helper) +[![Dev dependencies](https://david-dm.org/absolunet/cli-helper/dev-status.svg)](https://david-dm.org/absolunet/cli-helper?type=dev) + +> CLI helper + +## License +See the [license](https://github.com/absolunet/cli-helper/blob/master/license). diff --git a/test/.eslintrc.yaml b/test/.eslintrc.yaml new file mode 100644 index 0000000..4f0dc7c --- /dev/null +++ b/test/.eslintrc.yaml @@ -0,0 +1,5 @@ +# http://eslint.org/docs/rules/ + +# Environments +env: + mocha: true diff --git a/test/index.js b/test/index.js new file mode 100644 index 0000000..4235e70 --- /dev/null +++ b/test/index.js @@ -0,0 +1,8 @@ +//-------------------------------------------------------- +//-- Tests +//-------------------------------------------------------- +'use strict'; + +const lint = require('mocha-eslint'); + +lint(['index.js'], { strict:true });