@ardatan/relay-compiler
Version:
Fork of `relay-compiler`
302 lines (255 loc) • 8.83 kB
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
*
* @emails oncall+relay
*/
// flowlint ambiguous-object-type:error
'use strict';
var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault');
var _objectSpread2 = _interopRequireDefault(require('@babel/runtime/helpers/objectSpread2'));
var _createForOfIteratorHelper2 = _interopRequireDefault(
require('@babel/runtime/helpers/createForOfIteratorHelper'),
);
var invariant = require('invariant');
var md5 = require('../util/md5');
var _require = require('./extractAST'),
toASTRecord = _require.toASTRecord;
var _require2 = require('graphql'),
Source = _require2.Source,
parse = _require2.parse;
var Sources = /*#__PURE__*/ (function () {
Sources.fromSavedState = function fromSavedState(_ref) {
var extractFromFile = _ref.extractFromFile,
savedState = _ref.savedState;
var state = {};
var _iterator = (0, _createForOfIteratorHelper2['default'])(savedState),
_step;
try {
var _loop = function _loop() {
var _step$value = _step.value,
file = _step$value.file,
savedStateSources = _step$value.sources;
var nodes = {};
var sources = [];
var _iterator2 = (0, _createForOfIteratorHelper2['default'])(savedStateSources),
_step2;
try {
for (_iterator2.s(); !(_step2 = _iterator2.n()).done; ) {
var text = _step2.value;
var doc = parse(new Source(text, file));
!doc.definitions.length
? process.env.NODE_ENV !== 'production'
? invariant(false, 'expected not empty list of definitions')
: invariant(false)
: void 0;
var entities = doc.definitions.map(function (node) {
return toASTRecord(node);
});
entities.forEach(function (astRecord) {
nodes[md5(astRecord.text)] = astRecord.ast;
});
sources.push(text);
}
} catch (err) {
_iterator2.e(err);
} finally {
_iterator2.f();
}
state[file] = {
nodes: nodes,
sources: sources,
};
};
for (_iterator.s(); !(_step = _iterator.n()).done; ) {
_loop();
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
return new Sources({
extractFromFile: extractFromFile,
state: state,
});
};
function Sources(_ref2) {
var extractFromFile = _ref2.extractFromFile,
state = _ref2.state;
this._extractFromFile = extractFromFile;
this._state = (0, _objectSpread2['default'])({}, state);
}
var _proto = Sources.prototype;
_proto.processChanges = function processChanges(baseDir, files) {
var _ast$name$value, _ast$name;
var added = [];
var removed = [];
var state = (0, _objectSpread2['default'])({}, this._state);
var _iterator3 = (0, _createForOfIteratorHelper2['default'])(files),
_step3;
try {
for (_iterator3.s(); !(_step3 = _iterator3.n()).done; ) {
var _state$file$name$node, _state$file$name;
var _file = _step3.value;
var newDefs = void 0;
var newSources = void 0;
try {
var extracted = this._extractFromFile(baseDir, _file);
if (extracted != null) {
newDefs = extracted.nodes;
newSources = extracted.sources;
}
} catch (error) {
throw new Error(
'RelayCompiler: Sources module failed to parse '
.concat(_file.name, ':\n')
.concat(error.message),
);
}
var hasEntry = state.hasOwnProperty(_file.name);
var oldEntry =
(_state$file$name$node =
(_state$file$name = state[_file.name]) === null || _state$file$name === void 0
? void 0
: _state$file$name.nodes) !== null && _state$file$name$node !== void 0
? _state$file$name$node
: {}; // First case, we have new changes in the file
// for example changed Query or Fragment
if (newDefs != null && newDefs.length > 0) {
// We need to add all entities from the changed file to added arrays
var newEntry = {};
var newTexts = new Set();
var _iterator4 = (0, _createForOfIteratorHelper2['default'])(newDefs),
_step4;
try {
for (_iterator4.s(); !(_step4 = _iterator4.n()).done; ) {
var _step4$value = _step4.value,
_ast = _step4$value.ast,
text = _step4$value.text;
var hashedText = md5(text);
if (newTexts.has(hashedText)) {
var name = 'unknown';
switch (_ast.kind) {
case 'FragmentDefinition':
name = _ast.name.value;
break;
case 'OperationDefinition':
name =
(_ast$name$value =
(_ast$name = _ast.name) === null || _ast$name === void 0
? void 0
: _ast$name.value) !== null && _ast$name$value !== void 0
? _ast$name$value
: 'unnamed operation';
break;
}
throw new Error(
'Duplicate definition of `'.concat(name, '` in `').concat(_file.name, '`'),
);
}
newTexts.add(hashedText);
if (hasEntry && oldEntry[hashedText] != null) {
// Entity text did not change, so we
// don't need to change it in the state
newEntry[hashedText] = oldEntry[hashedText];
} else {
// Here we have completely new text.
// We need add it to the `added` changes
newEntry[hashedText] = _ast;
added.push({
file: _file.name,
ast: _ast,
});
}
} // Also, we need to delete all old entities
// that are not included in the new changes
} catch (err) {
_iterator4.e(err);
} finally {
_iterator4.f();
}
if (hasEntry) {
for (var _i = 0, _Object$keys = Object.keys(oldEntry); _i < _Object$keys.length; _i++) {
var oldHashedText = _Object$keys[_i];
var ast = oldEntry[oldHashedText];
if (!newTexts.has(oldHashedText)) {
removed.push({
file: _file.name,
ast: ast,
});
}
}
} // Finally, update the state with the changes
state[_file.name] = {
nodes: newEntry,
// $FlowFixMe[incompatible-type]
sources: newSources,
};
} else {
// Otherwise, file has been removed or there are no entities in the file
if (hasEntry) {
// We will put all ASTNodes from current state to removed collection
for (
var _i2 = 0, _Object$keys2 = Object.keys(oldEntry);
_i2 < _Object$keys2.length;
_i2++
) {
var _oldHashedText = _Object$keys2[_i2];
var _ast2 = oldEntry[_oldHashedText];
removed.push({
file: _file.name,
ast: _ast2,
});
}
delete state[_file.name];
}
}
}
} catch (err) {
_iterator3.e(err);
} finally {
_iterator3.f();
}
return {
// $FlowFixMe[incompatible-return]
changes: {
added: added,
removed: removed,
},
sources: new Sources({
extractFromFile: this._extractFromFile,
state: state,
}),
};
};
_proto.nodes = function* nodes() {
for (var _file2 in this._state) {
var entry = this._state[_file2];
for (
var _i3 = 0, _Object$values = Object.values(entry.nodes);
_i3 < _Object$values.length;
_i3++
) {
var node = _Object$values[_i3];
yield node;
}
}
};
_proto.serializeState = function serializeState() {
var serializedState = [];
for (var _file3 in this._state) {
serializedState.push({
file: _file3,
sources: this._state[_file3].sources,
});
}
return serializedState;
};
return Sources;
})();
module.exports = Sources;