diff --git a/.doclets.yml b/.doclets.yml new file mode 100644 index 0000000..9562a0b --- /dev/null +++ b/.doclets.yml @@ -0,0 +1,13 @@ +packageJson: package.json + +dir: src + +articles: + - Overview: readme.md + +branches: + - master + - develop + - feature/* + - release/* + - hotfix/* diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..f167c6d --- /dev/null +++ b/.editorconfig @@ -0,0 +1,14 @@ +# editorconfig.org + +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_size = 4 +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true + +[*.{json,yml}] +indent_size = 2 diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..4e0feef --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,144 @@ +module.exports = { + extends : [ + 'eslint:all' + ], + globals : { + 'define': true, + 'module': true, + 'require' : true, + 'console' : true, + + 'Symbol' : true, + + // typed arrays + 'Int8Array' : true, + 'Uint8Array' : true, + 'Uint8ClampedArray' : true, + 'Int16Array' : true, + 'Uint16Array' : true, + 'Int32Array' : true, + 'Uint32Array' : true, + 'Float32Array' : true, + 'Float64Array' : true + }, + 'parserOptions': { + 'ecmaVersion': 5 + }, + rules : { + 'strict': 'off', + 'padded-blocks': 'off', + 'func-names': 'off', + 'no-var' : 'off', + 'sort-vars' : 'off', + 'no-multi-spaces': 'off', + 'init-declarations': 'off', + 'prefer-arrow-callback' : 'off', + 'func-style': 'off', + 'no-plusplus': 'off', + 'no-continue': 'off', + 'no-prototype-builtins': 'off', + 'vars-on-top': 'error', + 'prefer-reflect': 'off', + 'space-unary-ops': 'off', + 'key-spacing' : 'off', + 'callback-return' : 'off', + 'no-implicit-coercion' : 'off', + 'no-negated-condition' : 'off', + 'guard-for-in' : 'off', + 'no-lonely-if' : 'off', + 'no-self-compare': 'off', + 'no-inline-comments' : 'off', + 'lines-around-comment' : 'off', + 'no-underscore-dangle': 'off', + 'no-unused-expressions': 'off', + 'one-var': 'off', + 'indent': 'off', + 'arrow-body-style' : 'off', + 'wrap-regex' : 'off', + 'prefer-spread' : 'off', + 'prefer-rest-params' : 'off', + 'no-invalid-this' : 'off', + 'newline-before-return': 'off', + 'no-console': [ + 'error', { + allow: [ + 'warn', + 'error' + ] + } + ], + 'new-cap': [ + 'error', { + 'newIsCap': false, + 'capIsNew': true, + } + ], + 'comma-dangle' : [ + 'error', 'always-multiline' + ], + 'max-params': [ + 'error', 5 + ], + 'max-lines': [ + 'error', { + 'max' : 999, + 'skipBlankLines' : true, + 'skipComments' : true + } + ], + 'quote-props': [ + 'error', + 'as-needed', { + 'keywords': false + } + ], + 'space-in-parens': 'off', + 'id-length': [ + 'error', { + 'exceptions': [ + 'i', 'j', 'p', 'n', 'x', 'y', 'w', 'e', 'h' + ] + } + ], + 'linebreak-style': [ + 'error', 'unix' + ], + 'complexity': [ + 'error', 50 + ], + 'max-statements': [ + 'error', 40 + ], + 'max-len': [ + 'error', 120, 4 + ], + 'camelcase': [ + 'error', { + 'properties': 'never' + } + ], + 'quotes' : [ + 'error', 'single', { + 'avoidEscape' : true, + 'allowTemplateLiterals' : true + } + ], + 'default-case': [ + 'error', { + 'commentPattern' : '^skip\\sdefault' + } + ], + 'no-magic-numbers': [ + 'error', { + 'ignore' : [-1, 0, 1, 2], + 'ignoreArrayIndexes' : true + } + ], + 'space-before-function-paren': [ + 'error', { + 'anonymous' : 'never', + 'named' : 'never' + } + ] + } +}; diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..7f23c90 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,59 @@ +# General .gitattributes v1.0.0 + +# Auto detect text files and perform LF normalization +* text=auto +* eol=lf + +# These files are text and should be normalized (Convert crlf => lf) +*.php text +*.css text +*.scss text +*.sass text +*.js text +*.htm text +*.html text +*.xml text +*.txt text +*.ini text +*.inc text +.htaccess text + +# These files are binary and should be left untouched +# images +*.png binary +*.jpg binary +*.jpeg binary +*.gif binary +*.ico binary +*.psd binary +*.ai binary + +# fonts +*.ttf binary +*.woff binary +*.woff2 binary +*.eot binary + +# documents +*.pdf binary +*.doc binary +*.docx binary + +# compressed formats +*.zip binary +*.tar binary +*.gz binary +*.rar binary +*.7z binary + +# executables +*.phar binary +*.exe binary + +# media formats +*.mov binary +*.mp4 binary +*.mp3 binary +*.flv binary +*.fla binary +*.swf binary diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..318f6a1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,17 @@ +# IntelliJ project directory +.idea/ + +# Vagrant VM directory +.vagrant/ + +# Node project dependencies +/node_modules/ + +# Code coverage report +/cov/ + +# Logs +/npm-debug.log + +# Required data for publishing project +/.publish.json diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..13c0ea7 --- /dev/null +++ b/.npmignore @@ -0,0 +1,26 @@ +# IntelliJ project directory +/.idea/ + +# Vagrant VM directory +/.vagrant/ + +# coverage directory (for development) +/cov/ + +# scripts directory (for development) +/scripts/ + +# source directory (for development) +/src/ + +# tests directory (for development) +/tests/ + +.doclets.yml +.editorconfig +.eslintrc.js +.gitattributes +.npmignore +.publish.json +.travis.yml +vagrantfile diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..ed89963 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,15 @@ +language: node_js + +node_js: + - stable + - "6" + - "6.1" + - "5" + - "5.1" + - "4" + - "4.2" + - "4.1" + - "4.0" + +script: + - npm run ci diff --git a/dist/js-partial-is-array.js b/dist/js-partial-is-array.js new file mode 100644 index 0000000..d5c5ba7 --- /dev/null +++ b/dist/js-partial-is-array.js @@ -0,0 +1,92 @@ +/* + |---------------------------------------------------------------------------------------------------------------------- + | A partial to check whether an object is an array. + |---------------------------------------------------------------------------------------------------------------------- + */ + +/** + * More information on [JavaScript Open Standards]{@link https://github.com/jsopenstd/jsopenstd}. + * + * @namespace js.partial + * @version 0.0.0 + * + * @author Richard King [GitHub]{@link https://github.com/richrdkng} + * @license [MIT]{@link https://github.com/jsopenstd/js-partial-foreach/blob/master/license.md} + */ + +/** + * UMD - [returnExports.js pattern]{@link https://github.com/umdjs/umd/blob/master/templates/returnExports.js} + * For more information and license, check the link below: + * [UMD GitHub Repository]{@link https://github.com/umdjs/umd} + */ +(function(root, factory) { + // AMD + /* istanbul ignore next: ignore coverage test for UMD */ + if (typeof define === 'function' && define.amd) { + define([], factory); + + // CommonJS + } else if (typeof module === 'object' && module.exports) { + module.exports = factory(); + + // Browser + } else { + root.js_partial_isArray = factory(); + } +}(this, function() { + 'use strict'; + + /** + * Determines whether an object is an array. + * By default it handles **typed arrays and array-likes as non-arrays**. + * + * @function isArray + * @memberOf js.partial + * + * @param {*} object - The object to check. + * @param {boolean} [handleTypedArrayAsArray=false] - Handle a typed array as a regular array too. + * By default a typed array is not classified as a regular array. + * @param {boolean} [handleArrayLikeAsArray=false] - Handle an array-like as a regular array too. + * An array-like is anything, that has a valid .length property + * and behaves as a collection, that stores values + * (e.g.: arguments, strings, objects based on arrays/objects). + * By default an array-like is not classified as a regular array. + * + * @returns {boolean} If the object is an array, it will return true. + */ + return function isArray(object, handleTypedArrayAsArray, handleArrayLikeAsArray) { + var handleTypedArray = handleTypedArrayAsArray === true, + handleArrayLike = handleArrayLikeAsArray === true; + + if (object !== null && typeof object === 'object') { + + if ( ! handleTypedArray && + ! handleArrayLike) { + + return Object.prototype.toString.call(object) === '[object Array]'; + } + + if (handleTypedArray) { + return object instanceof Int8Array || + object instanceof Uint8Array || + object instanceof Uint8ClampedArray || + object instanceof Int16Array || + object instanceof Uint16Array || + object instanceof Int32Array || + object instanceof Uint32Array || + object instanceof Float32Array || + object instanceof Float64Array; + } + + if (handleArrayLike) { + if ('length' in object && + typeof object.length === 'number') { + + return true; + } + } + } + + return false; + }; +})); diff --git a/dist/js-partial-is-array.min.js b/dist/js-partial-is-array.min.js new file mode 100644 index 0000000..a0ec52a --- /dev/null +++ b/dist/js-partial-is-array.min.js @@ -0,0 +1,2 @@ +/*! js-partial-is-array v0.0.0 | MIT License | (c) Richard King - richrdkng@gmail.com */ +!function(n,t){"function"==typeof define&&define.amd?define([],t):"object"==typeof module&&module.exports?module.exports=t():n.js_partial_isArray=t()}(this,function(){"use strict";return function(n,t,r){var e=t===!0,i=r===!0;if(null!==n&&"object"==typeof n){if(!e&&!i)return"[object Array]"===Object.prototype.toString.call(n);if(e)return n instanceof Int8Array||n instanceof Uint8Array||n instanceof Uint8ClampedArray||n instanceof Int16Array||n instanceof Uint16Array||n instanceof Int32Array||n instanceof Uint32Array||n instanceof Float32Array||n instanceof Float64Array;if(i&&"length"in n&&"number"==typeof n.length)return!0}return!1}}); \ No newline at end of file diff --git a/license.md b/license.md new file mode 100644 index 0000000..ae3f703 --- /dev/null +++ b/license.md @@ -0,0 +1,16 @@ +**The MIT License (MIT)** + +Copyright (c) 2016 **Richard King** [richrdkng@gmail.com](richrdkng@gmail.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. diff --git a/package.json b/package.json new file mode 100644 index 0000000..b7ff487 --- /dev/null +++ b/package.json @@ -0,0 +1,59 @@ +{ + "name": "js-partial-is-array", + "version": "0.0.0", + "description": "A partial to check whether an object is an array.", + "main": "dist/js-partial-is-array.js", + "license": "MIT", + "homepage": "https://github.com/jsopenstd/js-partial-is-array#readme", + "repository": { + "type": "git", + "url": "git://github.com/jsopenstd/js-partial-is-array.git" + }, + "bugs": { + "url": "https://github.com/jsopenstd/js-partial-is-array/issues" + }, + "author": { + "name": "Richard King", + "email": "richrdkng@gmail.com", + "url": "https://github.com/richrdkng" + }, + "scripts": { + "g": "node --harmony `which gulp` --gulpfile scripts/gulp/main.js", + "gulp": "npm run g", + "build": "npm run g -- tasks/build", + "test": "npm run g -- tasks/test", + "ci": "npm run g -- tasks/ci" + }, + "dependencies": {}, + "devDependencies": { + "assert": "^1.3.0", + "coveralls": "^2.11.9", + "del": "^2.2.0", + "gulp": "^3.9.1", + "gulp-coveralls": "^0.1.4", + "gulp-debug": "^2.1.2", + "gulp-eslint": "^3.0.1", + "gulp-header": "^1.8.8", + "gulp-istanbul": "^1.0.0", + "gulp-mocha": "^3.0.0", + "gulp-rename": "^1.2.2", + "gulp-sequence": "^0.4.5", + "gulp-uglify": "^2.0.0", + "merge2": "^1.0.2", + "semver": "^5.3.0" + }, + "keywords": [ + "js", + "partial", + "is", + "array", + "isarray", + "is-array", + "js-partial-is-array", + "jsopenstd", + "umd", + "amd", + "commonjs", + "browser" + ] +} diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..a9e9cf2 --- /dev/null +++ b/readme.md @@ -0,0 +1,97 @@ +# js-partial-is-array + +[![Recent Version][npm-badge]][npm-url] +[![Travis CI - Build Status][travis-badge]][travis-url] +[![Coveralls - Code Coverage Status][cov-badge]][cov-url] +[![David - Dependencies][dep-badge]][dep-url] +[![David - DevDependencies][dev-dep-badge]][dev-dep-url] +[![Doclets][doclets-badge]][doclets-url] +[![Gitter - Repository Chat][chat-badge]][chat-url] + +## Synopsis + +A partial to check whether **an object is an array**. +By default it handles **typed arrays and array-likes as non-arrays**. + +- Written in **UMD** + +## Install + +``` +npm install js-partial-is-array +``` + +## Usage + +For additional examples, +check the **[test folder](https://github.com/jsopenstd/js-partial-is-array/tree/master/tests)** + +```javascript +// TODO +``` + +## Documentation + +Check the source +[here](https://github.com/jsopenstd/js-partial-is-array/blob/master/src/js-partial-is-array.js) +since it's well structured and documented. Also you can find the rendered jsDoc documentation on +[Doclets.io](https://doclets.io/jsopenstd/js-partial-is-array/master). + +Also, check the [unit tests](https://github.com/jsopenstd/js-partial-is-array/blob/master/tests/tests.js) +in order to grasp the full-fledged capabilities. + +Have fun! ;) + +## Issues + +If you find any bugs and other issues, check the +[GSDC Guide - Issues](https://github.com/openstd/general-software-development-contribution-guide#issues) +section on how to submit issues in a standardized way on +[the project's issues page](https://github.com/jsopenstd/js-partial-is-array/issues). + +In case you have any suggestions regarding the project (features, additional capabilities, etc.), check the +[GSDC Guide - Suggestions](https://github.com/openstd/general-software-development-contribution-guide#suggestions) +section on how to submit suggestions in an easy, standardized way on +[the project's issues page](https://github.com/jsopenstd/js-partial-is-array/issues). + +## Contribution + +In order to contribute to this project, check the +[GSDC Guide](https://github.com/openstd/general-software-development-contribution-guide) +for an easy, standardized way on how to contribute to projects. + +## Support + +If you **by any means** find this project useful, +[consider supporting the organization](https://github.com/jsopenstd/jsopenstd/blob/master/support.md). + +There are multiple options to support the project and the developers. +Any means of support is beneficial and helpful. + +## License + +[MIT](license.md) @ Richard King + +[npm-badge]: https://img.shields.io/npm/v/js-partial-is-array.svg +[npm-url]: https://www.npmjs.com/package/js-partial-is-array + +[travis-badge]: https://travis-ci.org/jsopenstd/js-partial-is-array.svg?branch=master +[travis-url]: https://travis-ci.org/jsopenstd/js-partial-is-array + +[cov-badge]: https://coveralls.io/repos/github/jsopenstd/js-partial-is-array/badge.svg?branch=master +[cov-url]: https://coveralls.io/github/jsopenstd/js-partial-is-array + +[dep-badge]: https://david-dm.org/jsopenstd/js-partial-is-array.svg +[dep-url]: https://david-dm.org/jsopenstd/js-partial-is-array + +[dev-dep-badge]: https://david-dm.org/jsopenstd/js-partial-is-array/dev-status.svg +[dev-dep-url]: https://david-dm.org/jsopenstd/js-partial-is-array#info=devDependencies + +[doclets-badge]: https://img.shields.io/badge/style-on_doclets-brightgreen.svg?style=flat-square&label=docs +[doclets-url]: https://doclets.io/jsopenstd/js-partial-is-array/master + +[chat-badge]: https://badges.gitter.im/jsopenstd/js-partial-is-array.svg +[chat-url]: https://gitter.im/jsopenstd/js-partial-is-array?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge + +[partial-link]: https://github.com/jsopenstd/jsopenstd/blob/master/readme.md#partial +[umd-link]: https://github.com/jsopenstd/jsopenstd/blob/master/readme.md#umd diff --git a/scripts/gulp/main.js b/scripts/gulp/main.js new file mode 100644 index 0000000..78c219d --- /dev/null +++ b/scripts/gulp/main.js @@ -0,0 +1,17 @@ +'use strict'; + +const gulp = require(`gulp`), + debug = require(`gulp-debug`); + +require(`./tasks/build`); +require(`./tasks/bump`); +require(`./tasks/test`); +require(`./tasks/ci`); + +// left here for quick check whether gulp works +gulp.task( + `default`, + () => { + return gulp; + } +); diff --git a/scripts/gulp/tasks/build/index.js b/scripts/gulp/tasks/build/index.js new file mode 100644 index 0000000..81e3644 --- /dev/null +++ b/scripts/gulp/tasks/build/index.js @@ -0,0 +1,70 @@ +'use strict'; + +const gulp = require(`gulp`), + remove = require(`del`), + compressor = require('gulp-uglify'), + header = require('gulp-header'), + rename = require('gulp-rename'), + sequence = require(`gulp-sequence`), + debug = require(`gulp-debug`); + +gulp.task( + `tasks/build.clear`, + (cb) => { + remove.sync( + [ + `../../dist` + ], + { + force : true + } + ); + + cb(); + } +); + +gulp.task( + `tasks/build.development`, + () => { + return gulp + .src(`../../src/**/*.js`) + .pipe(gulp.dest(`../../dist`)); + } +); + +gulp.task( + `tasks/build.production`, + () => { + let template = require('../../../../src/license-header-template.json').template, + pkg = require('../../../../package.json'), + data = { + name : pkg.name, + version : pkg.version, + author : pkg.author.name, + email : pkg.author.email, + }; + + return gulp + .src(`../../src/**/*.js`) + .pipe(compressor()) + .pipe(header(template, data)) + .pipe(rename( + { + extname : '.min.js' + } + )) + .pipe(gulp.dest(`../../dist`)); + } +); + +gulp.task( + `tasks/build`, + (cb) => { + sequence( + `tasks/build.clear`, + `tasks/build.development`, + `tasks/build.production` + )(cb); + } +); diff --git a/scripts/gulp/tasks/bump/index.js b/scripts/gulp/tasks/bump/index.js new file mode 100644 index 0000000..7d29879 --- /dev/null +++ b/scripts/gulp/tasks/bump/index.js @@ -0,0 +1,147 @@ +'use strict'; + +const gulp = require('gulp'), + sequence = require('gulp-sequence'), + debug = require('gulp-debug'), + semver = require('semver'), + fs = require('fs'), + vars = require('../../vars'); + +const MAJOR = 1, + MINOR = 2, + PATCH = 3; + +let bumpType, + _nextVersion; + +const getNextVersion = () => { + let ver; + + if ( ! _nextVersion) { + ver = require('../../../../package.json').version; + + switch (bumpType) { + case MAJOR : + ver = semver.inc(ver, 'major'); + break; + + case MINOR : + ver = semver.inc(ver, 'minor'); + break; + + case PATCH : + ver = semver.inc(ver, 'patch'); + break; + } + + _nextVersion = ver; + } + + return _nextVersion; +}; + +gulp.task( + 'tasks/bump.set-bump-major', + (cb) => { + bumpType = MAJOR; + cb(); + } +); + +gulp.task( + 'tasks/bump.set-bump-minor', + (cb) => { + bumpType = MINOR; + cb(); + } +); + +gulp.task( + 'tasks/bump.set-bump-patch', + (cb) => { + bumpType = PATCH; + cb(); + } +); + +gulp.task( + 'tasks/bump.package_json', + (cb) => { + let path = '/vagrant/package.json', + pkg = require(path); + + pkg.version = getNextVersion(); + + var data = JSON.stringify(pkg, null, 2); + + // add new line to the end of the file by adding to the data + data += '\n'; + + fs.writeFileSync(path, data); + + cb(); + } +); + +gulp.task( + 'tasks/bump.src', + (cb) => { + bumpType = MAJOR; + + let path = `/vagrant/src/${vars.sourceName}.js`, + version = getNextVersion(), + src = fs.readFileSync( + path, + { + encoding : 'utf8' + } + ), + pattern = /\* @version [\d.]+/; + + src = src.replace(pattern, '* @version ' + version); + + fs.writeFileSync(path, src); + + cb(); + } +); + +gulp.task( + 'tasks/bump.bump-files', + (cb) => { + sequence( + 'tasks/bump.package_json', + 'tasks/bump.src' + )(cb); + } +); + +gulp.task( + 'tasks/bump-major', + (cb) => { + sequence( + 'tasks/bump.set-bump-major', + 'tasks/bump.bump-files' + )(cb); + } +); + +gulp.task( + 'tasks/bump-minor', + (cb) => { + sequence( + 'tasks/bump.set-bump-minor', + 'tasks/bump.bump-files' + )(cb); + } +); + +gulp.task( + 'tasks/bump-patch', + (cb) => { + sequence( + 'tasks/bump.set-bump-patch', + 'tasks/bump.bump-files' + )(cb); + } +); diff --git a/scripts/gulp/tasks/ci/index.js b/scripts/gulp/tasks/ci/index.js new file mode 100644 index 0000000..c726526 --- /dev/null +++ b/scripts/gulp/tasks/ci/index.js @@ -0,0 +1,26 @@ +'use strict'; + +const gulp = require(`gulp`), + coveralls = require(`gulp-coveralls`), + sequence = require(`gulp-sequence`), + debug = require(`gulp-debug`); + +gulp.task( + `tasks/submit-to-coveralls`, + () => { + return gulp + .src(`../../cov/**/lcov.info`) + .pipe(coveralls()); + } +); + +gulp.task( + `tasks/ci`, + (cb) => { + sequence( + `tasks/build`, + `tasks/test`, + `tasks/submit-to-coveralls` + )(cb); + } +); diff --git a/scripts/gulp/tasks/test/index.js b/scripts/gulp/tasks/test/index.js new file mode 100644 index 0000000..b70ee8d --- /dev/null +++ b/scripts/gulp/tasks/test/index.js @@ -0,0 +1,153 @@ +'use strict'; + +const gulp = require(`gulp`), + mocha = require(`gulp-mocha`), + coverage = require(`gulp-istanbul`), + sequence = require(`gulp-sequence`), + lint = require(`gulp-eslint`), + debug = require(`gulp-debug`), + vars = require(`../../vars`), + testVars = require(`../../../../tests/variables`); + +const sourceName = vars.sourceName; + +gulp.task( + `tasks/test.src`, + () => { + testVars.path = `../src/${sourceName}.js`; + + return gulp + .src( + `../../tests/tests.js`, + { + read : false + } + ) + .pipe( + mocha({ + ui : `exports` + }) + ); + } +); + +gulp.task( + `tasks/test.dist.development`, + () => { + testVars.path = `../dist/${sourceName}.js`; + + return gulp + .src( + `../../tests/tests.js`, + { + read : false + } + ) + .pipe( + mocha({ + ui : `exports` + }) + ); + } +); + +gulp.task( + `tasks/test.dist.production`, + () => { + testVars.path = `../dist/${sourceName}.min.js`; + + return gulp + .src( + `../../tests/tests.js`, + { + read : false + } + ) + .pipe( + mocha({ + ui : `exports` + }) + ); + } +); + +gulp.task( + `tasks/test.init-cov`, + () => { + return gulp + .src(`../../src/**/*.js`) + .pipe(coverage()) + .pipe(coverage.hookRequire()); + } +); + +gulp.task( + `tasks/test.with-cov`, + [ + `tasks/test.init-cov` + ], + () => { + testVars.path = `../src/${sourceName}.js`; + + return gulp + .src( + `../../tests/tests.js`, + { + read : false + } + ) + .pipe( + mocha({ + ui : `exports` + }) + ) + .pipe( + coverage.writeReports({ + dir : `../../cov` + }) + ) + .pipe( + coverage.enforceThresholds({ + thresholds : { + global : 100 // enforce 100% coverage + } + } + )); + } +); + +gulp.task( + `tasks/test.with-lint`, + [ + `tasks/test.src` + ], + () => { + return gulp + .src(`../../src/**/*.js`) + .pipe(lint()) + .pipe(lint.format()) + .pipe(lint.failAfterError()); + } +); + +gulp.task( + `tasks/test.dist`, + (cb) => { + sequence( + `tasks/test.dist.development`, + `tasks/test.dist.production` + )(cb); + } +); + +gulp.task( + `tasks/test`, + (cb) => { + sequence( + `tasks/test.src`, + `tasks/test.with-cov`, + `tasks/test.with-lint`, + `tasks/test.dist` + )(cb); + } +); diff --git a/scripts/gulp/vars.js b/scripts/gulp/vars.js new file mode 100644 index 0000000..c0636d0 --- /dev/null +++ b/scripts/gulp/vars.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = { + sourceName : 'js-partial-is-array' +}; diff --git a/scripts/tasks/main.py b/scripts/tasks/main.py new file mode 100644 index 0000000..5b89b52 --- /dev/null +++ b/scripts/tasks/main.py @@ -0,0 +1,290 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import sys +import shlex +import subprocess +import collections +import os.path +import json +import getpass + + +def exec_command(command, **kwargs): + shell = kwargs.get("shell", False) + stdin = kwargs.get("stdin", None) + stdout = kwargs.get("stdout", None) + stderr = kwargs.get("stderr", None) + + kwargs.update(shell=shell) + kwargs.update(stdin=stdin) + kwargs.update(stdout=stdout) + kwargs.update(stderr=stderr) + + if not isinstance(command, list): + command = shlex.split(command) + + return subprocess.call(command, **kwargs) + + +def observe_command(command, **kwargs): + shell = kwargs.get("shell", False) + stdin = kwargs.get("stdin", subprocess.PIPE) + stdout = kwargs.get("stdout", subprocess.PIPE) + stderr = kwargs.get("stderr", subprocess.PIPE) + + kwargs.update(shell=shell) + kwargs.update(stdin=stdin) + kwargs.update(stdout=stdout) + kwargs.update(stderr=stderr) + + if not isinstance(command, list): + command = shlex.split(command) + + proc = subprocess.Popen(command, **kwargs) + + try: + _stdin = proc.stdin.read() + except IOError: + _stdin = None + + try: + _stdout = proc.stdout.read() + except IOError: + _stdout = None + + try: + _stderr = proc.stderr.read() + except IOError: + _stderr = None + + if not _stdin: + _stdin = None + + if not _stdout: + _stdout = None + + if not _stderr: + _stderr = None + + Result = collections.namedtuple("result", "stdin, stdout, stderr") + + return Result(stdin=_stdin, stdout=_stdout, stderr=_stderr) + + +def file_exists(path): + return os.path.isfile(path) + + +def get_json_data(path): + with open(path) as data_file: + data = json.load(data_file) + + return data + + +def data_exists(json_data, key): + return get_data(json_data, key) is not None + + +def get_data(json_data, key): + parts = key.split(".") + value = None + + for part in parts: + + if part in json_data: + json_data = json_data[part] + value = json_data + + else: + value = None + break + + return value + + +def git_data_exists(json_data): + if (data_exists(json_data, "git") and + data_exists(json_data, "git.name") and + data_exists(json_data, "git.email")): + + return True + + return False + + +def npm_data_exists(json_data): + if (data_exists(json_data, "npm") and + data_exists(json_data, "npm.username") and + data_exists(json_data, "npm.email")): + + return True + + return False + + +def git_prerequisites_exist(): + output = observe_command("git config --global user.name") + + if output.stdout is None: + return False + + output = observe_command("git config --global user.email") + + if output.stdout is None: + return False + + return True + + +def npm_prerequisites_exist(): + output = observe_command("npm whoami") + + if output.stderr is not None: + return False + + return True + + +def git_set_prerequisites(json_data): + name = get_data(json_data, "git.name") + email = get_data(json_data, "git.email") + + exec_command("git config --global user.name \"{}\"".format(name)) + exec_command("git config --global user.email \"{}\"".format(email)) + + +def npm_set_prerequisites(npm_adduser_path, json_data): + username = get_data(json_data, "npm.username") + email = get_data(json_data, "npm.email") + + password = getpass.getpass("NPM Password: ") + + exec_command("{} {} {} {}".format(npm_adduser_path, username, password, email)) + + +def bump_project(bump_type): + bump = "tasks/bump-project-{}" + + if (bump_type == "major" or + bump_type == "minor" or + bump_type == "patch"): + + bump = bump.format(bump_type) + + else: + # "patch" is the default bump_type + bump = bump.format("patch") + + run_gulp(bump) + + +def bump_project_files(bump_type): + bump = "tasks/bump-{}" + + if (bump_type == "major" or + bump_type == "minor" or + bump_type == "patch"): + + bump = bump.format(bump_type) + + else: + # "patch" is the default bump_type + bump = bump.format("patch") + + run_gulp(bump) + + +def git_publish(): + data = get_json_data(package_json) + version = get_data(data, 'version') + + # stage files + exec_command(["git add --all"], shell=True) + + # commit + exec_command(["git commit -m \"{}\"".format(version)], shell=True) + + # tag + exec_command(["git tag {}".format(version)], shell=True) + + # push + exec_command(["git push origin master --tags"], shell=True) + + +def npm_publish(): + exec_command("npm publish") + + +def run_gulp(task=None): + if task is None: + task = "" + + exec_command(gulp.format(task)) + + +# necessary paths +publish_json = "/vagrant/.publish.json" +package_json = "/vagrant/package.json" +npm_adduser_sh = "/vagrant/scripts/tasks/npm-adduser.sh" + +# gulp path +gulp = "gulp --gulpfile /vagrant/scripts/gulp/main.js {}" + +args = sys.argv[1:] + +if len(args) > 0: + main_task = args[0] + sub_task = None + + if len(args) > 1: + sub_task = args[1] + + # process according to main_task + if main_task == "test": + run_gulp("tasks/test") + + elif main_task == "bump": + bump_project(sub_task) + + elif main_task == "build": + run_gulp("tasks/build") + + elif main_task == "publish": + if not file_exists(publish_json): + raise FileNotFoundError(".publish.json doesn't exist on: \"{}\"".format(publish_json)) + + data = get_json_data(publish_json) + + # check necessary data presence + if not git_data_exists(data): + raise ValueError("git data not found in .publish.json") + + if not npm_data_exists(data): + raise ValueError("npm data not found in .publish.json") + + # check prerequisites + if not git_prerequisites_exist(): + git_set_prerequisites(data) + + if not npm_prerequisites_exist(): + npm_set_prerequisites(npm_adduser_sh, data) + + # bump file versions according to sub_task + bump_project_files(sub_task) + + # build files + run_gulp("tasks/build") + + # commit and push files + git_publish() + + # publish on NPM + npm_publish() + + else: + run_gulp(main_task) + +else: + run_gulp() diff --git a/scripts/tasks/npm-adduser.sh b/scripts/tasks/npm-adduser.sh new file mode 100644 index 0000000..8740615 --- /dev/null +++ b/scripts/tasks/npm-adduser.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +export H_NPM_USERNAME="$1" +export H_NPM_PASSWORD="$2" +export H_NPM_EMAIL="$3" + +npm adduser <> /home/vagrant/.bashrc diff --git a/scripts/vagrant/scripts/install_essentials.sh b/scripts/vagrant/scripts/install_essentials.sh new file mode 100644 index 0000000..cc96e81 --- /dev/null +++ b/scripts/vagrant/scripts/install_essentials.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +# install essentials +sudo apt-get install python-software-properties \ + build-essential \ + git \ + nano \ + curl \ + mc \ + -y + +# install stress to be able to quickly check if the VM can use all the resources of the host CPU +# usage: + # for 1 core: stress -c 1 + # for 4 cores: stress -c 4 +sudo apt-get install stress -y + +# update after essentials (especially python-software-properties) +sudo apt-get update -y diff --git a/scripts/vagrant/scripts/install_git.sh b/scripts/vagrant/scripts/install_git.sh new file mode 100644 index 0000000..da05134 --- /dev/null +++ b/scripts/vagrant/scripts/install_git.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +# update git +sudo add-apt-repository ppa:git-core/ppa -y +sudo apt-get update -y + +sudo apt-get install git -y diff --git a/scripts/vagrant/scripts/install_node.sh b/scripts/vagrant/scripts/install_node.sh new file mode 100644 index 0000000..46d3f3d --- /dev/null +++ b/scripts/vagrant/scripts/install_node.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash + +function clean_up_dependencies() +{ + cd /vagrant + rm -rf node_modules + npm cache clean +} + +# install node & update npm +curl -sL https://deb.nodesource.com/setup_6.x | sudo bash - +sudo apt-get install nodejs -y + +sudo npm install npm --global + +# install dependency version updater globally +sudo npm rm npm-check-updates --global +sudo npm install npm-check-updates --global + +# install gulp globally +sudo npm rm gulp --global +sudo npm install gulp gulp-cli --global + +# install project dependencies +# clean-up before the first try to prevent "ENOENT: no such file or directory, open..." error during npm install +clean_up_dependencies + +# install dependencies +if ! npm install; then + + # clean-up before another try + clean_up_dependencies + + # when running Vagrant under Windows, in case of "EPROTO: protocol error, symlink...", + # try install dependencies with "--no-bin-links" + if ! npm install --no-bin-links; then + echo '"npm install" AND "npm install --no-bin-links" failed, try to resolve it manually' + fi +fi diff --git a/scripts/vagrant/scripts/install_python.sh b/scripts/vagrant/scripts/install_python.sh new file mode 100644 index 0000000..70bdb5d --- /dev/null +++ b/scripts/vagrant/scripts/install_python.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +# update python 2.7.x +sudo add-apt-repository ppa:fkrull/deadsnakes-python2.7 -y + +sudo apt-get update -y +sudo apt-get install python2.7 -y + +# install pip (python's package manager) +sudo apt-get install python-pip -y diff --git a/src/js-partial-is-array.js b/src/js-partial-is-array.js new file mode 100644 index 0000000..7ff4ba3 --- /dev/null +++ b/src/js-partial-is-array.js @@ -0,0 +1,98 @@ +/* + |---------------------------------------------------------------------------------------------------------------------- + | A partial to check whether an object is an array. + |---------------------------------------------------------------------------------------------------------------------- + */ + +/** + * More information on [JavaScript Open Standards]{@link https://github.com/jsopenstd/jsopenstd}. + * + * @namespace js.partial + * @version 0.0.0 + * + * @author Richard King [GitHub]{@link https://github.com/richrdkng} + * @license [MIT]{@link https://github.com/jsopenstd/js-partial-foreach/blob/master/license.md} + */ + +/** + * UMD - [returnExports.js pattern]{@link https://github.com/umdjs/umd/blob/master/templates/returnExports.js} + * For more information and license, check the link below: + * [UMD GitHub Repository]{@link https://github.com/umdjs/umd} + */ +(function(root, factory) { + // AMD + /* istanbul ignore next: ignore coverage test for UMD */ + if (typeof define === 'function' && define.amd) { + define([], factory); + + // CommonJS + } else if (typeof module === 'object' && module.exports) { + module.exports = factory(); + + // Browser + } else { + root.js_partial_isArray = factory(); + } +}(this, function() { + 'use strict'; + + /** + * Determines whether an object is an array. + * By default it handles **typed arrays and array-likes as non-arrays**. + * + * @function isArray + * @memberOf js.partial + * + * @param {*} object - The object to check. + * @param {boolean|null} [handleTypedArrayAsArray=false] - Handle a typed array as a regular array too. + * By default a typed array is not classified + * as a regular array. + * **Pass null to skip this argument** and leave its value + * with the default value. + * @param {boolean} [handleArrayLikeAsArray=false] - Handle an array-like as a regular array too. + * An array-like is anything, that has a valid .length + * property and behaves as a collection, that stores values + * such as arguments, strings, other objects based on + * arrays or objects. + * By default an array-like is not classified + * as a regular array. + * + * @returns {boolean} If the object is an array, it will return true. + */ + return function isArray(object, handleTypedArrayAsArray, handleArrayLikeAsArray) { + var handleTypedArray = handleTypedArrayAsArray === true, + handleArrayLike = handleArrayLikeAsArray === true; + + if (object !== null && typeof object === 'object') { + + if (Object.prototype.toString.call(object) === '[object Array]') { + return true; + } + + if (handleTypedArray) { + if (object instanceof Int8Array || + object instanceof Uint8Array || + object instanceof Uint8ClampedArray || + object instanceof Int16Array || + object instanceof Uint16Array || + object instanceof Int32Array || + object instanceof Uint32Array || + object instanceof Float32Array || + object instanceof Float64Array) { + + return true; + } + } + + if (handleArrayLike) { + if ('length' in object && + typeof object.length === 'number') { + + return true; + } + } + } + + return false; + }; +})); diff --git a/src/license-header-template.json b/src/license-header-template.json new file mode 100644 index 0000000..9592372 --- /dev/null +++ b/src/license-header-template.json @@ -0,0 +1,3 @@ +{ + "template" : "/*! <%= name %> v<%= version %> | MIT License | (c) <%= author %> - <%= email %> */\n" +} diff --git a/tests/tests.js b/tests/tests.js new file mode 100644 index 0000000..58ceae5 --- /dev/null +++ b/tests/tests.js @@ -0,0 +1,66 @@ +'use strict'; + +const assert = require('assert'), + vars = require('./variables'), + isArray = require(vars.path); + +module.exports = { + 'js-partial-is-object' : () => { + let _undefined = undefined, + _null = null, + _boolean = false, + _number = 0, + _string = 'str', + _function = () => {}, + _array = [], + _object = {}, + + _objectCreated_1 = Object.create({}), + _objectCreated_2 = Object.create(Object.prototype), + _nullProtoObject = Object.create(null), + + _typedArray = new Uint8Array(0), + _arrayLike = (function() { return arguments; })(1, 2, 3); + + assert(isArray() === false); + assert(isArray(_undefined) === false); + assert(isArray(_null) === false); + assert(isArray(_boolean) === false); + assert(isArray(_number) === false); + assert(isArray(_string) === false); + assert(isArray(_function) === false); + assert(isArray(_array) === true); + assert(isArray(_object) === false); + + assert(isArray(_objectCreated_1) === false); + assert(isArray(_objectCreated_2) === false); + assert(isArray(_nullProtoObject) === false); + + assert(isArray(_array, true) === true); + assert(isArray(_array, false) === true); + + assert(isArray(_typedArray, true) === true); + assert(isArray(_typedArray, false) === false); + + assert(isArray(_arrayLike, true) === false); + assert(isArray(_arrayLike, false) === false); + + assert(isArray(_array, true, true) === true); + assert(isArray(_array, false, true) === true); + assert(isArray(_array, null, true) === true); + + assert(isArray(_typedArray, true, true) === true); + assert(isArray(_typedArray, false, false) === false); + assert(isArray(_typedArray, null, false) === false); + + assert(isArray(_arrayLike, true, true) === true); + assert(isArray(_arrayLike, false, false) === false); + assert(isArray(_arrayLike, null, true) === true); + assert(isArray(_arrayLike, null, false) === false); + + assert(isArray(_object, true, true) === false); + assert(isArray(_object, false, false) === false); + assert(isArray(_object, null, true) === false); + assert(isArray(_object, null, false) === false); + } +}; diff --git a/tests/variables.js b/tests/variables.js new file mode 100644 index 0000000..1ed86df --- /dev/null +++ b/tests/variables.js @@ -0,0 +1,3 @@ +module.exports = { + path : '' +}; diff --git a/vagrantfile b/vagrantfile new file mode 100644 index 0000000..015c0bd --- /dev/null +++ b/vagrantfile @@ -0,0 +1,9 @@ +# -*- mode: ruby -*- +# vi: set ft=ruby : + +Vagrant.configure(2) do |config| + + config.vm.box = "ubuntu/trusty64" + config.vm.provision :shell, :path => "scripts/vagrant/provision.sh" + +end