Files
30-seconds-of-code/node_modules/@gatsbyjs/relay-compiler/lib/CodegenWatcher.js
2019-08-20 15:52:05 +02:00

278 lines
7.4 KiB
JavaScript

/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*
* @format
*/
'use strict';
var _asyncToGenerator = require("@babel/runtime/helpers/asyncToGenerator");
var GraphQLWatchmanClient = require("./GraphQLWatchmanClient");
var Profiler = require("./GraphQLCompilerProfiler");
var crypto = require("crypto");
var fs = require("fs");
var path = require("path");
var SUBSCRIPTION_NAME = 'graphql-codegen';
var QUERY_RETRIES = 3;
function queryFiles(_x, _x2, _x3) {
return _queryFiles.apply(this, arguments);
}
function _queryFiles() {
_queryFiles = _asyncToGenerator(function* (baseDir, expression, filter) {
return yield Profiler.waitFor('Watchman:query',
/*#__PURE__*/
_asyncToGenerator(function* () {
var client = new GraphQLWatchmanClient(QUERY_RETRIES);
var _ref = yield Promise.all([client.watchProject(baseDir), getFields(client)]),
watchResp = _ref[0],
fields = _ref[1];
var resp = yield client.command('query', watchResp.root, {
expression: expression,
fields: fields,
relative_root: watchResp.relativePath
});
client.end();
return updateFiles(new Set(), baseDir, filter, resp.files);
}));
});
return _queryFiles.apply(this, arguments);
}
function queryDirectories(_x4, _x5) {
return _queryDirectories.apply(this, arguments);
}
function _queryDirectories() {
_queryDirectories = _asyncToGenerator(function* (baseDir, expression) {
return yield Profiler.waitFor('Watchman:query',
/*#__PURE__*/
_asyncToGenerator(function* () {
var client = new GraphQLWatchmanClient();
var watchResp = yield client.watchProject(baseDir);
var resp = yield client.command('query', watchResp.root, {
expression: expression,
fields: ['name'],
relative_root: watchResp.relativePath
});
client.end();
return resp.files;
}));
});
return _queryDirectories.apply(this, arguments);
}
function getFields(_x6) {
return _getFields.apply(this, arguments);
} // For use when not using Watchman.
function _getFields() {
_getFields = _asyncToGenerator(function* (client) {
var fields = ['name', 'exists'];
if (yield client.hasCapability('field-content.sha1hex')) {
fields.push('content.sha1hex');
}
return fields;
});
return _getFields.apply(this, arguments);
}
function queryFilepaths(_x7, _x8, _x9) {
return _queryFilepaths.apply(this, arguments);
}
/**
* Provides a simplified API to the watchman API.
* Given some base directory and a list of subdirectories it calls the callback
* with watchman change events on file changes.
*/
function _queryFilepaths() {
_queryFilepaths = _asyncToGenerator(function* (baseDir, filepaths, filter) {
// Construct WatchmanChange objects as an intermediate step before
// calling updateFiles to produce file content.
var files = filepaths.map(function (filepath) {
return {
name: filepath,
exists: true,
'content.sha1hex': null
};
});
return updateFiles(new Set(), baseDir, filter, files);
});
return _queryFilepaths.apply(this, arguments);
}
function watch(_x10, _x11, _x12) {
return _watch.apply(this, arguments);
}
function _watch() {
_watch = _asyncToGenerator(function* (baseDir, expression, callback) {
return yield Profiler.waitFor('Watchman:subscribe',
/*#__PURE__*/
_asyncToGenerator(function* () {
var client = new GraphQLWatchmanClient();
var watchResp = yield client.watchProject(baseDir);
yield makeSubscription(client, watchResp.root, watchResp.relativePath, expression, callback);
}));
});
return _watch.apply(this, arguments);
}
function makeSubscription(_x13, _x14, _x15, _x16, _x17) {
return _makeSubscription.apply(this, arguments);
}
/**
* Further simplifies `watch` and calls the callback on every change with a
* full list of files that match the conditions.
*/
function _makeSubscription() {
_makeSubscription = _asyncToGenerator(function* (client, root, relativePath, expression, callback) {
client.on('subscription', function (resp) {
if (resp.subscription === SUBSCRIPTION_NAME) {
callback(resp);
}
});
var fields = yield getFields(client);
yield client.command('subscribe', root, SUBSCRIPTION_NAME, {
expression: expression,
fields: fields,
relative_root: relativePath
});
});
return _makeSubscription.apply(this, arguments);
}
function watchFiles(_x18, _x19, _x20, _x21) {
return _watchFiles.apply(this, arguments);
}
/**
* Similar to watchFiles, but takes an async function. The `compile` function
* is awaited and not called in parallel. If multiple changes are triggered
* before a compile finishes, the latest version is called after the compile
* finished.
*
* TODO: Consider changing from a Promise to abortable, so we can abort mid
* compilation.
*/
function _watchFiles() {
_watchFiles = _asyncToGenerator(function* (baseDir, expression, filter, callback) {
var files = new Set();
yield watch(baseDir, expression, function (changes) {
if (!changes.files) {
// Watchmen fires a change without files when a watchman state changes,
// for example during an hg update.
return;
}
files = updateFiles(files, baseDir, filter, changes.files);
callback(files);
});
});
return _watchFiles.apply(this, arguments);
}
function watchCompile(_x22, _x23, _x24, _x25) {
return _watchCompile.apply(this, arguments);
}
function _watchCompile() {
_watchCompile = _asyncToGenerator(function* (baseDir, expression, filter, compile) {
var compiling = false;
var needsCompiling = false;
var latestFiles = null;
watchFiles(baseDir, expression, filter,
/*#__PURE__*/
function () {
var _ref6 = _asyncToGenerator(function* (files) {
needsCompiling = true;
latestFiles = files;
if (compiling) {
return;
}
compiling = true;
while (needsCompiling) {
needsCompiling = false;
yield compile(latestFiles);
}
compiling = false;
});
return function (_x26) {
return _ref6.apply(this, arguments);
};
}());
});
return _watchCompile.apply(this, arguments);
}
function updateFiles(files, baseDir, filter, fileChanges) {
var fileMap = new Map();
files.forEach(function (file) {
file.exists && fileMap.set(file.relPath, file);
});
fileChanges.forEach(function (_ref2) {
var name = _ref2.name,
exists = _ref2.exists,
hash = _ref2['content.sha1hex'];
var shouldRemove = !exists;
if (!shouldRemove) {
var _file = {
exists: true,
relPath: name,
hash: hash || hashFile(path.join(baseDir, name))
};
if (filter(_file)) {
fileMap.set(name, _file);
} else {
shouldRemove = true;
}
}
shouldRemove && fileMap.set(name, {
exists: false,
relPath: name
});
});
return new Set(fileMap.values());
}
function hashFile(filename) {
var content = fs.readFileSync(filename);
return crypto.createHash('sha1').update(content).digest('hex');
}
module.exports = {
queryDirectories: queryDirectories,
queryFiles: queryFiles,
queryFilepaths: queryFilepaths,
watch: watch,
watchFiles: watchFiles,
watchCompile: watchCompile
};