ethers.js/gulpfile.js

357 lines
11 KiB
JavaScript

'use strict';
var fs = require('fs');
var through = require('through');
var gulp = require("gulp");
var ts = require("gulp-typescript");
var tsProject = ts.createProject("tsconfig.json");
var browserify = require("browserify");
var source = require('vinyl-source-stream');
var tsify = require("tsify");
var sourcemaps = require('gulp-sourcemaps');
var uglify = require('gulp-uglify');
var buffer = require('vinyl-buffer');
function createTransform(transforms, show) {
if (!show) { show = { }; }
function padding(length) {
let pad = '';
while (pad.length < length) { pad += ' '; }
return pad;
}
function transformFile(path) {
for (var pattern in transforms) {
if (path.match(new RegExp('/' + pattern + '$'))) {
return transforms[pattern];
}
}
return null;
}
return function(path, options) {
var data = '';
return through(function(chunk) {
data += chunk;
}, function () {
var transformed = transformFile(path);
var shortPath = path;
if (shortPath.substring(0, __dirname.length) == __dirname) {
shortPath = shortPath.substring(__dirname.length);
}
var size = fs.readFileSync(path).length;
if (transformed != null) {
if (show.transformed) {
console.log('Transformed:', shortPath, padding(70 - shortPath.length), size, padding(6 - String(size).length), '=>', transformed.length);
}
data = transformed;
} else if (shortPath === '/src.ts/utils/wordlist.ts') {
data += '\n\nexportWordlist = true;'
if (show.transformed) {
console.log('Transformed:', shortPath, padding(70 - shortPath.length), size, padding(6 - String(size).length), '=>', data.length);
}
} else {
if (show.preserved) {
console.log('Preserved: ', shortPath, padding(70 - shortPath.length), size);
}
}
this.queue(data);
this.queue(null);
});
}
}
/**
* Bundled Library (browser)
*
* Source: src.ts/index.ts src.ts/{contracts,providers,utils,wallet}/*.ts src.ts/wordlists/lang-en.ts
* Target: dist/ethers{.min,}.js
*/
function taskBundle(name, options) {
var show = options.show || { };
// The elliptic package.json is only used for its version
var ellipticPackage = require('elliptic/package.json');
ellipticPackage = JSON.stringify({ version: ellipticPackage.version });
var version = require('./package.json').version;
var undef = "module.exports = undefined;";
var empty = "module.exports = {};";
// This is only used in getKeyPair, which we do not use; but we'll
// leave it in tact using the browser crypto functions
var brorand = "module.exports = function(length) { var result = new Uint8Array(length); (global.crypto || global.msCrypto).getRandomValues(result); return result; }";
// setImmediate is installed globally by our src.browser/shims.ts, loaded from src.ts/index.ts
var process = "module.exports = { browser: true };";
var timers = "module.exports = { setImmediate: global.setImmediate }; ";
function readShim(filename) {
return fs.readFileSync('./shims/' + filename + '.js').toString();
}
var transforms = {
// Remove the precomputed secp256k1 points
"elliptic/lib/elliptic/precomputed/secp256k1.js": undef,
// Remove curves we don't care about
"elliptic/curve/edwards.js": empty,
"elliptic/curve/mont.js": empty,
"elliptic/lib/elliptic/eddsa/.*": empty,
// We only use the version from this JSON package
"elliptic/package.json" : ellipticPackage,
// Remove RIPEMD160 and unneeded hashing algorithms
//"hash.js/lib/hash/ripemd.js": "module.exports = {ripemd160: null}",
"hash.js/lib/hash/sha/1.js": empty,
"hash.js/lib/hash/sha/224.js": empty,
"hash.js/lib/hash/sha/384.js": empty,
// Swap out borland for the random bytes we already have
"brorand/index.js": brorand,
"xmlhttprequest/lib/XMLHttpRequest.js": readShim("xmlhttprequest"),
// Used by sha3 if it exists; (so make it no exist)
"process/browser.js": process,
"timers-browserify/main.js": timers,
"ethers.js/utils/base64.js": readShim("base64"),
"ethers.js/providers/ipc-provider.js": readShim("empty"),
"ethers.js/utils/hmac.js": readShim("hmac"),
"ethers.js/utils/pbkdf2.js": readShim("pbkdf2"),
"ethers.js/utils/random-bytes.js": readShim("random-bytes"),
"ethers.js/utils/shims.js": readShim("shims"),
"ethers.js/wordlists/index.js": readShim("wordlists"),
};
gulp.task(name, function () {
var result = browserify({
basedir: '.',
debug: false,
entries: [ './index.js' ],
cache: { },
packageCache: {},
standalone: "ethers",
transform: [ [ createTransform(transforms, show), { global: true } ] ],
})
.bundle()
.pipe(source(options.filename))
if (options.minify) {
result = result.pipe(buffer())
.pipe(sourcemaps.init({ loadMaps: true }))
.pipe(uglify({
output: { ascii_only: true }
}))
.pipe(sourcemaps.write('./'))
}
result = result.pipe(gulp.dest(options.dest));
return result;
});
}
// Creates dist/ethers.js
taskBundle("default", { filename: "ethers.js", dest: 'dist', show: { transformed: true, preserved: true }, minify: false });
// Creates dist/ethers.js
taskBundle("default-test", { filename: "ethers.js", dest: 'tests/dist', show: { transformed: true }, minify: false });
// Creates dist/ethers.min.js
taskBundle("minified", { filename: "ethers.min.js", dest: 'dist', minify: true });
// Creates dist/ethers.min.js
taskBundle("minified-test", { filename: "ethers.min.js", dest: 'tests/dist', minify: true });
gulp.task('shims', function () {
var result = browserify({
basedir: '.',
debug: false,
entries: [ './tests/shims/index.js' ],
cache: { },
packageCache: {},
standalone: "_shims",
insertGlobalVars: {
process: function() { return; },
}
})
.bundle()
.pipe(source('shims.js'))
.pipe(buffer())
.pipe(uglify({
output: { ascii_only: true }
}))
.pipe(gulp.dest('dist'));
return result;
});
/*
// Dump the TypeScript definitions to dist/types/
gulp.task("types", function() {
return gulp.src(['./src.ts/index.ts', './src.ts / * * / * . ts'])
.pipe(ts({
declaration: true,
esModuleInterop: true,
moduleResolution: "node",
lib: [ "es2015", "es5", "dom" ],
module: "commonjs",
outDir: './dist/types',
target: "es5",
}))
.dts
.pipe(gulp.dest("dist/types/"))
});
*/
/**
* Browser Friendly BIP39 Wordlists
*
* source: src.ts/wordlist/lang-*.ts
* target: dist/wordlist-*.js
*
* Since all of the functions these wordlists use is already
* available from the global ethers library, we use this to
* target the global ethers functions directly, rather than
* re-include them.
*/
function taskLang(locale) {
function transformBip39(path, options) {
var data = '';
return through(function(chunk) {
data += chunk;
}, function () {
var shortPath = path;
if (shortPath.substring(0, __dirname.length) == __dirname) {
shortPath = shortPath.substring(__dirname.length);
}
// Word list files...
if (shortPath.match(/^\/src\.ts\/wordlists\//)) {
shortPath = '/';
}
switch (shortPath) {
// Use the existing "ethers.errors"
case '/src.ts/errors.ts':
data = "module.exports = global.ethers.errors";
break;
// Use the existing "ethers.utils"
case '/src.ts/utils/bytes.ts':
case '/src.ts/utils/hash.ts':
case '/src.ts/utils/properties.ts':
case '/src.ts/utils/utf8.ts':
data = "module.exports = global.ethers.utils";
break;
// If it is the Wordlist class, register should export the wordlist
case '/src.ts/utils/wordlist.ts':
data += '\n\nexportWordlist = true;'
break;
// Do nothing
case '/':
break;
default:
throw new Error('unhandled file: ' + shortPath);
}
this.queue(data);
this.queue(null);
});
}
gulp.task("bip39-" + locale, function() {
return browserify({
basedir: '.',
debug: false,
entries: [ 'src.ts/wordlists/lang-' + locale + ".ts" ],
cache: {},
packageCache: {},
transform: [ [ transformBip39, { global: true } ] ],
})
.plugin(tsify)
.bundle()
.pipe(source("wordlist-" + locale + ".js"))
.pipe(buffer())
.pipe(uglify({
output: { ascii_only: true }
}))
.pipe(gulp.dest("dist"));
});
}
taskLang("es");
taskLang("fr");
taskLang("it");
taskLang("ja");
taskLang("ko");
taskLang("zh");
// Package up all the test cases into tests/dist/tests.json
gulp.task("tests", function() {
function readShim(filename) {
return fs.readFileSync('./tests/' + filename + '.js').toString();
}
var transforms = {
"tests/utils-ethers.js": readShim('utils-ethers-browser')
}
// Create a mock-fs module that can load our gzipped test cases
var data = {};
fs.readdirSync('tests/tests').forEach(function(filename) {
if (!filename.match(/\.json\.gz$/)) { return; }
filename = 'tests/tests/' + filename;
data['/' + filename] = fs.readFileSync(filename).toString('base64');
});
fs.readdirSync('tests/tests/easyseed-bip39').forEach(function(filename) {
if (!filename.match(/\.json$/)) { return; }
filename = 'tests/tests/easyseed-bip39/' + filename;
data['/' + filename] = fs.readFileSync(filename).toString('base64');
});
fs.readdirSync('tests/wordlist-generation').forEach(function(filename) {
if (!filename.match(/\.txt$/)) { return; }
filename = 'tests/wordlist-generation/' + filename;
data['/' + filename] = fs.readFileSync(filename).toString('base64');
});
fs.writeFileSync('./tests/dist/tests.json', JSON.stringify(data));
return browserify({
basedir: './',
debug: false,
entries: [ "./tests/browser.js" ],
cache: {},
packageCache: {},
standalone: "tests",
transform: [ [ createTransform(transforms), { global: true } ] ],
})
.bundle()
.pipe(source("tests.js"))
.pipe(gulp.dest("tests/dist/"));
});