diff --git a/.babelrc b/.babelrc new file mode 100755 index 00000000..32d293d4 --- /dev/null +++ b/.babelrc @@ -0,0 +1,5 @@ +{ + "presets": [ + "env" + ] +} diff --git a/.editorconfig b/.editorconfig new file mode 100755 index 00000000..26fde2c6 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,15 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true +indent_style = tab + +[{*.json,*.yml,.babelrc,.bowerrc,.postcssrc}] +indent_style = space +indent_size = 2 + +[*.txt,wp-config-sample.php] +end_of_line = crlf diff --git a/.eslintrc b/.eslintrc new file mode 100755 index 00000000..6659ea1d --- /dev/null +++ b/.eslintrc @@ -0,0 +1,19 @@ +{ + "parser": "babel-eslint", + "env": { + "browser": true, + "es6": true + }, + "extends": "eslint:recommended", + "rules": { + "yoda": [ 2 ], + "indent": [ 2, "tab", { "SwitchCase": 2 } ], + "linebreak-style": [ 2, "unix" ], + "quotes": [ 2, "single" ], + "semi": [ 2, "always" ], + "space-in-parens": [ 2, "always" ], + "no-console": [ 1 ], + "no-alert": [ 1 ], + "camelcase": [ 2 ] + } +} diff --git a/.gitignore b/.gitignore new file mode 100755 index 00000000..710e0716 --- /dev/null +++ b/.gitignore @@ -0,0 +1,30 @@ +node_modules +bower_components +release +vendor +composer.lock +phpunit.xml +.idea + +# Project Files +dist + +# Editors +*.esproj +*.tmproj +*.tmproject +tmtags +.*.sw[a-z] +*.un~ +Session.vim +*.swp + +# Mac OSX +.DS_Store +._* +.Spotlight-V100 +.Trashes + +# Windows +Thumbs.db +Desktop.ini diff --git a/assets/css/admin/admin-style.css b/assets/css/admin/admin-style.css new file mode 100755 index 00000000..151f37c5 --- /dev/null +++ b/assets/css/admin/admin-style.css @@ -0,0 +1,3 @@ +/** + * TenupAutoTweet - Admin Styles + */ diff --git a/assets/css/frontend/base/index.css b/assets/css/frontend/base/index.css new file mode 100755 index 00000000..8b137891 --- /dev/null +++ b/assets/css/frontend/base/index.css @@ -0,0 +1 @@ + diff --git a/assets/css/frontend/components/index.css b/assets/css/frontend/components/index.css new file mode 100755 index 00000000..e69de29b diff --git a/assets/css/frontend/editor-style.css b/assets/css/frontend/editor-style.css new file mode 100644 index 00000000..cb85910e --- /dev/null +++ b/assets/css/frontend/editor-style.css @@ -0,0 +1,3 @@ +/** + * TenupAutoTweet - Editor Styles + */ diff --git a/assets/css/frontend/global/index.css b/assets/css/frontend/global/index.css new file mode 100755 index 00000000..e69de29b diff --git a/assets/css/frontend/layout/index.css b/assets/css/frontend/layout/index.css new file mode 100755 index 00000000..e69de29b diff --git a/assets/css/frontend/style.css b/assets/css/frontend/style.css new file mode 100755 index 00000000..4091693d --- /dev/null +++ b/assets/css/frontend/style.css @@ -0,0 +1,19 @@ +/** + * TenupAutoTweet + */ + +/* Global - global pieces like media queries, mixins and placholders */ +@import url("global/index"); + +/* Base - base styles such as fonts, typography, and wordpress overrides */ +/* as well as some global micro-elements like icons */ +@import url("base/index"); + +/* Layout - styles specific to layout */ +@import url("layout/index"); + +/* Templates */ +@import url("templates/index"); + +/* Components */ +@import url("components/index"); diff --git a/assets/css/frontend/templates/index.css b/assets/css/frontend/templates/index.css new file mode 100755 index 00000000..e69de29b diff --git a/assets/css/shared/shared-style.css b/assets/css/shared/shared-style.css new file mode 100755 index 00000000..5fb1caa3 --- /dev/null +++ b/assets/css/shared/shared-style.css @@ -0,0 +1,3 @@ +/** + * TenupAutoTweet: Shared Styles + */ diff --git a/assets/fonts/font-name/weight/.gitkeep b/assets/fonts/font-name/weight/.gitkeep new file mode 100755 index 00000000..c1df4390 --- /dev/null +++ b/assets/fonts/font-name/weight/.gitkeep @@ -0,0 +1 @@ +# Basically just want to ignore the directory contents diff --git a/assets/images/src/.gitkeep b/assets/images/src/.gitkeep new file mode 100755 index 00000000..c1df4390 --- /dev/null +++ b/assets/images/src/.gitkeep @@ -0,0 +1 @@ +# Basically just want to ignore the directory contents diff --git a/assets/js/admin/admin.js b/assets/js/admin/admin.js new file mode 100755 index 00000000..7fb911bd --- /dev/null +++ b/assets/js/admin/admin.js @@ -0,0 +1 @@ +//import foo from './bar' diff --git a/assets/js/frontend/components/.gitkeep b/assets/js/frontend/components/.gitkeep new file mode 100755 index 00000000..c1df4390 --- /dev/null +++ b/assets/js/frontend/components/.gitkeep @@ -0,0 +1 @@ +# Basically just want to ignore the directory contents diff --git a/assets/js/frontend/frontend.js b/assets/js/frontend/frontend.js new file mode 100755 index 00000000..cc927d42 --- /dev/null +++ b/assets/js/frontend/frontend.js @@ -0,0 +1 @@ +// import foo from './components/bar'; diff --git a/assets/js/shared/shared.js b/assets/js/shared/shared.js new file mode 100755 index 00000000..7fb911bd --- /dev/null +++ b/assets/js/shared/shared.js @@ -0,0 +1 @@ +//import foo from './bar' diff --git a/assets/svg/.gitkeep b/assets/svg/.gitkeep new file mode 100755 index 00000000..c1df4390 --- /dev/null +++ b/assets/svg/.gitkeep @@ -0,0 +1 @@ +# Basically just want to ignore the directory contents diff --git a/composer.json b/composer.json new file mode 100644 index 00000000..d6191567 --- /dev/null +++ b/composer.json @@ -0,0 +1,22 @@ +{ + "name": "10up/tenup-auto-tweet", + "description": "Tenup Auto Tweet", + "authors": [ + { + "name": "Author", + "email": "info@10up.com" + } + ], + "require": { + "php": ">=7.0", + "abraham/twitteroauth": "^0.7.4" + }, + "autoload": { + "psr-4": { + "TenupAutoTweet\\": "includes/classes/" + } + }, + "require-dev": { + "10up/wp_mock": "dev-dev" + } +} diff --git a/gulp-tasks/cssclean.js b/gulp-tasks/cssclean.js new file mode 100755 index 00000000..32209452 --- /dev/null +++ b/gulp-tasks/cssclean.js @@ -0,0 +1,6 @@ +import gulp from 'gulp'; +import del from 'del'; + +gulp.task( 'cssclean', () => { + del( ['./dist/*.css'] ); +} ); \ No newline at end of file diff --git a/gulp-tasks/cssnano.js b/gulp-tasks/cssnano.js new file mode 100755 index 00000000..3f6c9cd2 --- /dev/null +++ b/gulp-tasks/cssnano.js @@ -0,0 +1,37 @@ +import gulp from 'gulp'; +import cssnano from 'gulp-cssnano'; +import rename from 'gulp-rename'; +import sourcemaps from 'gulp-sourcemaps'; +import pump from 'pump'; +import livereload from 'gulp-livereload'; +import filter from 'gulp-filter'; + +gulp.task( 'cssnano', ( cb ) => { + const fileDest = './dist/css', + fileSrc = [ + './dist/*.css' + ], + taskOpts = [cssnano( { + autoprefixer: false, + calc: { + precision: 8 + }, + zindex: false, + convertValues: true + } )]; + + pump( [ + gulp.src( fileSrc ), + sourcemaps.init( { + loadMaps: true + } ), + cssnano( taskOpts ), + rename( function( path ) { + path.extname = '.min.css'; + } ), + sourcemaps.write( './' ), + gulp.dest( fileDest ), + filter( '**/*.css' ), + livereload() + ], cb ); +} ); diff --git a/gulp-tasks/cssnext.js b/gulp-tasks/cssnext.js new file mode 100755 index 00000000..2fd5bf30 --- /dev/null +++ b/gulp-tasks/cssnext.js @@ -0,0 +1,39 @@ +import gulp from 'gulp'; +import postcss from 'gulp-postcss'; +import sourcemaps from 'gulp-sourcemaps'; +import pump from 'pump'; + +gulp.task( 'cssnext', ( cb ) => { + const fileSrc = [ + './assets/css/admin/admin-style.css', + './assets/css/frontend/editor-style.css', + './assets/css/frontend/style.css', + './assets/css/shared/shared-style.css' + ]; + const fileDest = './dist'; + const cssNextOpts = { + features: { + autoprefixer: { + browsers: ['last 2 versions'] + } + } + }; + const taskOpts = [ + require( 'postcss-import' ), + require( 'postcss-cssnext' )( cssNextOpts ) + ]; + + pump( [ + gulp.src( fileSrc ), + sourcemaps.init( { + loadMaps: true + } ), + postcss( taskOpts ), + sourcemaps.write( './css', { + mapFile: function( mapFilePath ) { + return mapFilePath.replace( '.css.map', '.min.css.map' ); + } + } ), + gulp.dest( fileDest ) + ], cb ); +} ); diff --git a/gulp-tasks/webpack.js b/gulp-tasks/webpack.js new file mode 100755 index 00000000..9e242ab9 --- /dev/null +++ b/gulp-tasks/webpack.js @@ -0,0 +1,21 @@ +import gulp from 'gulp'; +import pump from 'pump'; +import webpack from 'webpack'; +import webpackStream from 'webpack-stream'; +import livereload from 'gulp-livereload'; + +function processWebpack( src, conf, dest, cb ) { + pump( [ + gulp.src( src ), + webpackStream( require( conf ), webpack ), + gulp.dest( dest ), + livereload() + ], cb ); +} + +gulp.task( 'webpack', () => { + const src = '../assets/js/**/*.js'; + const conf = '../webpack.config.babel.js'; + const dest = './dist/js'; + processWebpack( src, conf, dest ); +} ); diff --git a/gulpfile.babel.js b/gulpfile.babel.js new file mode 100755 index 00000000..44dbdaef --- /dev/null +++ b/gulpfile.babel.js @@ -0,0 +1,33 @@ +import gulp from 'gulp'; +import requireDir from 'require-dir'; +import runSequence from 'run-sequence'; +import livereload from 'gulp-livereload'; + +requireDir( './gulp-tasks' ); + +gulp.task( 'js', () => { + runSequence( + 'webpack', + ); +} ); + +gulp.task( 'css', () => { + runSequence( + 'cssnext', + 'cssnano', + 'cssclean' + ); +} ); + +gulp.task( 'watch', () => { + livereload.listen( { basePath: 'dist' } ); + gulp.watch( ['./assets/css/**/*.css', '!./assets/css/src/**/*.css'], ['css'] ); + gulp.watch( './assets/js/**/*.js', ['js'] ); +} ); + +gulp.task( 'default', () => { + runSequence( + 'css', + 'webpack' + ); +} ); diff --git a/includes/classes/.gitkeep b/includes/classes/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/includes/functions/core.php b/includes/functions/core.php new file mode 100644 index 00000000..a1d5316c --- /dev/null +++ b/includes/functions/core.php @@ -0,0 +1,236 @@ +assertConditionsMet(); + } + + /** + * Test internationalization integration. + */ + public function test_i18n() { + // Setup + \WP_Mock::wpFunction( 'get_locale', array( + 'times' => 1, + 'args' => array(), + 'return' => 'en_US', + ) ); + \WP_Mock::onFilter( 'plugin_locale' )->with( 'en_US', 'tenup-auto-tweet' )->reply( 'en_US' ); + \WP_Mock::wpFunction( 'load_textdomain', array( + 'times' => 1, + 'args' => array( 'tenup-auto-tweet', 'lang_dir/tenup-auto-tweet/tenup-auto-tweet-en_US.mo' ), + ) ); + \WP_Mock::wpFunction( 'plugin_basename', array( + 'times' => 1, + 'args' => array( 'path' ), + 'return' => 'path', + ) ); + \WP_Mock::wpFunction( 'load_plugin_textdomain', array( + 'times' => 1, + 'args' => array( 'tenup-auto-tweet', false, 'path/languages/' ), + ) ); + + // Act + i18n(); + + // Verify + $this->assertConditionsMet(); + } + + /** + * Test initialization method. + */ + public function test_init() { + // Setup + \WP_Mock::expectAction( 'tenup_auto_tweet_init' ); + + // Act + init(); + + // Verify + $this->assertConditionsMet(); + } + + /** + * Test activation routine. + */ + public function test_activate() { + // Setup + \WP_Mock::wpFunction( 'flush_rewrite_rules', array( + 'times' => 1 + ) ); + + // Act + activate(); + + // Verify + $this->assertConditionsMet(); + } + + /** + * Test deactivation routine. + */ + public function test_deactivate() { + // Setup + + // Act + deactivate(); + + // Verify + } +} diff --git a/tests/phpunit/test-tools/TestCase.php b/tests/phpunit/test-tools/TestCase.php new file mode 100644 index 00000000..534ec37a --- /dev/null +++ b/tests/phpunit/test-tools/TestCase.php @@ -0,0 +1,75 @@ +setPreserveGlobalState( false ); + return parent::run( $result ); + } + + protected $testFiles = array(); + + public function setUp() { + if ( ! empty( $this->testFiles ) ) { + foreach ( $this->testFiles as $file ) { + if ( file_exists( PROJECT . $file ) ) { + require_once( PROJECT . $file ); + } + } + } + + parent::setUp(); + } + + public function assertActionsCalled() { + $actions_not_added = $expected_actions = 0; + try { + WP_Mock::assertActionsCalled(); + } catch ( \Exception $e ) { + $actions_not_added = 1; + $expected_actions = $e->getMessage(); + } + $this->assertEmpty( $actions_not_added, $expected_actions ); + } + + public function ns( $function ) { + if ( ! is_string( $function ) || false !== strpos( $function, '\\' ) ) { + return $function; + } + + $thisClassName = trim( get_class( $this ), '\\' ); + + if ( ! strpos( $thisClassName, '\\' ) ) { + return $function; + } + + // $thisNamespace is constructed by exploding the current class name on + // namespace separators, running array_slice on that array starting at 0 + // and ending one element from the end (chops the class name off) and + // imploding that using namespace separators as the glue. + $thisNamespace = implode( '\\', array_slice( explode( '\\', $thisClassName ), 0, - 1 ) ); + + return "$thisNamespace\\$function"; + } + + /** + * Define constants after requires/includes + * + * See http://kpayne.me/2012/07/02/phpunit-process-isolation-and-constant-already-defined/ + * for more details + * + * @param \Text_Template $template + */ + public function prepareTemplate( \Text_Template $template ) { + $template->setVar( [ + 'globals' => '$GLOBALS[\'__PHPUNIT_BOOTSTRAP\'] = \'' . $GLOBALS['__PHPUNIT_BOOTSTRAP'] . '\';', + ] ); + parent::prepareTemplate( $template ); + } +} diff --git a/webpack.config.babel.js b/webpack.config.babel.js new file mode 100755 index 00000000..55e2fd3b --- /dev/null +++ b/webpack.config.babel.js @@ -0,0 +1,60 @@ +import path from 'path'; +import webpack from 'webpack'; + +const DIST_PATH = path.resolve( './dist/js' ); + +const config = { + cache: true, + entry: { + admin: './assets/js/admin/admin.js', + frontend: './assets/js/frontend/frontend.js', + shared: './assets/js/shared/shared.js' + }, + output: { + path: DIST_PATH, + filename: '[name].min.js', + }, + resolve: { + modules: ['node_modules'], + }, + devtool: 'source-map', + module: { + rules: [ + { + test: /\.js$/, + enforce: 'pre', + loader: 'eslint-loader', + query: { + configFile: './.eslintrc' + } + }, + { + test: /\.js$/, + use: [{ + loader: 'babel-loader', + options: { + babelrc: true, + } + + }] + } + ] + }, + mode: 'production', + plugins: [ + new webpack.NoEmitOnErrorsPlugin(), + ], + stats: { + colors: true + }, + /* + Uncomment this if you need to exclude dependencies from the output bundles, + like if WordPress is including jQuery (for example). + + externals: { + jquery: 'jQuery' + } + */ +}; + +module.exports = config;