Skip to content

Commit

Permalink
Make it possible to use tools-common's gulp tasks as a library (#5)
Browse files Browse the repository at this point in the history
* More work to make tools-common librarified

* Add version to package.json

* Use cwd rather than __dirname

* Use the tools-common .eslintrc.json if no project-specific one is found

* Use tools-common tslint as a fallback too

* Update gulp-typings

* Document the "if main" section of gulpfile.js

* Document the subtle gulp cwd constraint

* Gulp as peer dependency, gulp tasks as gulp-tasks.js

* Add generateCompleteTaskgraph, fix style nits and improve docs
  • Loading branch information
rictic authored Jul 22, 2016
1 parent 7f2887e commit ed1dd8f
Show file tree
Hide file tree
Showing 4 changed files with 194 additions and 140 deletions.
2 changes: 1 addition & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@
"rules": {
"comma-dangle": [2, "always-multiline"],
"no-unused-vars": [2, { "vars": "all", "args": "none" }],
"no-console": "off""
"no-console": "off"
}
}
165 changes: 165 additions & 0 deletions gulp-tasks.js
Original file line number Diff line number Diff line change
@@ -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);
}
146 changes: 16 additions & 130 deletions gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -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']),
});
21 changes: 12 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
{
"name": "tools-common",
"repository": "https://github.com/Polymer/tools-common",
"version": "1.0.0",
"engines": {
"node": ">=4.0"
},
Expand All @@ -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"
}
}

0 comments on commit ed1dd8f

Please sign in to comment.