diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000000000..9e7436c5c2d20 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,9 @@ +dist/ +docs/ +examples/ +node_modules/ +lib/ +scripts/ +# for disable website but should be done as well +website/ +*.md diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000000000..207a858b6b1c3 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,90 @@ +--- +parser: babel-eslint + +plugins: + - react + +env: + browser: true + node: true + +globals: + __DEV__: true + # Jest / Jasmine + describe: false + xdescribe: false + beforeEach: false + afterEach: false + it: false + xit: false + jest: false + pit: false + expect: false + spyOn: false + jasmine: false + +rules: + # ERRORS + space-before-blocks: 2 + indent: [2, 2, {SwitchCase: 1}] + brace-style: 2 + space-after-keywords: 2 + strict: [2, global] + # Make this a warning for now. We do this in a few places so we might need to + # disable + dot-notation: 2 + dot-location: [2, property] + quotes: [2, single, avoid-escape] + no-multi-spaces: 2 + + # WISHLIST. One day... + # We'll need a custom version of this that does a subset of the whole rule. + # Otherwise this is just too noisy. + # valid-jsdoc: 1 + # Ideally, we could just warn when *new* lines are added that exceed 80 chars + # while not warning about existing ones (often URLs, etc. which are + # necessarily long), but we don't have a good way to do so. + # max-len: [0, 80] + + # DISABLED. These aren't compatible with our style + # We use this for private/internal variables + no-underscore-dangle: 0 + # We pass constructors around / access them from members + new-cap: 0 + # We do this a lot. + no-use-before-define: 0 + # We do this in a few places to align values + key-spacing: 0 + # It's nice to be able to leave catch blocks empty + no-empty: 0 + # It makes code more readable to make this explicit sometimes + no-undef-init: 0 + + # BROKEN. We'd like to turn these back on. + # causes a ton of noise, eslint is too picky? + block-scoped-var: 0 + + # JSX + # Our transforms set this automatically + react/display-name: 0 + react/jsx-boolean-value: [2, always] + react/jsx-no-undef: 2 + react/jsx-quotes: [2, double] + # We don't care to do this + react/jsx-sort-prop-types: 0 + react/jsx-sort-props: 0 + react/jsx-uses-react: 2 + react/jsx-uses-vars: 2 + # It's easier to test some things this way + react/no-did-mount-set-state: 0 + react/no-did-update-set-state: 0 + # We define multiple components in test files + react/no-multi-comp: 0 + react/no-unknown-property: 2 + # This isn't useful in our test code + react/prop-types: 0 + react/react-in-jsx-scope: 2 + react/self-closing-comp: 2 + # We don't care to do this + react/sort-comp: 0 + react/wrap-multilines: [2, {declaration: false, assignment: false}] diff --git a/.travis.yml b/.travis.yml index 66d609f64dcdc..5bd1a316b46d6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,8 @@ language: node_js node_js: - 'iojs-v3' +before_install: +- npm install -g npm@2 env: - TEST_DIR=. - TEST_DIR=scripts/babel-relay-plugin diff --git a/gulpfile.js b/gulpfile.js index 388a681232485..722f24a105f3b 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -7,6 +7,8 @@ * of patent rights can be found in the PATENTS file in the same directory. */ +/* eslint-disable */ + 'use strict'; var babel = require('gulp-babel'); diff --git a/package.json b/package.json index e8ee3b08c79db..5a78f82caf740 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "scripts": { "build": "[ $(ulimit -n) -lt 4096 ] && ulimit -n 4096; gulp", "prepublish": "npm run build", + "lint": "eslint .", "test": "npm run typecheck && NODE_ENV=test jest", "typecheck": "flow check src/", "update-schema": "babel-node ./scripts/jest/updateSchema.js" @@ -36,10 +37,13 @@ }, "devDependencies": { "babel-core": "5.8.21", + "babel-eslint": "^4.0.7", "babel-loader": "5.3.2", "babel-relay-plugin": "^0.1.2", "del": "^1.2.0", "envify": "^3.4.0", + "eslint": "^1.1.0", + "eslint-plugin-react": "^3.2.3", "flow-bin": "0.14.0", "graphql": "^0.2.6", "gulp": "^3.9.0", diff --git a/src/container/__tests__/RelayRootContainer-test.js b/src/container/__tests__/RelayRootContainer-test.js index 9b37b97c3da28..16dccbdb6b9ca 100644 --- a/src/container/__tests__/RelayRootContainer-test.js +++ b/src/container/__tests__/RelayRootContainer-test.js @@ -391,7 +391,7 @@ describe('RelayRootContainer', function() { it('aborts loading requests', () => { function mockLoading(request) { - request.block(); + request.block(); } expect(mockLoading).toAbortOnUpdate(); expect(mockLoading).toAbortOnUnmount(); diff --git a/src/legacy/query/GraphQL.js b/src/legacy/query/GraphQL.js index fdd769bab9c28..2b09579e7d834 100644 --- a/src/legacy/query/GraphQL.js +++ b/src/legacy/query/GraphQL.js @@ -542,7 +542,7 @@ class GraphQLMutation extends GraphQLOperation { /** * @return {number} */ - getJSONType() { + getJSONType() { return JSON_TYPES.MUTATION; } } @@ -587,7 +587,7 @@ class GraphQLSubscription extends GraphQLOperation { /** * @return {number} */ - getJSONType() { + getJSONType() { return JSON_TYPES.SUBSCRIPTION; } } diff --git a/src/legacy/store/GraphQLRange.js b/src/legacy/store/GraphQLRange.js index b60632619d438..71116c584ff83 100644 --- a/src/legacy/store/GraphQLRange.js +++ b/src/legacy/store/GraphQLRange.js @@ -1048,7 +1048,7 @@ class GraphQLRange { return range; } - toJSON(){ + toJSON() { return [ this._hasFirst, this._hasLast, diff --git a/src/legacy/store/GraphQLSegment.js b/src/legacy/store/GraphQLSegment.js index 95778f1adc5ea..caaf786324597 100644 --- a/src/legacy/store/GraphQLSegment.js +++ b/src/legacy/store/GraphQLSegment.js @@ -258,9 +258,9 @@ class GraphQLSegment { index + ' to (' + this._minIndex + - ", " + + ', ' + this._maxIndex + - ")" + ')' ); return; diff --git a/src/legacy/store/__mocks__/generateClientID.js b/src/legacy/store/__mocks__/generateClientID.js index 5c17925474517..412eea973d124 100644 --- a/src/legacy/store/__mocks__/generateClientID.js +++ b/src/legacy/store/__mocks__/generateClientID.js @@ -12,7 +12,7 @@ var count = 1; var generateClientID = jest.genMockFunction().mockImplementation( - () => { return 'client:' + count++;} + () => 'client:' + count++ ); module.exports = generateClientID; diff --git a/src/legacy/store/__tests__/GraphQLFragmentPointer-test.js b/src/legacy/store/__tests__/GraphQLFragmentPointer-test.js index 9ae60f8504eed..57c58bb2ecd20 100644 --- a/src/legacy/store/__tests__/GraphQLFragmentPointer-test.js +++ b/src/legacy/store/__tests__/GraphQLFragmentPointer-test.js @@ -155,7 +155,7 @@ describe('GraphQLFragmentPointer', () => { }); it('throws when creating a singular pointer with multiple IDs', () => { - expect(() =>{ + expect(() => { new GraphQLFragmentPointer(['123'], singularFragment); }).toFailInvariant( 'GraphQLFragmentPointer: Wrong plurality, array of data IDs ' + @@ -164,7 +164,7 @@ describe('GraphQLFragmentPointer', () => { }); it('throws when creating a plural pointer with a single ID', () => { - expect(() =>{ + expect(() => { new GraphQLFragmentPointer('123', pluralFragment); }).toFailInvariant( 'GraphQLFragmentPointer: Wrong plurality, single data ID supplied ' + diff --git a/src/legacy/store/__tests__/GraphQLSegment-test.js b/src/legacy/store/__tests__/GraphQLSegment-test.js index 81a09069dbb3c..cf4c5ec941e1c 100644 --- a/src/legacy/store/__tests__/GraphQLSegment-test.js +++ b/src/legacy/store/__tests__/GraphQLSegment-test.js @@ -270,7 +270,7 @@ describe('GraphQLSegment', () => { it('rolls back bumped edges from failed concatSegment operations', () => { console.error = jest.genMockFunction(); segment.addEdgesAfterCursor(edges.slice(0, 2), null); - expect(segment.__debug().idToIndices['edge2'].length).toBe(1); + expect(segment.__debug().idToIndices.edge2.length).toBe(1); var otherSegment = new GraphQLSegment(); var edge2 = edges.slice(1, 2); @@ -286,7 +286,7 @@ describe('GraphQLSegment', () => { 'edge2' ); // Make sure it rolled back the deleted edge from indices map - expect(segment.__debug().idToIndices['edge2'].length).toBe(1); + expect(segment.__debug().idToIndices.edge2.length).toBe(1); }); it('should check for valid id in segment', () => { diff --git a/src/legacy/store/generateClientEdgeID.js b/src/legacy/store/generateClientEdgeID.js index ed2fc193cc981..6702fb7acf812 100644 --- a/src/legacy/store/generateClientEdgeID.js +++ b/src/legacy/store/generateClientEdgeID.js @@ -20,7 +20,7 @@ * @internal */ function generateClientEdgeID(rangeID: string, nodeID: string): string { - return 'client:' + rangeID + ':' + nodeID; + return 'client:' + rangeID + ':' + nodeID; } module.exports = generateClientEdgeID; diff --git a/src/mutation/RelayMutationTransaction.js b/src/mutation/RelayMutationTransaction.js index a7c4b9bcf58e4..c67b2ba2e47ea 100644 --- a/src/mutation/RelayMutationTransaction.js +++ b/src/mutation/RelayMutationTransaction.js @@ -328,7 +328,9 @@ class RelayMutationTransaction { var shouldRollback = true; var commitFailureCallback = this._onCommitFailureCallback; if (commitFailureCallback) { - var preventAutoRollback = function() { shouldRollback = false; }; + var preventAutoRollback = function() { + shouldRollback = false; + }; ErrorUtils.applyWithGuard( commitFailureCallback, null, diff --git a/src/mutation/__tests__/RelayMutationTransaction-test.js b/src/mutation/__tests__/RelayMutationTransaction-test.js index 331b3fa3aaafc..9d31e743e9955 100644 --- a/src/mutation/__tests__/RelayMutationTransaction-test.js +++ b/src/mutation/__tests__/RelayMutationTransaction-test.js @@ -300,93 +300,94 @@ describe('RelayMutationTransaction', () => { it('auto-rollbacks colliding queued transactions upon failure, unless ' + 'prevented', () => { - var failureCallback1 = jest.genMockFunction().mockImplementation( - (transaction, preventAutoRollback) => { - expect(transaction).toBe(transaction1); - expect(transaction.getStatus()).toBe( - RelayMutationTransactionStatus.COMMIT_FAILED - ); - preventAutoRollback(); - } - ); - var transaction1 = new RelayMutationTransaction(mockMutation1); - transaction1.commit({onFailure: failureCallback1}); - - var failureCallback2 = jest.genMockFunction().mockImplementation( - (transaction, preventAutoRollback) => { - expect(transaction).toBe(transaction2); - expect(transaction.getStatus()).toBe( - RelayMutationTransactionStatus.COLLISION_COMMIT_FAILED - ); - } - ); - var transaction2 = new RelayMutationTransaction(mockMutation1); - transaction2.commit({onFailure: failureCallback2}); - - var failureCallback3 = jest.genMockFunction().mockImplementation( - (transaction, preventAutoRollback) => { - expect(transaction).toBe(transaction3); - expect(transaction.getStatus()).toBe( - RelayMutationTransactionStatus.COLLISION_COMMIT_FAILED - ); - preventAutoRollback(); - } - ); - var transaction3 = new RelayMutationTransaction(mockMutation1); - transaction3.commit({onFailure: failureCallback3}); - - expect(transaction1.getStatus()).toBe( - RelayMutationTransactionStatus.COMMITTING - ); - expect(transaction2.getStatus()).toBe( - RelayMutationTransactionStatus.COMMIT_QUEUED - ); - expect(transaction3.getStatus()).toBe( - RelayMutationTransactionStatus.COMMIT_QUEUED - ); - - var failureCallback4 = jest.genMockFunction().mockImplementation(); - var transaction4 = new RelayMutationTransaction(mockMutation2); - transaction4.commit({onFailure: failureCallback4}); - - var failureCallback5 = jest.genMockFunction().mockImplementation(); - var transaction5 = new RelayMutationTransaction(mockMutation2); - transaction5.commit({onFailure: failureCallback5}); - - expect(transaction4.getStatus()).toBe( - RelayMutationTransactionStatus.COMMITTING - ); - expect(transaction5.getStatus()).toBe( - RelayMutationTransactionStatus.COMMIT_QUEUED - ); - expect(RelayNetworkLayer.sendMutation.mock.calls.length).toBe(2); - - var request = RelayNetworkLayer.sendMutation.mock.calls[0][0]; - request.reject(new Error('error')); - jest.runAllTimers(); - - expect(failureCallback1).toBeCalled(); - expect(failureCallback2).toBeCalled(); - expect(failureCallback3).toBeCalled(); - expect(failureCallback4).not.toBeCalled(); - expect(failureCallback5).not.toBeCalled(); - expect(transaction1.getStatus()).toBe( - RelayMutationTransactionStatus.COMMIT_FAILED - ); - expect(() => transaction2.getStatus()).toThrow( - 'Invariant Violation: RelayMutationTransaction: Only pending ' + - 'transactions can be interacted with.' - ); - expect(transaction3.getStatus()).toBe( - RelayMutationTransactionStatus.COLLISION_COMMIT_FAILED - ); - expect(transaction4.getStatus()).toBe( - RelayMutationTransactionStatus.COMMITTING - ); - expect(transaction5.getStatus()).toBe( - RelayMutationTransactionStatus.COMMIT_QUEUED - ); - }); + var failureCallback1 = jest.genMockFunction().mockImplementation( + (transaction, preventAutoRollback) => { + expect(transaction).toBe(transaction1); + expect(transaction.getStatus()).toBe( + RelayMutationTransactionStatus.COMMIT_FAILED + ); + preventAutoRollback(); + } + ); + var transaction1 = new RelayMutationTransaction(mockMutation1); + transaction1.commit({onFailure: failureCallback1}); + + var failureCallback2 = jest.genMockFunction().mockImplementation( + (transaction, preventAutoRollback) => { + expect(transaction).toBe(transaction2); + expect(transaction.getStatus()).toBe( + RelayMutationTransactionStatus.COLLISION_COMMIT_FAILED + ); + } + ); + var transaction2 = new RelayMutationTransaction(mockMutation1); + transaction2.commit({onFailure: failureCallback2}); + + var failureCallback3 = jest.genMockFunction().mockImplementation( + (transaction, preventAutoRollback) => { + expect(transaction).toBe(transaction3); + expect(transaction.getStatus()).toBe( + RelayMutationTransactionStatus.COLLISION_COMMIT_FAILED + ); + preventAutoRollback(); + } + ); + var transaction3 = new RelayMutationTransaction(mockMutation1); + transaction3.commit({onFailure: failureCallback3}); + + expect(transaction1.getStatus()).toBe( + RelayMutationTransactionStatus.COMMITTING + ); + expect(transaction2.getStatus()).toBe( + RelayMutationTransactionStatus.COMMIT_QUEUED + ); + expect(transaction3.getStatus()).toBe( + RelayMutationTransactionStatus.COMMIT_QUEUED + ); + + var failureCallback4 = jest.genMockFunction().mockImplementation(); + var transaction4 = new RelayMutationTransaction(mockMutation2); + transaction4.commit({onFailure: failureCallback4}); + + var failureCallback5 = jest.genMockFunction().mockImplementation(); + var transaction5 = new RelayMutationTransaction(mockMutation2); + transaction5.commit({onFailure: failureCallback5}); + + expect(transaction4.getStatus()).toBe( + RelayMutationTransactionStatus.COMMITTING + ); + expect(transaction5.getStatus()).toBe( + RelayMutationTransactionStatus.COMMIT_QUEUED + ); + expect(RelayNetworkLayer.sendMutation.mock.calls.length).toBe(2); + + var request = RelayNetworkLayer.sendMutation.mock.calls[0][0]; + request.reject(new Error('error')); + jest.runAllTimers(); + + expect(failureCallback1).toBeCalled(); + expect(failureCallback2).toBeCalled(); + expect(failureCallback3).toBeCalled(); + expect(failureCallback4).not.toBeCalled(); + expect(failureCallback5).not.toBeCalled(); + expect(transaction1.getStatus()).toBe( + RelayMutationTransactionStatus.COMMIT_FAILED + ); + expect(() => transaction2.getStatus()).toThrow( + 'Invariant Violation: RelayMutationTransaction: Only pending ' + + 'transactions can be interacted with.' + ); + expect(transaction3.getStatus()).toBe( + RelayMutationTransactionStatus.COLLISION_COMMIT_FAILED + ); + expect(transaction4.getStatus()).toBe( + RelayMutationTransactionStatus.COMMITTING + ); + expect(transaction5.getStatus()).toBe( + RelayMutationTransactionStatus.COMMIT_QUEUED + ); + } + ); }); describe('recommit', () => { diff --git a/src/network-layer/default/RelayDefaultNetworkLayer.js b/src/network-layer/default/RelayDefaultNetworkLayer.js index 61753b23fe89d..6722b0b1e9f34 100644 --- a/src/network-layer/default/RelayDefaultNetworkLayer.js +++ b/src/network-layer/default/RelayDefaultNetworkLayer.js @@ -161,7 +161,7 @@ class RelayDefaultNetworkLayer { * Rejects HTTP responses with a status code that is not >= 200 and < 300. * This is done to follow the internal behavior of `fetchWithRetries`. */ -function throwOnServerError(response: any): any { +function throwOnServerError(response: any): any { if (response.status >= 200 && response.status < 300) { return response; } else { diff --git a/src/network-layer/default/__tests__/RelayDefaultNetworkLayer-test.js b/src/network-layer/default/__tests__/RelayDefaultNetworkLayer-test.js index 86830a6d26d75..b49f045a62cf7 100644 --- a/src/network-layer/default/__tests__/RelayDefaultNetworkLayer-test.js +++ b/src/network-layer/default/__tests__/RelayDefaultNetworkLayer-test.js @@ -45,7 +45,7 @@ describe('RelayDefaultNetworkLayer', () => { RelayConnectionInterface = require('RelayConnectionInterface'); RelayDefaultNetworkLayer = require('RelayDefaultNetworkLayer'); RelayMetaRoute = require('RelayMetaRoute'); - RelayMutationRequest = require('RelayMutationRequest'); + RelayMutationRequest = require('RelayMutationRequest'); RelayQuery = require('RelayQuery'); RelayQueryRequest = require('RelayQueryRequest'); diff --git a/src/query/RelayQuery.js b/src/query/RelayQuery.js index 6de428bfce331..7399b98c49cfb 100644 --- a/src/query/RelayQuery.js +++ b/src/query/RelayQuery.js @@ -16,7 +16,7 @@ var GraphQL = require('GraphQL'); var RelayConnectionInterface = require('RelayConnectionInterface'); var RelayFragmentReference = require('RelayFragmentReference'); -import type {Call} from 'RelayInternalTypes'; +import type {Call} from 'RelayInternalTypes'; var RelayMetaRoute = require('RelayMetaRoute'); var RelayRouteFragment = require('RelayRouteFragment'); import type {Variables} from 'RelayTypes'; diff --git a/src/query/RelayQueryTransform.js b/src/query/RelayQueryTransform.js index 54b89315e083c..7858f64a27574 100644 --- a/src/query/RelayQueryTransform.js +++ b/src/query/RelayQueryTransform.js @@ -14,6 +14,7 @@ 'use strict'; import type RelayQuery from 'RelayQuery'; + var RelayQueryVisitor = require('RelayQueryVisitor'); /** diff --git a/src/query/__tests__/RelayQuery-test.js b/src/query/__tests__/RelayQuery-test.js index a72e370a8cfcb..bfa4918cb4590 100644 --- a/src/query/__tests__/RelayQuery-test.js +++ b/src/query/__tests__/RelayQuery-test.js @@ -731,7 +731,7 @@ describe('RelayQuery', () => { `; var variables = {size: '32'}; var pictureVariable = - getNode(pictureVariableRQL, variables).getChildren()[0]; + getNode(pictureVariableRQL, variables).getChildren()[0]; expect(pictureScalar.equals(pictureVariable)).toBe(true); var diffId = getNode(generatedIdRQL).getChildren()[1]; diff --git a/src/store/RelayNeglectionStateMap.js b/src/store/RelayNeglectionStateMap.js index 3466bb6d6f5ca..f966e26b1a21d 100644 --- a/src/store/RelayNeglectionStateMap.js +++ b/src/store/RelayNeglectionStateMap.js @@ -59,7 +59,7 @@ class RelayNeglectionStateMap { dataID ); data.subscriptions--; - this._map.set(dataID, data); + this._map.set(dataID, data); } increaseSubscriptionsFor(dataID: DataID): void { @@ -70,7 +70,7 @@ class RelayNeglectionStateMap { } var data = this._map.get(dataID); data.subscriptions++; - this._map.set(dataID, data); + this._map.set(dataID, data); } register(dataID: DataID): void { diff --git a/src/store/RelayStoreData.js b/src/store/RelayStoreData.js index 5dd77c7ba4a4a..9096cae1f4b9a 100644 --- a/src/store/RelayStoreData.js +++ b/src/store/RelayStoreData.js @@ -162,7 +162,7 @@ class RelayStoreData { * Runs the callback after all data has been read out from diskc cache into * cachedRecords */ - runWithDiskCache(callback: () => void): void{ + runWithDiskCache(callback: () => void): void { if (this._cachePopulated || !this._cacheManager) { resolveImmediate(callback); } else { diff --git a/src/store/__mocks__/observeAllRelayQueryData.js b/src/store/__mocks__/observeAllRelayQueryData.js index c4fb10c72c93a..7fc015f3d7f49 100644 --- a/src/store/__mocks__/observeAllRelayQueryData.js +++ b/src/store/__mocks__/observeAllRelayQueryData.js @@ -8,6 +8,7 @@ */ 'use strict'; + var actualImplementation = require.requireActual('observeAllRelayQueryData'); var mockImplementation = jest.genMockFunction().mockImplementation( diff --git a/src/store/__mocks__/observeRelayQueryData.js b/src/store/__mocks__/observeRelayQueryData.js index d869eceef141f..1d9eb07797a13 100644 --- a/src/store/__mocks__/observeRelayQueryData.js +++ b/src/store/__mocks__/observeRelayQueryData.js @@ -8,6 +8,7 @@ */ 'use strict'; + var actualImplementation = require.requireActual('observeRelayQueryData'); var mockImplementation = jest.genMockFunction().mockImplementation( diff --git a/src/store/__tests__/RelayRecordStore-test.js b/src/store/__tests__/RelayRecordStore-test.js index 99c27bb9dddfc..41737a4752907 100644 --- a/src/store/__tests__/RelayRecordStore-test.js +++ b/src/store/__tests__/RelayRecordStore-test.js @@ -367,39 +367,41 @@ describe('RelayRecordStore', () => { it('falls through to existing records for fields not in the queued record', () => { - var record = { - id: '4', - name: 'Zuck', - __dataID__: '4', - }; - var queuedRecord = { - id: '4', - __dataID__: '4', - }; - var store = new RelayRecordStore({ - records: {'4': record}, - queuedRecords: {'4': queuedRecord}, - }); - expect(store.getField('4', 'name')).toBe('Zuck'); - }); + var record = { + id: '4', + name: 'Zuck', + __dataID__: '4', + }; + var queuedRecord = { + id: '4', + __dataID__: '4', + }; + var store = new RelayRecordStore({ + records: {'4': record}, + queuedRecords: {'4': queuedRecord}, + }); + expect(store.getField('4', 'name')).toBe('Zuck'); + } + ); it('falls through to cached records for fields not in the existing record', () => { - var record = { - id: '4', - __dataID__: '4', - }; - var cachedRecord = { - id: '4', - name: 'Mark', - __dataID__: '4', - }; - var store = new RelayRecordStore({ - cachedRecords: {'4': cachedRecord}, - records: {'4': record}, - }); - expect(store.getField('4', 'name')).toBe('Mark'); - }); + var record = { + id: '4', + __dataID__: '4', + }; + var cachedRecord = { + id: '4', + name: 'Mark', + __dataID__: '4', + }; + var store = new RelayRecordStore({ + cachedRecords: {'4': cachedRecord}, + records: {'4': record}, + }); + expect(store.getField('4', 'name')).toBe('Mark'); + } + ); }); describe('getLinkedRecordID()', () => { diff --git a/src/store/__tests__/RelayRecordStore_write-test.js b/src/store/__tests__/RelayRecordStore_write-test.js index 078ef74c1c688..6e3348e12f7b5 100644 --- a/src/store/__tests__/RelayRecordStore_write-test.js +++ b/src/store/__tests__/RelayRecordStore_write-test.js @@ -420,7 +420,7 @@ describe('RelayRecordStore', () => { ); }); - it('overwrites ranges if present', () => { + it('overwrites ranges if present', () => { var cache = RelayMockCacheManager.genCacheManager(); var records = {}; var store = new RelayRecordStore({records}, null, null, cache); diff --git a/src/store/__tests__/observeAllRelayQueryData-test.js b/src/store/__tests__/observeAllRelayQueryData-test.js index 3e052b65d9135..e8eeb9f90fd62 100644 --- a/src/store/__tests__/observeAllRelayQueryData-test.js +++ b/src/store/__tests__/observeAllRelayQueryData-test.js @@ -194,7 +194,7 @@ describe('observeRelayQueryData', () => { ]); }); - it('calls the callback with data in the same order the dataIDs are', () =>{ + it('calls the callback with data in the same order the dataIDs are', () => { var query = getNode(Relay.QL`fragment on Node @relay(plural:true){id}`); var records = { a: {__dataID__: 'a', id: 1}, diff --git a/src/store/__tests__/observeRelayQueryData-test.js b/src/store/__tests__/observeRelayQueryData-test.js index 73304a2ed7160..3da9a21dafd17 100644 --- a/src/store/__tests__/observeRelayQueryData-test.js +++ b/src/store/__tests__/observeRelayQueryData-test.js @@ -151,88 +151,86 @@ describe('observeRelayQueryData', () => { }); it('calls subscribers when data is added to an observed node', () => { - var recordsStore = new RelayRecordStore({records: { - user: {id: 1, name: 'Chris', birthdate: {__dataID__: 'date'}}, - date: null, - }}); - var query = getNode(Relay.QL`fragment on User{id, name, birthdate {day}}`); - var observable = observeRelayQueryData(recordsStore, query, 'user'); + var recordsStore = new RelayRecordStore({records: { + user: {id: 1, name: 'Chris', birthdate: {__dataID__: 'date'}}, + date: null, + }}); + var query = getNode(Relay.QL`fragment on User{id, name, birthdate {day}}`); + var observable = observeRelayQueryData(recordsStore, query, 'user'); - observable.subscribe({onNext: firstMockCallback}); - var handleUpdate = addListenerForIDs.mock.calls[0][1]; + observable.subscribe({onNext: firstMockCallback}); + var handleUpdate = addListenerForIDs.mock.calls[0][1]; - // Mutate birthdate record - recordsStore.putRecord('date'); - recordsStore.putField('date', 'day', 30); - handleUpdate(); + // Mutate birthdate record + recordsStore.putRecord('date'); + recordsStore.putField('date', 'day', 30); + handleUpdate(); - expect(firstMockCallback).toBeCalledWith({ - __dataID__: 'user', - id: 1, - name: 'Chris', - birthdate: { - __dataID__: 'date', - day: 30, - }, - }); - expect(addListenerForIDs.mock.remove[0]).toBeCalled(); - expect(addListenerForIDs.mock.calls[1][0]).toEqual([ - 'user', 'date' - ]); - } - ); + expect(firstMockCallback).toBeCalledWith({ + __dataID__: 'user', + id: 1, + name: 'Chris', + birthdate: { + __dataID__: 'date', + day: 30, + }, + }); + expect(addListenerForIDs.mock.remove[0]).toBeCalled(); + expect(addListenerForIDs.mock.calls[1][0]).toEqual([ + 'user', 'date' + ]); + }); it('calls a subscriber when data disappears from a node', () => { - var recordsStore = new RelayRecordStore({records: { - user: {id: 1, name: 'Jon', birthdate: {__dataID__: 'date'}}, - date: {day: 15 }, - }}); - var query = getNode(Relay.QL`fragment on User{id, name, birthdate {day}}`); - var observable = observeRelayQueryData(recordsStore, query, 'user'); + var recordsStore = new RelayRecordStore({records: { + user: {id: 1, name: 'Jon', birthdate: {__dataID__: 'date'}}, + date: {day: 15 }, + }}); + var query = getNode(Relay.QL`fragment on User{id, name, birthdate {day}}`); + var observable = observeRelayQueryData(recordsStore, query, 'user'); - observable.subscribe({onNext: firstMockCallback}); - var handleUpdate = addListenerForIDs.mock.calls[0][1]; + observable.subscribe({onNext: firstMockCallback}); + var handleUpdate = addListenerForIDs.mock.calls[0][1]; - // Remove record from store - recordsStore.deleteRecord('date'); - handleUpdate(); + // Remove record from store + recordsStore.deleteRecord('date'); + handleUpdate(); - expect(firstMockCallback).toBeCalledWith({ - __dataID__: 'user', - id: 1, - name: 'Jon', - birthdate: null, - }); - expect(addListenerForIDs.mock.calls[0][0]).toEqual([ - 'user', 'date' - ]); - expect(addListenerForIDs.mock.remove[0]).toBeCalled(); - expect(addListenerForIDs.mock.calls[1][0]).toEqual([ - 'user', 'date' - ]); - } - ); + expect(firstMockCallback).toBeCalledWith({ + __dataID__: 'user', + id: 1, + name: 'Jon', + birthdate: null, + }); + expect(addListenerForIDs.mock.calls[0][0]).toEqual([ + 'user', 'date' + ]); + expect(addListenerForIDs.mock.remove[0]).toBeCalled(); + expect(addListenerForIDs.mock.calls[1][0]).toEqual([ + 'user', 'date' + ]); + }); it('no longer calls disposed-of subscribers when data changes', () => { - var recordsStore = new RelayRecordStore({records: { - user: {id: 1, name: 'Jon', birthdate: {__dataID__: 'date'}}, - date: {day: 15 }, - }}); - var query = getNode(Relay.QL`fragment on User{id, name, birthdate {day}}`); - var observable = observeRelayQueryData(recordsStore, query, 'user'); + var recordsStore = new RelayRecordStore({records: { + user: {id: 1, name: 'Jon', birthdate: {__dataID__: 'date'}}, + date: {day: 15 }, + }}); + var query = getNode(Relay.QL`fragment on User{id, name, birthdate {day}}`); + var observable = observeRelayQueryData(recordsStore, query, 'user'); - observable.subscribe({onNext: firstMockCallback}); - var handleUpdate = addListenerForIDs.mock.calls[0][1]; - var subscription = observable.subscribe({onNext: secondMockCallback}); + observable.subscribe({onNext: firstMockCallback}); + var handleUpdate = addListenerForIDs.mock.calls[0][1]; + var subscription = observable.subscribe({onNext: secondMockCallback}); - expect(secondMockCallback).toBeCalled(); + expect(secondMockCallback).toBeCalled(); - subscription.dispose(); - recordsStore.deleteRecord('date'); - handleUpdate(); + subscription.dispose(); + recordsStore.deleteRecord('date'); + handleUpdate(); - expect(firstMockCallback.mock.calls.length).toBe(2); - expect(secondMockCallback.mock.calls.length).toBe(1); + expect(firstMockCallback.mock.calls.length).toBe(2); + expect(secondMockCallback.mock.calls.length).toBe(1); }); describe('garbage collection', () => { diff --git a/src/store/__tests__/readRelayQueryData-test.js b/src/store/__tests__/readRelayQueryData-test.js index b6857b479b0eb..1659f001461f7 100644 --- a/src/store/__tests__/readRelayQueryData-test.js +++ b/src/store/__tests__/readRelayQueryData-test.js @@ -838,35 +838,36 @@ describe('readRelayQueryData', () => { it('does not clobber previously-read sibling fields when a linked dataID ' + 'is `null` or `undefined`', () => { - var query = getNode(Relay.QL` - fragment on User { - id, - address { - city, - }, - } - `); - var records = { - user_id: { - __dataID__: 'user_id', - id: 'user_id', - address: null, - }, - }; - var data = getData({records}, query, 'user_id'); - expect(data.address).toBeNull(); - expect(data.id).toBe('user_id'); - - records = { - user_id: { - __dataID__: 'user_id', - id: 'user_id', - }, - }; - data = getData({records}, query, 'user_id'); - expect(data.address).toBeUndefined(); - expect(data.id).toBe('user_id'); - }); + var query = getNode(Relay.QL` + fragment on User { + id, + address { + city, + }, + } + `); + var records = { + user_id: { + __dataID__: 'user_id', + id: 'user_id', + address: null, + }, + }; + var data = getData({records}, query, 'user_id'); + expect(data.address).toBeNull(); + expect(data.id).toBe('user_id'); + + records = { + user_id: { + __dataID__: 'user_id', + id: 'user_id', + }, + }; + data = getData({records}, query, 'user_id'); + expect(data.address).toBeUndefined(); + expect(data.id).toBe('user_id'); + } + ); it('does not set undefined value if linked dataID missing', () => { var query = getNode(Relay.QL` diff --git a/src/store/observeRelayQueryData.js b/src/store/observeRelayQueryData.js index c18da5d930522..55400d5c2e2fa 100644 --- a/src/store/observeRelayQueryData.js +++ b/src/store/observeRelayQueryData.js @@ -12,6 +12,7 @@ */ 'use strict'; + var GraphQLStoreChangeEmitter = require('GraphQLStoreChangeEmitter'); var RelayError = require('RelayError'); import type {DataID} from 'RelayInternalTypes'; diff --git a/src/tools/__mocks__/RelayTestUtils.js b/src/tools/__mocks__/RelayTestUtils.js index 8d963d6f5bb0a..fd20d04c04a87 100644 --- a/src/tools/__mocks__/RelayTestUtils.js +++ b/src/tools/__mocks__/RelayTestUtils.js @@ -397,7 +397,7 @@ var RelayTestUtils = { * when the objects match. */ toMatchQueryJSON(expected) { - var matchQueryJSON = (actual, expected, path) => { + var matchQueryJSON = (actual, expected, path) => { if (typeof actual !== 'object') { if (actual === expected) { return true; diff --git a/src/tools/__tests__/RelayTaskScheduler-test.js b/src/tools/__tests__/RelayTaskScheduler-test.js index 28cb7cfa5b758..c403e03a0903c 100644 --- a/src/tools/__tests__/RelayTaskScheduler-test.js +++ b/src/tools/__tests__/RelayTaskScheduler-test.js @@ -112,7 +112,9 @@ describe('RelayTaskScheduler', () => { RelayTaskScheduler.await( () => 'foo', - () => { throw mockError; }, + () => { + throw mockError; + }, mockCallback, ).catch(mockFailureCallback); @@ -129,7 +131,9 @@ describe('RelayTaskScheduler', () => { var mockSuccessCallback = jest.genMockFunction(); RelayTaskScheduler.await( - () => { throw mockError; }, + () => { + throw mockError; + }, ).catch(mockFailureCallback); RelayTaskScheduler.await( diff --git a/src/traversal/__tests__/checkRelayQueryData-test.js b/src/traversal/__tests__/checkRelayQueryData-test.js index 9fa6a24d2e9ab..5ee844ae9bf78 100644 --- a/src/traversal/__tests__/checkRelayQueryData-test.js +++ b/src/traversal/__tests__/checkRelayQueryData-test.js @@ -88,7 +88,7 @@ describe('checkRelayQueryData', () => { expect(result).toEqual(true); }); - it('returns true when checking basic id query', () => { + it('returns true when checking basic id query', () => { var records = { 1055790163: { id: '1055790163', diff --git a/src/traversal/__tests__/diffRelayQuery_connection-test.js b/src/traversal/__tests__/diffRelayQuery_connection-test.js index 3e32ef7c78041..2a0813b4a9296 100644 --- a/src/traversal/__tests__/diffRelayQuery_connection-test.js +++ b/src/traversal/__tests__/diffRelayQuery_connection-test.js @@ -330,231 +330,233 @@ describe('diffRelayQuery', () => { it('fetches missing `node` data via a `node()` query and missing `edges` '+ 'data via a `connection.find()` query if connection is findable', () => { - var records = {}; - var store = new RelayRecordStore({records}, {map: rootCallMap}); - var tracker = new RelayQueryTracker(); - - var alias = generateRQLFieldAlias('newsFeed.first(3)'); - var payload = { - viewer: { - [alias]: { - edges: [ - {cursor: 'c1', node: {id:'s1', message:{text:'s1'}}}, - {cursor: 'c2', node: {id:'s2', message:{text:'s1'}}}, - {cursor: 'c3', node: {id:'s3', message:{text:'s1'}}}, - ], - [PAGE_INFO]: { - [HAS_NEXT_PAGE]: true, - [HAS_PREV_PAGE]: false, + var records = {}; + var store = new RelayRecordStore({records}, {map: rootCallMap}); + var tracker = new RelayQueryTracker(); + + var alias = generateRQLFieldAlias('newsFeed.first(3)'); + var payload = { + viewer: { + [alias]: { + edges: [ + {cursor: 'c1', node: {id:'s1', message:{text:'s1'}}}, + {cursor: 'c2', node: {id:'s2', message:{text:'s1'}}}, + {cursor: 'c3', node: {id:'s3', message:{text:'s1'}}}, + ], + [PAGE_INFO]: { + [HAS_NEXT_PAGE]: true, + [HAS_PREV_PAGE]: false, + }, }, }, - }, - }; - var writeQuery = getNode(Relay.QL` - query { - viewer { - newsFeed(first:"3") { - edges { - node { - message { - text + }; + var writeQuery = getNode(Relay.QL` + query { + viewer { + newsFeed(first:"3") { + edges { + node { + message { + text + } } } } } } - } - `); - writePayload(store, writeQuery, payload, tracker); - - // node: `feedback{id}` is missing (fetch via node() query) - // edges: `sortKey` is missing (fetch via .find() query) - var fetchQuery = getNode(Relay.QL` - query { - viewer { - newsFeed(first:"3") { - edges { - sortKey, - node { - feedback { - id + `); + writePayload(store, writeQuery, payload, tracker); + + // node: `feedback{id}` is missing (fetch via node() query) + // edges: `sortKey` is missing (fetch via .find() query) + var fetchQuery = getNode(Relay.QL` + query { + viewer { + newsFeed(first:"3") { + edges { + sortKey, + node { + feedback { + id + } } } } } } - } - `); - var diffQueries = diffRelayQuery(fetchQuery, store, tracker); - expect(diffQueries.length).toBe(6); - expect(diffQueries[0]).toEqualQueryRoot(getNode(Relay.QL` - query { - node(id:"s1") { - feedback { - id + `); + var diffQueries = diffRelayQuery(fetchQuery, store, tracker); + expect(diffQueries.length).toBe(6); + expect(diffQueries[0]).toEqualQueryRoot(getNode(Relay.QL` + query { + node(id:"s1") { + feedback { + id + } } } - } - `)); - expect(diffQueries[1]).toEqualQueryRoot(getVerbatimNode(Relay.QL` - query { - viewer { - newsFeed(find:"s1") { - edges { - cursor, - node { - id - }, - sortKey, + `)); + expect(diffQueries[1]).toEqualQueryRoot(getVerbatimNode(Relay.QL` + query { + viewer { + newsFeed(find:"s1") { + edges { + cursor, + node { + id + }, + sortKey, + } } } } - } - `)); - expect(diffQueries[2]).toEqualQueryRoot(getNode(Relay.QL` - query { - node(id:"s2") { - feedback { - id + `)); + expect(diffQueries[2]).toEqualQueryRoot(getNode(Relay.QL` + query { + node(id:"s2") { + feedback { + id + } } } - } - `)); - expect(diffQueries[3]).toEqualQueryRoot(getVerbatimNode(Relay.QL` - query { - viewer { - newsFeed(find:"s2") { - edges { - cursor, - node { - id - }, - sortKey, + `)); + expect(diffQueries[3]).toEqualQueryRoot(getVerbatimNode(Relay.QL` + query { + viewer { + newsFeed(find:"s2") { + edges { + cursor, + node { + id + }, + sortKey, + } } } } - } - `)); - expect(diffQueries[4]).toEqualQueryRoot(getNode(Relay.QL` - query { - node(id:"s3") { - feedback { - id + `)); + expect(diffQueries[4]).toEqualQueryRoot(getNode(Relay.QL` + query { + node(id:"s3") { + feedback { + id + } } } - } - `)); - expect(diffQueries[5]).toEqualQueryRoot(getVerbatimNode(Relay.QL` - query { - viewer { - newsFeed(find:"s3") { - edges { - cursor, - node { - id - }, - sortKey, + `)); + expect(diffQueries[5]).toEqualQueryRoot(getVerbatimNode(Relay.QL` + query { + viewer { + newsFeed(find:"s3") { + edges { + cursor, + node { + id + }, + sortKey, + } } } } - } - `)); - }); + `)); + } + ); it('fetches missing `node` data via a `node()` query and warns about ' + 'unfetchable `edges` data if connection is not findable', () => { - var records = {}; - var store = new RelayRecordStore({records}, {map: rootCallMap}); - var tracker = new RelayQueryTracker(); - - var alias = generateRQLFieldAlias('notificationStories.first(3)'); - var payload = { - viewer: { - [alias]: { - edges: [ - {cursor: 'c1', node: {id:'s1', message:{text:'s1'}}}, - {cursor: 'c2', node: {id:'s2', message:{text:'s1'}}}, - {cursor: 'c3', node: {id:'s3', message:{text:'s1'}}}, - ], - [PAGE_INFO]: { - [HAS_NEXT_PAGE]: true, - [HAS_PREV_PAGE]: false, + var records = {}; + var store = new RelayRecordStore({records}, {map: rootCallMap}); + var tracker = new RelayQueryTracker(); + + var alias = generateRQLFieldAlias('notificationStories.first(3)'); + var payload = { + viewer: { + [alias]: { + edges: [ + {cursor: 'c1', node: {id:'s1', message:{text:'s1'}}}, + {cursor: 'c2', node: {id:'s2', message:{text:'s1'}}}, + {cursor: 'c3', node: {id:'s3', message:{text:'s1'}}}, + ], + [PAGE_INFO]: { + [HAS_NEXT_PAGE]: true, + [HAS_PREV_PAGE]: false, + }, }, }, - }, - }; - var writeQuery = getNode(Relay.QL` - query { - viewer { - notificationStories(first:"3") { - edges { - node { - message { - text + }; + var writeQuery = getNode(Relay.QL` + query { + viewer { + notificationStories(first:"3") { + edges { + node { + message { + text + } } } } } } - } - `); - writePayload(store, writeQuery, payload, tracker); - - // node: `feedback{id}` is missing (fetch via node() query) - // edges: `showBeeper` is missing but cannot be refetched because - // `notificationStories` does not support `.find()` - var fetchQuery = getNode(Relay.QL` - query { - viewer { - notificationStories(first:"3") { - edges { - showBeeper, - node { - feedback { - id + `); + writePayload(store, writeQuery, payload, tracker); + + // node: `feedback{id}` is missing (fetch via node() query) + // edges: `showBeeper` is missing but cannot be refetched because + // `notificationStories` does not support `.find()` + var fetchQuery = getNode(Relay.QL` + query { + viewer { + notificationStories(first:"3") { + edges { + showBeeper, + node { + feedback { + id + } } } } } } - } - `); - var diffQueries = diffRelayQuery(fetchQuery, store, tracker); - expect(diffQueries.length).toBe(3); - expect(diffQueries[0]).toEqualQueryRoot(getNode(Relay.QL` - query { - node(id:"s1") { - feedback { - id + `); + var diffQueries = diffRelayQuery(fetchQuery, store, tracker); + expect(diffQueries.length).toBe(3); + expect(diffQueries[0]).toEqualQueryRoot(getNode(Relay.QL` + query { + node(id:"s1") { + feedback { + id + } } } - } - `)); - expect(diffQueries[1]).toEqualQueryRoot(getNode(Relay.QL` - query { - node(id:"s2") { - feedback { - id + `)); + expect(diffQueries[1]).toEqualQueryRoot(getNode(Relay.QL` + query { + node(id:"s2") { + feedback { + id + } } } - } - `)); - expect(diffQueries[2]).toEqualQueryRoot(getNode(Relay.QL` - query { - node(id:"s3") { - feedback { - id + `)); + expect(diffQueries[2]).toEqualQueryRoot(getNode(Relay.QL` + query { + node(id:"s3") { + feedback { + id + } } } - } - `)); - expect([ - 'RelayDiffQueryBuilder: connection `edges{*}` fields can only be ' + - 'refetched if the connection supports the `find` call. Cannot ' + - 'refetch data for field `%s`.', - 'notificationStories', - ]).toBeWarnedNTimes(3); - }); + `)); + expect([ + 'RelayDiffQueryBuilder: connection `edges{*}` fields can only be ' + + 'refetched if the connection supports the `find` call. Cannot ' + + 'refetch data for field `%s`.', + 'notificationStories', + ]).toBeWarnedNTimes(3); + } + ); it('does not flatten fragments when creating new root queries', () => { var records = {}; diff --git a/src/traversal/__tests__/inferRelayFieldsFromData-test.js b/src/traversal/__tests__/inferRelayFieldsFromData-test.js index 15490f38f61e9..9ccc3cfbe38be 100644 --- a/src/traversal/__tests__/inferRelayFieldsFromData-test.js +++ b/src/traversal/__tests__/inferRelayFieldsFromData-test.js @@ -106,7 +106,7 @@ describe('inferRelayFieldsFromData', function() { id: '123', screennames: [ {service: 'GTALK'}, - {service: "TWITTER"}, + {service: 'TWITTER'}, ], })).toEqualFields(Relay.QL` fragment on Actor { id, diff --git a/src/traversal/__tests__/splitDeferredRelayQueries-test.js b/src/traversal/__tests__/splitDeferredRelayQueries-test.js index a276c146dac0c..624d10465b826 100644 --- a/src/traversal/__tests__/splitDeferredRelayQueries-test.js +++ b/src/traversal/__tests__/splitDeferredRelayQueries-test.js @@ -274,8 +274,9 @@ describe('splitDeferredRelayQueries()', () => { // field has two `node` children: // - the requisite `node{id}` // - the nested deferred fragment - expect(flattenRelayQuery(deferred[0].deferred[0].required)). - toEqualQueryRoot(flattenRelayQuery(getNode(Relay.QL` + expect( + flattenRelayQuery(deferred[0].deferred[0].required) + ).toEqualQueryRoot(flattenRelayQuery(getNode(Relay.QL` query { viewer { newsFeed { diff --git a/src/traversal/__tests__/writeRelayQueryPayload_connectionField-test.js b/src/traversal/__tests__/writeRelayQueryPayload_connectionField-test.js index 9d9830c5f1b49..b60b5a49957eb 100644 --- a/src/traversal/__tests__/writeRelayQueryPayload_connectionField-test.js +++ b/src/traversal/__tests__/writeRelayQueryPayload_connectionField-test.js @@ -411,7 +411,7 @@ describe('writeRelayQueryPayload()', () => { id: 'friend1ID' }, source: { - id: '123' + id: '123' } } ], diff --git a/src/traversal/checkRelayQueryData.js b/src/traversal/checkRelayQueryData.js index ccf0125b6ce19..c7e51509fdb88 100644 --- a/src/traversal/checkRelayQueryData.js +++ b/src/traversal/checkRelayQueryData.js @@ -145,7 +145,7 @@ class RelayQueryChecker extends RelayQueryVisitor { return; } if (dataIDs) { - for (var ii = 0; ii < dataIDs.length; ii++){ + for (var ii = 0; ii < dataIDs.length; ii++) { if (!state.result) { break; } @@ -192,8 +192,8 @@ class RelayQueryChecker extends RelayQueryVisitor { return; } var edges = rangeInfo.requestedEdges; - for (var ii = 0; ii < edges.length; ii++){ - if (!state.result){ + for (var ii = 0; ii < edges.length; ii++) { + if (!state.result) { break; } var nextState = {