Unverified Commit 91608f05 authored by Robert Knight's avatar Robert Knight Committed by GitHub

Merge pull request #1135 from hypothesis/reformat-scripts

Format gulpfile.js and files in scripts/ using Prettier
parents ad1462f2 7883ae51
**/vendor/*
.*/**
build/
docs/
This diff is collapsed.
......@@ -149,8 +149,8 @@
"scripts": {
"build": "cross-env NODE_ENV=production gulp build",
"lint": "eslint .",
"checkformatting": "prettier --check 'src/**/*.js'",
"format": "prettier --list-different --write 'src/**/*.js'",
"checkformatting": "prettier --check '**/*.js'",
"format": "prettier --list-different --write '**/*.js'",
"test": "gulp test",
"report-coverage": "codecov -f coverage/coverage-final.json",
"version": "make clean build/manifest.json",
......
......@@ -19,7 +19,9 @@ async function createGitHubRelease() {
const GITHUB_ORG_REPO_PAT = /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/;
if (!pkg.repository || !pkg.repository.match(GITHUB_ORG_REPO_PAT)) {
throw new Error('package.json is missing a "repository" field of the form :owner/:repo');
throw new Error(
'package.json is missing a "repository" field of the form :owner/:repo'
);
}
if (!process.env.GITHUB_TOKEN) {
......
......@@ -74,20 +74,23 @@ function stripUnnecessaryReturns(js) {
//
// If we need something more sophisticated, we shouldn't modify the
// source as a string but should instead write a Babel code transformer.
return js.split('\n').map(line => {
const returnPrefix = 'return ';
if (line.trim().startsWith(returnPrefix)) {
const remainder = line.trim().slice(returnPrefix.length);
for (let i=0; i < stripReturnPatterns.length; i++) {
if (remainder.match(stripReturnPatterns[i])) {
return remainder;
return js
.split('\n')
.map(line => {
const returnPrefix = 'return ';
if (line.trim().startsWith(returnPrefix)) {
const remainder = line.trim().slice(returnPrefix.length);
for (let i = 0; i < stripReturnPatterns.length; i++) {
if (remainder.match(stripReturnPatterns[i])) {
return remainder;
}
}
return line;
} else {
return line;
}
return line;
} else {
return line;
}
}).join('\n');
})
.join('\n');
}
/**
......@@ -99,28 +102,32 @@ function stripUnnecessaryReturns(js) {
*/
function checkSyntax(js) {
try {
babylon.parse(js, {sourceType: 'module'});
babylon.parse(js, { sourceType: 'module' });
} catch (err) {
const context = js.split('\n').reduce((context, line, index) => {
const lineNumber = index+1;
let linePrefix;
if (lineNumber === err.loc.line) {
linePrefix = `**${lineNumber}`;
} else {
linePrefix = ` ${lineNumber}`;
}
if (Math.abs(lineNumber - err.loc.line) < 10) {
return context.concat(`${linePrefix}: ${line}`);
} else {
return context;
}
}, []).join('\n');
const context = js
.split('\n')
.reduce((context, line, index) => {
const lineNumber = index + 1;
let linePrefix;
if (lineNumber === err.loc.line) {
linePrefix = `**${lineNumber}`;
} else {
linePrefix = ` ${lineNumber}`;
}
if (Math.abs(lineNumber - err.loc.line) < 10) {
return context.concat(`${linePrefix}: ${line}`);
} else {
return context;
}
}, [])
.join('\n');
throw new Error(
`Could not parsing ES2015 JavaScript generated by 'decaffeinate'.
You may need to fix or simplify the CoffeeScript first.
Error: ${err}
Context:\n${context}\n\n`);
Context:\n${context}\n\n`
);
}
}
......@@ -140,12 +147,14 @@ function reformat(js) {
return Promise.reject(err);
}
return typescriptFormatter.processString(inFile, js, {
baseDir: __dirname,
tsfmt: true,
}).then(result => {
return result.dest;
})
return typescriptFormatter
.processString(inFile, js, {
baseDir: __dirname,
tsfmt: true,
})
.then(result => {
return result.dest;
})
.then(result => {
const checker = new Checker();
checker.configure(jscsConfig);
......@@ -154,11 +163,13 @@ function reformat(js) {
}
function toResultOrError(promise) {
return promise.then(result => {
return { result: result };
}).catch(err => {
return { error: err };
});
return promise
.then(result => {
return { result: result };
})
.catch(err => {
return { error: err };
});
}
function convertFile(inFile, outFile) {
......@@ -167,9 +178,7 @@ function convertFile(inFile, outFile) {
let js;
try {
js = decaffeinate.convert(
fs.readFileSync(inFile).toString('utf8')
);
js = decaffeinate.convert(fs.readFileSync(inFile).toString('utf8'));
} catch (err) {
return Promise.reject(err);
}
......@@ -183,25 +192,33 @@ const conversions = [];
process.argv.slice(2).forEach(filePath => {
const inFile = path.resolve(filePath);
const outFile = inFile.replace(/\.coffee$/, '.js');
conversions.push(toResultOrError(convertFile(inFile, outFile)).then(function (result) {
result.fileName = inFile;
return result;
}));
conversions.push(
toResultOrError(convertFile(inFile, outFile)).then(function(result) {
result.fileName = inFile;
return result;
})
);
});
Promise.all(conversions).then(results => {
let ok = 0;
let failed = 0;
results.forEach(result => {
if (result.error) {
console.log('Error converting %s: \n\n%s', result.fileName, result.error.message);
++failed;
} else {
console.log('Converted %s', result.fileName);
++ok;
}
Promise.all(conversions)
.then(results => {
let ok = 0;
let failed = 0;
results.forEach(result => {
if (result.error) {
console.log(
'Error converting %s: \n\n%s',
result.fileName,
result.error.message
);
++failed;
} else {
console.log('Converted %s', result.fileName);
++ok;
}
});
console.log('Converted %d files, failed to convert %d files', ok, failed);
})
.catch(err => {
console.log('Conversion error:', err);
});
console.log('Converted %d files, failed to convert %d files', ok, failed);
}).catch(err => {
console.log('Conversion error:', err);
});
......@@ -49,9 +49,11 @@ class S3Uploader {
async upload(destPath, srcFile, { cacheControl }) {
if (!this.region) {
// Find out where the S3 bucket is.
const regionResult = await this.s3.getBucketLocation({
Bucket: this.bucket,
}).promise();
const regionResult = await this.s3
.getBucketLocation({
Bucket: this.bucket,
})
.promise();
this.region = regionResult.LocationConstraint;
this.s3 = new AWS.S3({ region: this.region });
}
......@@ -101,20 +103,16 @@ async function uploadPackageToS3(bucket, options) {
// Upload all package files to `$PACKAGE_NAME/$VERSION`.
const uploads = files.map(file =>
uploader.upload(
`${packageName}/${version}/${file}`,
file,
{ cacheControl: cacheForever },
)
uploader.upload(`${packageName}/${version}/${file}`, file, {
cacheControl: cacheForever,
})
);
await Promise.all(uploads);
// Upload a copy of the entry-point to `$PACKAGE_NAME@$VERSION`.
await uploader.upload(
`${packageName}@${version}`,
entryPoint,
{ cacheControl: cacheForever },
);
await uploader.upload(`${packageName}@${version}`, entryPoint, {
cacheControl: cacheForever,
});
// Upload a copy of the entry-point to `$PACKAGE_NAME` or `$PACKAGE_NAME@$TAG`.
// This enables creating URLs that always point to the current version of
......@@ -151,8 +149,7 @@ const options = {
cacheEntry: commander.cacheEntry,
};
uploadPackageToS3(commander.bucket, options)
.catch(err => {
console.error('Failed to upload S3 package', err);
process.exit(1);
});
uploadPackageToS3(commander.bucket, options).catch(err => {
console.error('Failed to upload S3 package', err);
process.exit(1);
});
......@@ -20,14 +20,14 @@ const watchify = require('watchify');
const log = gulpUtil.log;
function streamFinished(stream) {
return new Promise(function (resolve, reject) {
return new Promise(function(resolve, reject) {
stream.on('finish', resolve);
stream.on('error', reject);
});
}
function waitForever() {
return new Promise(function () {});
return new Promise(function() {});
}
/**
......@@ -38,22 +38,25 @@ function waitForever() {
* @param {string} trailerCode - Code added at the end of the wrapper function.
* @return {Transform} - A Node `Transform` stream.
*/
function wrapCodeWithFunction(headerCode, trailerCode='') {
function wrapCodeWithFunction(headerCode, trailerCode = '') {
const iifeStart = '(function() {' + headerCode + ';';
const iifeEnd = ';' + trailerCode + '})()';
let isFirstChunk = true;
return through(function (data, enc, callback) {
if (isFirstChunk) {
isFirstChunk = false;
this.push(Buffer.from(iifeStart));
return through(
function(data, enc, callback) {
if (isFirstChunk) {
isFirstChunk = false;
this.push(Buffer.from(iifeStart));
}
this.push(data);
callback();
},
function(callback) {
this.push(Buffer.from(iifeEnd));
callback();
}
this.push(data);
callback();
}, function (callback) {
this.push(Buffer.from(iifeEnd));
callback();
});
);
}
/**
......@@ -110,7 +113,7 @@ function useExternalRequireName(name) {
module.exports = function createBundle(config, buildOpts) {
mkdirp.sync(config.path);
buildOpts = buildOpts || {watch: false};
buildOpts = buildOpts || { watch: false };
// Use a custom name for the "require" function that bundles use to export
// and import modules from other bundles. This avoids conflicts with eg.
......@@ -133,11 +136,7 @@ module.exports = function createBundle(config, buildOpts) {
//
// See node_modules/browserify/lib/builtins.js to find out which
// modules provide the implementations of these.
builtins: [
'console',
'_process',
'querystring',
],
builtins: ['console', '_process', 'querystring'],
externalRequireName,
insertGlobalVars: {
// The Browserify polyfill for the `Buffer` global is large and
......@@ -151,7 +150,7 @@ module.exports = function createBundle(config, buildOpts) {
// `global` or `self` that is not an alias for `window`. See
// https://github.com/hypothesis/h/issues/2723 and
// https://github.com/hypothesis/client/issues/277
global: function () {
global: function() {
return 'window';
},
},
......@@ -165,7 +164,7 @@ module.exports = function createBundle(config, buildOpts) {
// Specify modules that Browserify should not parse.
// The 'noParse' array must contain full file paths,
// not module names.
bundleOpts.noParse = (config.noParse || []).map(function (id) {
bundleOpts.noParse = (config.noParse || []).map(function(id) {
// If package.json specifies a custom entry point for the module for
// use in the browser, resolve that.
const packageConfig = require('../../package.json');
......@@ -184,7 +183,7 @@ module.exports = function createBundle(config, buildOpts) {
const bundle = browserify([], bundleOpts);
(config.require || []).forEach(function (req) {
(config.require || []).forEach(function(req) {
// When another bundle uses 'bundle.external(<module path>)',
// the module path is rewritten relative to the
// base directory and a '/' prefix is added, so
......@@ -194,15 +193,17 @@ module.exports = function createBundle(config, buildOpts) {
// In the bundle which provides './dir/module', we
// therefore need to expose the module as '/dir/module'.
if (req[0] === '.') {
bundle.require(req, {expose: req.slice(1)});
bundle.require(req, { expose: req.slice(1) });
} else if (req[0] === '/') {
// If the require path is absolute, the same rules as
// above apply but the path needs to be relative to
// the root of the repository
const repoRootPath = path.join(__dirname, '../../');
const relativePath = path.relative(path.resolve(repoRootPath),
path.resolve(req));
bundle.require(req, {expose: '/' + relativePath});
const relativePath = path.relative(
path.resolve(repoRootPath),
path.resolve(req)
);
bundle.require(req, { expose: '/' + relativePath });
} else {
// this is a package under node_modules/, no
// rewriting required.
......@@ -213,7 +214,7 @@ module.exports = function createBundle(config, buildOpts) {
bundle.add(config.entry || []);
bundle.external(config.external || []);
(config.transforms || []).forEach(function (transform) {
(config.transforms || []).forEach(function(transform) {
if (transform === 'coffee') {
bundle.transform(coffeeify);
}
......@@ -223,49 +224,56 @@ module.exports = function createBundle(config, buildOpts) {
});
if (config.minify) {
bundle.transform({global: true}, uglifyify);
bundle.transform({ global: true }, uglifyify);
}
// Include or disable debugging checks in our code and dependencies by
// replacing references to `process.env.NODE_ENV`.
bundle.transform(envify({
NODE_ENV: process.env.NODE_ENV || 'development',
}), {
// Ideally packages should configure this transform in their package.json
// file if they need it, but not all of them do.
global: true,
});
bundle.transform(
envify({
NODE_ENV: process.env.NODE_ENV || 'development',
}),
{
// Ideally packages should configure this transform in their package.json
// file if they need it, but not all of them do.
global: true,
}
);
function build() {
const output = fs.createWriteStream(bundlePath);
const b = bundle.bundle();
b.on('error', function (err) {
b.on('error', function(err) {
log('Build error', err.toString());
});
const stream = (b
const stream = b
.pipe(useExternalRequireName(externalRequireName))
.pipe(exorcist(sourcemapPath))
.pipe(output));
.pipe(output);
return streamFinished(stream);
}
if (buildOpts.watch) {
bundle.plugin(watchify);
bundle.on('update', function (ids) {
bundle.on('update', function(ids) {
const start = Date.now();
log('Source files changed', ids);
build().then(function () {
log('Updated %s (%d ms)', bundleFileName, Date.now() - start);
}).catch(function (err) {
console.error('Building updated bundle failed:', err);
});
});
build().then(function () {
log('Built ' + bundleFileName);
}).catch(function (err) {
console.error('Error building bundle:', err);
build()
.then(function() {
log('Updated %s (%d ms)', bundleFileName, Date.now() - start);
})
.catch(function(err) {
console.error('Building updated bundle failed:', err);
});
});
build()
.then(function() {
log('Built ' + bundleFileName);
})
.catch(function(err) {
console.error('Error building bundle:', err);
});
return waitForever();
} else {
......
......@@ -42,7 +42,7 @@ function LiveReloadServer(port, config) {
function listen() {
const log = gulpUtil.log;
const app = function (req, response) {
const app = function(req, response) {
const url = urlParser.parse(req.url);
let content;
......@@ -140,7 +140,7 @@ function LiveReloadServer(port, config) {
};
const server = createServer(app);
server.listen(port, function (err) {
server.listen(port, function(err) {
if (err) {
log('Setting up live reload server failed', err);
}
......@@ -152,14 +152,14 @@ function LiveReloadServer(port, config) {
httpServer: server,
});
ws.on('request', function (req) {
ws.on('request', function(req) {
log('Live reload client connected');
const conn = req.accept(null, req.origin);
connections.push(conn);
conn.on('close', function () {
conn.on('close', function() {
const closedConn = conn;
connections = connections.filter(function (conn) {
connections = connections.filter(function(conn) {
return conn !== closedConn;
});
});
......@@ -173,12 +173,14 @@ function LiveReloadServer(port, config) {
* Paths are relative to the root asset
* build directory.
*/
this.notifyChanged = function (assets) {
connections.forEach(function (conn) {
conn.sendUTF(JSON.stringify({
type: 'assets-changed',
changed: assets,
}));
this.notifyChanged = function(assets) {
connections.forEach(function(conn) {
conn.sendUTF(
JSON.stringify({
type: 'assets-changed',
changed: assets,
})
);
});
};
......
......@@ -14,24 +14,27 @@ const VinylFile = require('vinyl');
* manifest mapping input paths (eg. "scripts/foo.js")
* to URLs with cache-busting query parameters (eg. "scripts/foo.js?af95bd").
*/
module.exports = function (opts) {
module.exports = function(opts) {
const manifest = {};
return through.obj(function (file, enc, callback) {
const hash = crypto.createHash('sha1');
hash.update(file.contents);
return through.obj(
function(file, enc, callback) {
const hash = crypto.createHash('sha1');
hash.update(file.contents);
const hashSuffix = hash.digest('hex').slice(0, 6);
const relPath = path.relative('build/', file.path);
manifest[relPath] = relPath + '?' + hashSuffix;
const hashSuffix = hash.digest('hex').slice(0, 6);
const relPath = path.relative('build/', file.path);
manifest[relPath] = relPath + '?' + hashSuffix;
callback();
}, function (callback) {
const manifestFile = new VinylFile({
path: opts.name,
contents: Buffer.from(JSON.stringify(manifest, null, 2), 'utf-8'),
});
this.push(manifestFile);
callback();
});
callback();
},
function(callback) {
const manifestFile = new VinylFile({
path: opts.name,
contents: Buffer.from(JSON.stringify(manifest, null, 2), 'utf-8'),
});
this.push(manifestFile);
callback();
}
);
};
......@@ -23,13 +23,13 @@ function servePackage(port, hostname) {
const app = express();
// Enable CORS for assets so that cross-origin font loading works.
app.use(function (req, res, next) {
app.use(function(req, res, next) {
res.append('Access-Control-Allow-Origin', '*');
res.append('Access-Control-Allow-Methods', 'GET');
next();
});
const serveBootScript = function (req, res) {
const serveBootScript = function(req, res) {
const entryPath = require.resolve('../..');
const entryScript = readFileSync(entryPath).toString('utf-8');
res.send(entryScript);
......
......@@ -17,11 +17,10 @@ const SENTRY_API_ROOT = 'https://app.getsentry.com/api/0';
* }
*/
/** Wrapper around request() that returns a Promise. */
function httpRequest(opts) {
return new Promise(function (resolve, reject) {
request(opts, function (err, response, body) {
return new Promise(function(resolve, reject) {
request(opts, function(err, response, body) {
if (err) {
reject(err);
} else {
......@@ -34,11 +33,12 @@ function httpRequest(opts) {
});
}
/** Create a release in Sentry. Returns a Promise. */
function createRelease(opts, project, release) {
return httpRequest({
uri: `${SENTRY_API_ROOT}/projects/${opts.organization}/${project}/releases/`,
uri: `${SENTRY_API_ROOT}/projects/${
opts.organization
}/${project}/releases/`,
method: 'POST',
auth: {
user: opts.key,
......@@ -48,23 +48,27 @@ function createRelease(opts, project, release) {
version: release,
},
json: true,
}).then(function (result) {
const success = (result.response.statusCode === 201);
const alreadyCreated = (result.response.statusCode === 400 &&
result.body.detail.match(/already exists/));
}).then(function(result) {
const success = result.response.statusCode === 201;
const alreadyCreated =
result.response.statusCode === 400 &&
result.body.detail.match(/already exists/);
if (success || alreadyCreated) {
return;
}
throw new Error(`unable to create release '${release}' in project '${project}'`);
throw new Error(
`unable to create release '${release}' in project '${project}'`
);
});
}
/** Upload a named file to a release in Sentry. Returns a Promise. */
function uploadReleaseFile(opts, project, release, file) {
return httpRequest({
uri: `${SENTRY_API_ROOT}/projects/${opts.organization}/${project}/releases/${release}/files/`,
uri: `${SENTRY_API_ROOT}/projects/${
opts.organization
}/${project}/releases/${release}/files/`,
method: 'POST',
auth: {
user: opts.key,
......@@ -74,15 +78,16 @@ function uploadReleaseFile(opts, project, release, file) {
file: fs.createReadStream(file.path),
name: path.basename(file.path),
},
}).then(function (result) {
}).then(function(result) {
if (result.response.statusCode === 201) {
return;
}
throw new Error(`Uploading file failed: ${result.response.statusCode}: ${result.body}`);
throw new Error(
`Uploading file failed: ${result.response.statusCode}: ${result.body}`
);
});
}
/**
* Upload a stream of Vinyl files as a Sentry release.
*
......@@ -99,25 +104,25 @@ function uploadReleaseFile(opts, project, release, file) {
*/
module.exports = function uploadToSentry(opts, projects, release) {
// Create releases in every project
const releases = projects.map(function (project) {
const releases = projects.map(function(project) {
gulpUtil.log(`Creating release '${release}' in project '${project}'`);
return createRelease(opts, project, release);
});
return through.obj(function (file, enc, callback) {
return through.obj(function(file, enc, callback) {
Promise.all(releases)
.then(function () {
.then(function() {
gulpUtil.log(`Uploading ${path.basename(file.path)}`);
const uploads = projects.map(function (project) {
const uploads = projects.map(function(project) {
return uploadReleaseFile(opts, project, release, file);
});
return Promise.all(uploads);
})
.then(function () {
.then(function() {
callback();
})
.catch(function (err) {
.catch(function(err) {
gulpUtil.log('Sentry upload failed: ', err);
callback(err);
});
......
......@@ -9,12 +9,7 @@
module.exports = {
bundles: {
jquery: ['jquery'],
angular: [
'angular',
'angular-route',
'ng-tags-input',
'angular-toastr',
],
angular: ['angular', 'angular-route', 'ng-tags-input', 'angular-toastr'],
katex: ['katex'],
showdown: ['showdown'],
raven: ['raven-js'],
......@@ -29,7 +24,5 @@ module.exports = {
// 2. The module is itself a compiled Browserify bundle containing
// internal require() statements, which should not be processed
// when including the bundle in another project.
noParseModules: [
'jquery',
],
noParseModules: ['jquery'],
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment