diff --git a/.eslintrc.json b/.eslintrc.json index 9a904598f..833eaa5cf 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -9,6 +9,6 @@ "rules": { "comma-dangle": [2, "always-multiline"], "no-unused-vars": [2, { "vars": "all", "args": "none" }], - "no-console": "off"" + "no-console": "off" } } diff --git a/gulp-tasks.js b/gulp-tasks.js new file mode 100644 index 000000000..a14108b15 --- /dev/null +++ b/gulp-tasks.js @@ -0,0 +1,165 @@ +/** + * @license + * Copyright (c) 2016 The Polymer Project Authors. All rights reserved. + * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt + * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt + * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt + * Code distributed by Google as part of the polymer project is also + * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt + */ + +'use strict'; + +const fs = require('fs-extra'); +const gulp = require('gulp'); +const mocha = require('gulp-mocha'); +const tslint_lib = require('gulp-tslint'); +const typescript = require('gulp-typescript'); +const typings = require('gulp-typings'); +const mergeStream = require('merge-stream'); +const path = require('path'); +const runSequence = require('run-sequence'); + +function task(name, deps, impl) { + if (gulp.hasTask(name)) { + throw new Error( + `A task with the name ${JSON.stringify(name)} already exists!`); + } + gulp.task(name, deps, impl); +} + +module.exports.init = function() { + task('init', () => gulp.src('./typings.json').pipe(typings())); +} + +module.exports.depcheck = function depcheck(options) { + const depcheck_lib = require('depcheck'); + const defaultOptions = {stickyDeps: new Set()}; + options = Object.assign({}, defaultOptions, options); + + task('depcheck', () => { + return new Promise((resolve, reject) => { + // Note that process.cwd() in a gulp task is the directory of the + // running gulpfile. See e.g. https://github.com/gulpjs/gulp/issues/523 + depcheck_lib(process.cwd(), {ignoreDirs: []}, resolve); + }).then((result) => { + const invalidFiles = Object.keys(result.invalidFiles) || []; + const invalidJsFiles = invalidFiles.filter((f) => f.endsWith('.js')); + + if (invalidJsFiles.length > 0) { + console.log('Invalid files:', result.invalidFiles); + throw new Error('Invalid files'); + } + + const unused = new Set(result.dependencies); + for (const falseUnused of options.stickyDeps) { + unused.delete(falseUnused); + } + if (unused.size > 0) { + console.log('Unused dependencies:', unused); + throw new Error('Unused dependencies'); + } + }); + }); +} + +module.exports.lint = function(options) { + module.exports.tslint(options); + module.exports.eslint(options); + module.exports.depcheck(options); + task('lint', ['tslint', 'eslint', 'depcheck']); +} + +function getJsonConfig(filename) { + var placesToLook = [ + process.cwd(), + __dirname, + ]; + for (const directory of placesToLook) { + try { + return JSON.parse( + fs.readFileSync(path.join(directory, filename), 'utf-8')); + } catch (error) { /* don't care */ } + } + throw new Error('Could not find a .eslintrc.json. This should never happen.'); +} + +module.exports.tslint = function(options) { + const defaultOptions = {tsSrcs: gulp.src('src/**/*.ts')}; + options = Object.assign({}, defaultOptions, options); + const tslintConfig = getJsonConfig('tslint.json'); + task('tslint', () => + options.tsSrcs + .pipe(tslint_lib({ + configuration: tslintConfig, + })) + .pipe(tslint_lib.report('verbose'))); +} + +module.exports.eslint = function(options) { + const eslint_lib = require('gulp-eslint'); + const defaultOptions = {jsSrcs: gulp.src(['test/**/*.js', 'gulpfile.js'])}; + options = Object.assign({}, defaultOptions, options); + const eslintConfig = getJsonConfig('.eslintrc.json'); + task('eslint', () => + options.jsSrcs + .pipe(eslint_lib(eslintConfig)) + .pipe(eslint_lib.format()) + .pipe(eslint_lib.failAfterError())); +} + +module.exports.build = function(options) { + const defaultOptions = { + tsSrcs: gulp.src('src/**/*.ts'), + dataSrcs: gulp.src(['src/**/*', '!src/**/*.ts']), + }; + options = Object.assign({}, defaultOptions, options); + + const tsProject = typescript.createProject('tsconfig.json'); + + task('build', () => + mergeStream( + options.tsSrcs.pipe(typescript(tsProject)), + options.dataSrcs + ).pipe(gulp.dest('lib')) + ); +} + +module.exports.clean = function(options) { + const defaultOptions = {buildArtifacts: ['lib/', 'typings/']}; + options = Object.assign({}, defaultOptions, options); + + task('clean', () => { + for (const buildArtifact of options.buildArtifacts) { + fs.removeSync(path.join(process.cwd(), buildArtifact)); + } + }); +} + + +module.exports.buildAll = function(options) { + module.exports.clean(options); + module.exports.init(options); + module.exports.lint(options); + module.exports.build(options); + + task('build-all', (done) => { + runSequence('clean', 'init', 'lint', 'build', done); + }); +} + +module.exports.test = function(options) { + module.exports.buildAll(options); + + task('test', ['build'], () => + gulp.src('test/**/*_test.js', {read: false}) + .pipe(mocha({ + ui: 'tdd', + reporter: 'spec', + })) + ); +} + +module.exports.generateCompleteTaskgraph = function(options) { + module.exports.test(options); +} diff --git a/gulpfile.js b/gulpfile.js index 5e289b344..1854a2787 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -10,134 +10,20 @@ 'use strict'; -const depcheck_lib = require('depcheck'); -const eslint_lib = require('gulp-eslint'); -const fs = require('fs-extra'); const gulp = require('gulp'); -const mergeStream = require('merge-stream'); -const mocha = require('gulp-mocha'); -const path = require('path'); -const runSeq = require('run-sequence'); -const tslint_lib = require("gulp-tslint"); -const typescript = require('gulp-typescript'); -const typings = require('gulp-typings'); - -function task(name, deps, impl) { - if (gulp.hasTask(name)) { - throw new Error( - `A task with the name ${JSON.stringify(name)} already exists!`); - } - gulp.task(name, deps, impl); -} - -module.exports.init = function() { - task('init', () => gulp.src("./typings.json").pipe(typings())); -} - -module.exports.depcheck = function depcheck(options) { - const defaultOptions = {stickyDeps: new Set()}; - options = Object.assign({}, defaultOptions, options); - - task('depcheck', () => { - return new Promise((resolve, reject) => { - depcheck_lib(__dirname, {ignoreDirs: []}, resolve); - }).then((result) => { - const invalidFiles = Object.keys(result.invalidFiles) || []; - const invalidJsFiles = invalidFiles.filter((f) => f.endsWith('.js')); - - if (invalidJsFiles.length > 0) { - console.log('Invalid files:', result.invalidFiles); - throw new Error('Invalid files'); - } - - const unused = new Set(result.dependencies); - for (const falseUnused of options.stickyDeps) { - unused.delete(falseUnused); - } - if (unused.size > 0) { - console.log('Unused dependencies:', unused); - throw new Error('Unused dependencies'); - } - }); - }); -} - -module.exports.lint = function(options) { - module.exports.tslint(options); - module.exports.eslint_lib(options); - module.exports.depcheck(options); - task('lint', ['tslint', 'eslint', 'depcheck']); -} - -module.exports.tslint = function(options) { - const defaultOptions = {tsSrcs: gulp.src('src/**/*.ts')}; - options = Object.assign({}, defaultOptions, options); - task('tslint', () => - options.tsSrcs - .pipe(tslint_lib({ - configuration: 'tslint.json', - })) - .pipe(tslint_lib.report('verbose'))); -} - -module.exports.eslint = function(options) { - const defaultOptions = {jsSrcs: gulp.src('test/**/*.js')}; - options = Object.assign({}, defaultOptions, options); - task('eslint', () => - options.jsSrcs - .pipe(eslint()) - .pipe(eslint.format()) - .pipe(eslint.failAfterError())); -} - -module.exports.build = function(options) { - const defaultOptions = { - tsSrcs: gulp.src('src/**/*.ts'), - dataSrcs: gulp.src(['src/**/*', '!src/**/*.ts']) - }; - options = Object.assign({}, defaultOptions, options); - - const tsProject = typescript.createProject('tsconfig.json'); - - task('build', () => - mergeStream( - options.tsSrcs.pipe(typescript(tsProject)), - options.dataSrcs - ).pipe(gulp.dest('lib')) - ); -} - -module.exports.clean = function(options) { - const defaultOptions = {buildArtifacts: ['lib']}; - options = Object.assign({}, defaultOptions, options); - - task('clean', () => { - for (const buildArtifact of options.buildArtifacts) { - fs.removeSync(path.join(__dirname, buildArtifact)); - } - }); -} - - -module.exports.buildAll = function(options) { - module.exports.clean(options); - module.exports.init(options); - module.exports.lint(options); - module.exports.build(options); - - task('build-all', (done) => { - runSeq('clean', 'init', 'lint', 'build', done); - }); -} - -module.exports.test = function(options) { - module.exports.buildAll(options); - - task('test', ['build'], () => - gulp.src('test/**/*_test.js', {read: false}) - .pipe(mocha({ - ui: 'tdd', - reporter: 'spec', - })) - ); -} +const toolsCommon = require('./gulp-tasks'); +// Use this instead when you copy-paste this file into other repos: +// const toolsCommon = require('tools-common/gulp-tasks'); + +toolsCommon.generateCompleteTaskgraph({ + // What will get deleted when gulp clean is run + buildArtifacts: ['lib/', 'typings/'], + + // Dependencies that we assert are actually used, even if they look unused. + stickyDeps: new Set([/* sticky deps here */]), + + // Typescript sources here + tsSrcs: gulp.src('src/**/*.ts'), + // Files to copy to lib/ + dataSrcs: gulp.src(['src/**/*', '!src/**/*.ts']), +}); diff --git a/package.json b/package.json index b08a5bf4e..5ec2783eb 100644 --- a/package.json +++ b/package.json @@ -1,4 +1,7 @@ { + "name": "tools-common", + "repository": "https://github.com/Polymer/tools-common", + "version": "1.0.0", "engines": { "node": ">=4.0" }, @@ -11,21 +14,21 @@ }, "author": "The Polymer Project Authors", "license": "BSD-3-Clause", - "devDependencies": { - "chai": "^3.5.0", + "dependencies": { "depcheck": "^0.6.3", "fs-extra": "^0.30.0", "gulp-eslint": "^2.0.0", "gulp-mocha": "^2.2.0", "gulp-tslint": "^5.0.0", "gulp-typescript": "^2.13.4", - "gulp-typings": "^1.3.6", + "gulp-typings": "^2.0.0", "run-sequence": "^1.2.0", - "sinon": "^1.17.4", - "temp": "^0.8.3", - "tslint": "^3.10.2", - "vinyl-fs-fake": "^1.1.0", - "yeoman-assert": "^2.2.1", - "yeoman-test": "^1.1.0" + "tslint": "^3.10.2" + }, + "peerDependencies": { + "gulp": "^3.9.1" + }, + "devDependencies": { + "gulp": "^3.9.1" } }