relay-compiler 9.0.0 → 9.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (197) hide show
  1. package/bin/RelayCompilerBin.js.flow +169 -0
  2. package/bin/RelayCompilerMain.js.flow +508 -0
  3. package/bin/__fixtures__/plugin-module.js.flow +17 -0
  4. package/bin/relay-compiler +2002 -1733
  5. package/codegen/CodegenDirectory.js.flow +375 -0
  6. package/codegen/CodegenRunner.js.flow +431 -0
  7. package/codegen/CodegenTypes.js.flow +28 -0
  8. package/codegen/CodegenWatcher.js.flow +254 -0
  9. package/codegen/NormalizationCodeGenerator.js.flow +499 -0
  10. package/codegen/ReaderCodeGenerator.js.flow +453 -0
  11. package/codegen/RelayCodeGenerator.js.flow +76 -0
  12. package/codegen/RelayFileWriter.js.flow +366 -0
  13. package/codegen/SourceControl.js.flow +58 -0
  14. package/codegen/compileRelayArtifacts.js.flow +182 -0
  15. package/codegen/createPrintRequireModuleDependency.js.flow +21 -0
  16. package/codegen/writeRelayGeneratedFile.js.flow +194 -0
  17. package/core/ASTCache.js.flow +73 -0
  18. package/core/ASTConvert.js.flow +233 -0
  19. package/core/CompilerContext.js.flow +190 -0
  20. package/core/CompilerError.js.flow +250 -0
  21. package/core/DotGraphQLParser.js.flow +39 -0
  22. package/core/GraphQLCompilerProfiler.js.flow +341 -0
  23. package/core/GraphQLDerivedFromMetadata.js.flow +48 -0
  24. package/core/GraphQLWatchmanClient.js.flow +111 -0
  25. package/core/IR.js.flow +329 -0
  26. package/core/IRPrinter.js.flow +488 -0
  27. package/core/IRTransformer.js.flow +377 -0
  28. package/core/IRValidator.js.flow +260 -0
  29. package/core/IRVisitor.js.flow +150 -0
  30. package/core/JSModuleParser.js.flow +24 -0
  31. package/core/RelayCompilerScope.js.flow +199 -0
  32. package/core/RelayFindGraphQLTags.js.flow +119 -0
  33. package/core/RelayGraphQLEnumsGenerator.js.flow +55 -0
  34. package/core/RelayIRTransforms.js.flow +130 -0
  35. package/core/RelayParser.js.flow +1759 -0
  36. package/core/RelaySourceModuleParser.js.flow +135 -0
  37. package/core/Schema.js.flow +1985 -0
  38. package/core/SchemaUtils.js.flow +109 -0
  39. package/core/filterContextForNode.js.flow +50 -0
  40. package/core/getFieldDefinition.js.flow +156 -0
  41. package/core/getIdentifierForArgumentValue.js.flow +49 -0
  42. package/core/getIdentifierForSelection.js.flow +69 -0
  43. package/core/getLiteralArgumentValues.js.flow +32 -0
  44. package/core/getNormalizationOperationName.js.flow +19 -0
  45. package/core/inferRootArgumentDefinitions.js.flow +323 -0
  46. package/index.js +1 -1
  47. package/index.js.flow +202 -0
  48. package/language/RelayLanguagePluginInterface.js.flow +283 -0
  49. package/language/javascript/FindGraphQLTags.js.flow +233 -0
  50. package/language/javascript/RelayFlowBabelFactories.js.flow +180 -0
  51. package/language/javascript/RelayFlowGenerator.js.flow +1040 -0
  52. package/language/javascript/RelayFlowTypeTransformers.js.flow +184 -0
  53. package/language/javascript/RelayLanguagePluginJavaScript.js.flow +34 -0
  54. package/language/javascript/formatGeneratedModule.js.flow +65 -0
  55. package/lib/bin/RelayCompilerBin.js +10 -0
  56. package/lib/bin/RelayCompilerMain.js +113 -119
  57. package/lib/codegen/CodegenDirectory.js +2 -6
  58. package/lib/codegen/CodegenRunner.js +34 -75
  59. package/lib/codegen/CodegenWatcher.js +13 -21
  60. package/lib/codegen/NormalizationCodeGenerator.js +43 -40
  61. package/lib/codegen/ReaderCodeGenerator.js +43 -35
  62. package/lib/codegen/RelayCodeGenerator.js +7 -5
  63. package/lib/codegen/RelayFileWriter.js +15 -36
  64. package/lib/codegen/compileRelayArtifacts.js +16 -30
  65. package/lib/codegen/writeRelayGeneratedFile.js +56 -98
  66. package/lib/core/ASTCache.js +1 -3
  67. package/lib/core/CompilerContext.js +1 -3
  68. package/lib/core/CompilerError.js +27 -54
  69. package/lib/core/GraphQLCompilerProfiler.js +8 -12
  70. package/lib/core/GraphQLWatchmanClient.js +4 -12
  71. package/lib/core/IRPrinter.js +5 -5
  72. package/lib/core/IRTransformer.js +8 -6
  73. package/lib/core/IRValidator.js +1 -3
  74. package/lib/core/RelayCompilerScope.js +4 -4
  75. package/lib/core/RelayGraphQLEnumsGenerator.js +12 -15
  76. package/lib/core/RelayIRTransforms.js +9 -5
  77. package/lib/core/RelayParser.js +44 -56
  78. package/lib/core/RelaySourceModuleParser.js +1 -3
  79. package/lib/core/Schema.js +78 -65
  80. package/lib/core/getFieldDefinition.js +12 -15
  81. package/lib/core/getIdentifierForSelection.js +1 -1
  82. package/lib/core/inferRootArgumentDefinitions.js +27 -36
  83. package/lib/language/javascript/RelayFlowGenerator.js +49 -78
  84. package/lib/language/javascript/RelayFlowTypeTransformers.js +1 -3
  85. package/lib/reporters/ConsoleReporter.js +1 -3
  86. package/lib/reporters/MultiReporter.js +1 -3
  87. package/lib/runner/Artifacts.js +69 -170
  88. package/lib/runner/BufferedFilesystem.js +32 -66
  89. package/lib/runner/GraphQLASTNodeGroup.js +54 -120
  90. package/lib/runner/GraphQLNodeMap.js +14 -19
  91. package/lib/runner/Sources.js +49 -78
  92. package/lib/runner/StrictMap.js +20 -36
  93. package/lib/runner/getChangedNodeNames.js +30 -62
  94. package/lib/transforms/ApplyFragmentArgumentTransform.js +33 -28
  95. package/lib/transforms/ClientExtensionsTransform.js +7 -12
  96. package/lib/transforms/ConnectionTransform.js +26 -24
  97. package/lib/transforms/DeferStreamTransform.js +20 -16
  98. package/lib/transforms/DisallowTypenameOnRoot.js +55 -0
  99. package/lib/transforms/FieldHandleTransform.js +6 -2
  100. package/lib/transforms/FlattenTransform.js +19 -14
  101. package/lib/transforms/GenerateIDFieldTransform.js +7 -3
  102. package/lib/transforms/GenerateTypeNameTransform.js +6 -2
  103. package/lib/transforms/InlineDataFragmentTransform.js +7 -3
  104. package/lib/transforms/MaskTransform.js +17 -17
  105. package/lib/transforms/MatchTransform.js +110 -32
  106. package/lib/transforms/RefetchableFragmentTransform.js +21 -17
  107. package/lib/transforms/RelayDirectiveTransform.js +11 -3
  108. package/lib/transforms/SkipClientExtensionsTransform.js +8 -0
  109. package/lib/transforms/SkipHandleFieldTransform.js +6 -2
  110. package/lib/transforms/SkipRedundantNodesTransform.js +6 -2
  111. package/lib/transforms/SkipSplitOperationTransform.js +32 -0
  112. package/lib/transforms/SkipUnreachableNodeTransform.js +9 -2
  113. package/lib/transforms/SkipUnusedVariablesTransform.js +18 -17
  114. package/lib/transforms/SplitModuleImportTransform.js +2 -2
  115. package/lib/transforms/TestOperationTransform.js +7 -3
  116. package/lib/transforms/ValidateGlobalVariablesTransform.js +18 -30
  117. package/lib/transforms/ValidateRequiredArgumentsTransform.js +12 -15
  118. package/lib/transforms/ValidateServerOnlyDirectivesTransform.js +16 -30
  119. package/lib/transforms/ValidateUnusedVariablesTransform.js +18 -30
  120. package/lib/transforms/query-generators/FetchableQueryGenerator.js +161 -0
  121. package/lib/transforms/query-generators/NodeQueryGenerator.js +7 -2
  122. package/lib/transforms/query-generators/QueryQueryGenerator.js +1 -0
  123. package/lib/transforms/query-generators/ViewerQueryGenerator.js +1 -0
  124. package/lib/transforms/query-generators/index.js +23 -6
  125. package/lib/transforms/query-generators/utils.js +12 -15
  126. package/lib/util/RelayCompilerCache.js +1 -3
  127. package/lib/util/dedupeJSONStringify.js +15 -12
  128. package/lib/util/getModuleName.js +1 -1
  129. package/package.json +2 -2
  130. package/relay-compiler.js +4 -4
  131. package/relay-compiler.min.js +4 -4
  132. package/reporters/ConsoleReporter.js.flow +81 -0
  133. package/reporters/MultiReporter.js.flow +43 -0
  134. package/reporters/Reporter.js.flow +19 -0
  135. package/runner/Artifacts.js.flow +219 -0
  136. package/runner/BufferedFilesystem.js.flow +194 -0
  137. package/runner/GraphQLASTNodeGroup.js.flow +176 -0
  138. package/runner/GraphQLASTUtils.js.flow +26 -0
  139. package/runner/GraphQLNodeMap.js.flow +55 -0
  140. package/runner/Sources.js.flow +218 -0
  141. package/runner/StrictMap.js.flow +96 -0
  142. package/runner/compileArtifacts.js.flow +76 -0
  143. package/runner/extractAST.js.flow +100 -0
  144. package/runner/getChangedNodeNames.js.flow +48 -0
  145. package/runner/getSchemaInstance.js.flow +36 -0
  146. package/runner/types.js.flow +37 -0
  147. package/transforms/ApplyFragmentArgumentTransform.js.flow +474 -0
  148. package/transforms/ClientExtensionsTransform.js.flow +220 -0
  149. package/transforms/ConnectionTransform.js.flow +869 -0
  150. package/transforms/DeferStreamTransform.js.flow +258 -0
  151. package/transforms/DisallowIdAsAlias.js.flow +47 -0
  152. package/transforms/DisallowTypenameOnRoot.js.flow +45 -0
  153. package/transforms/FieldHandleTransform.js.flow +80 -0
  154. package/transforms/FilterDirectivesTransform.js.flow +45 -0
  155. package/transforms/FlattenTransform.js.flow +456 -0
  156. package/transforms/GenerateIDFieldTransform.js.flow +134 -0
  157. package/transforms/GenerateTypeNameTransform.js.flow +81 -0
  158. package/transforms/InlineDataFragmentTransform.js.flow +124 -0
  159. package/transforms/InlineFragmentsTransform.js.flow +71 -0
  160. package/transforms/MaskTransform.js.flow +126 -0
  161. package/transforms/MatchTransform.js.flow +583 -0
  162. package/transforms/RefetchableFragmentTransform.js.flow +272 -0
  163. package/transforms/RelayDirectiveTransform.js.flow +99 -0
  164. package/transforms/SkipClientExtensionsTransform.js.flow +54 -0
  165. package/transforms/SkipHandleFieldTransform.js.flow +44 -0
  166. package/transforms/SkipRedundantNodesTransform.js.flow +253 -0
  167. package/transforms/SkipSplitOperationTransform.js.flow +37 -0
  168. package/transforms/SkipUnreachableNodeTransform.js.flow +149 -0
  169. package/transforms/SkipUnusedVariablesTransform.js.flow +59 -0
  170. package/transforms/SplitModuleImportTransform.js.flow +98 -0
  171. package/transforms/TestOperationTransform.js.flow +138 -0
  172. package/transforms/TransformUtils.js.flow +26 -0
  173. package/transforms/ValidateGlobalVariablesTransform.js.flow +81 -0
  174. package/transforms/ValidateRequiredArgumentsTransform.js.flow +127 -0
  175. package/transforms/ValidateServerOnlyDirectivesTransform.js.flow +112 -0
  176. package/transforms/ValidateUnusedVariablesTransform.js.flow +89 -0
  177. package/transforms/query-generators/FetchableQueryGenerator.js.flow +190 -0
  178. package/transforms/query-generators/NodeQueryGenerator.js.flow +206 -0
  179. package/transforms/query-generators/QueryQueryGenerator.js.flow +57 -0
  180. package/transforms/query-generators/ViewerQueryGenerator.js.flow +97 -0
  181. package/transforms/query-generators/index.js.flow +90 -0
  182. package/transforms/query-generators/utils.js.flow +72 -0
  183. package/util/CodeMarker.js.flow +79 -0
  184. package/util/DefaultHandleKey.js.flow +17 -0
  185. package/util/RelayCompilerCache.js.flow +88 -0
  186. package/util/Rollout.js.flow +39 -0
  187. package/util/TimeReporter.js.flow +79 -0
  188. package/util/areEqualOSS.js.flow +123 -0
  189. package/util/dedupeJSONStringify.js.flow +152 -0
  190. package/util/getDefinitionNodeHash.js.flow +25 -0
  191. package/util/getModuleName.js.flow +39 -0
  192. package/util/joinArgumentDefinitions.js.flow +99 -0
  193. package/util/md5.js.flow +22 -0
  194. package/util/murmurHash.js.flow +94 -0
  195. package/util/nullthrowsOSS.js.flow +25 -0
  196. package/util/orList.js.flow +37 -0
  197. package/util/partitionArray.js.flow +37 -0
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @flow strict
8
+ * @format
9
+ */
10
+
11
+ // flowlint ambiguous-object-type:error
12
+
13
+ 'use strict';
14
+
15
+ /**
16
+ * Marks a string of code as code to be replaced later.
17
+ */
18
+ function moduleDependency(code: string): string {
19
+ return `@@MODULE_START@@${code}@@MODULE_END@@`;
20
+ }
21
+
22
+ /**
23
+ * After JSON.stringify'ing some code that contained parts marked with `mark()`,
24
+ * this post-processes the JSON to convert the marked code strings to raw code.
25
+ *
26
+ * Example:
27
+ * CodeMarker.postProcess(
28
+ * JSON.stringify({code: CodeMarker.mark('alert(1)')})
29
+ * )
30
+ */
31
+ function postProcess(json: string, printModule: string => string): string {
32
+ return json.replace(
33
+ /"@@MODULE_START@@(.*?)@@MODULE_END@@"/g,
34
+ (_, moduleName) => printModule(moduleName),
35
+ );
36
+ }
37
+
38
+ /**
39
+ * Transforms a value such that any transitive CodeMarker strings are replaced
40
+ * with the value of the named module in the given module map.
41
+ */
42
+ function transform(node: mixed, moduleMap: {[string]: mixed, ...}): mixed {
43
+ if (node == null) {
44
+ return node;
45
+ } else if (Array.isArray(node)) {
46
+ return node.map(item => transform(item, moduleMap));
47
+ } else if (typeof node === 'object') {
48
+ const next = {};
49
+ Object.keys(node).forEach(key => {
50
+ next[key] = transform(node[key], moduleMap);
51
+ });
52
+ return next;
53
+ } else if (typeof node === 'string') {
54
+ const match = /^@@MODULE_START@@(.*?)@@MODULE_END@@$/.exec(node);
55
+ if (match != null) {
56
+ const moduleName = match[1];
57
+ if (moduleMap.hasOwnProperty(moduleName)) {
58
+ return moduleMap[moduleName];
59
+ } else {
60
+ throw new Error(
61
+ `Could not find a value for CodeMarker value '${moduleName}', ` +
62
+ 'make sure to supply one in the module mapping.',
63
+ );
64
+ }
65
+ } else if (node.indexOf('@@MODULE_START') >= 0) {
66
+ throw new Error(`Found unprocessed CodeMarker value '${node}'.`);
67
+ }
68
+ return node;
69
+ } else {
70
+ // mixed
71
+ return node;
72
+ }
73
+ }
74
+
75
+ module.exports = {
76
+ moduleDependency,
77
+ postProcess,
78
+ transform,
79
+ };
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @flow strict
8
+ * @format
9
+ */
10
+
11
+ // flowlint ambiguous-object-type:error
12
+
13
+ 'use strict';
14
+
15
+ module.exports = {
16
+ DEFAULT_HANDLE_KEY: '',
17
+ };
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @flow strict
8
+ * @format
9
+ */
10
+
11
+ // flowlint ambiguous-object-type:error
12
+
13
+ 'use strict';
14
+
15
+ const Profiler = require('../core/GraphQLCompilerProfiler');
16
+
17
+ const crypto = require('crypto');
18
+ const fs = require('fs');
19
+ const os = require('os');
20
+ const path = require('path');
21
+
22
+ /**
23
+ * A file backed cache. Values are JSON encoded on disk, so only JSON
24
+ * serializable values should be used.
25
+ */
26
+ class RelayCompilerCache<T> {
27
+ _name: string;
28
+ _cacheBreaker: string;
29
+ _dir: ?string = null;
30
+
31
+ /**
32
+ * @param name Human readable identifier for the cache
33
+ * @param cacheBreaker This should be changed in order to invalidate existing
34
+ * caches.
35
+ */
36
+ constructor(name: string, cacheBreaker: string) {
37
+ this._name = name;
38
+ this._cacheBreaker = cacheBreaker;
39
+ }
40
+
41
+ _getFile(key: string): string {
42
+ if (this._dir == null) {
43
+ // Include username in the cache dir to avoid issues with directories being
44
+ // owned by a different user.
45
+ const username = os.userInfo().username;
46
+ const cacheID = crypto
47
+ .createHash('md5')
48
+ .update(this._cacheBreaker)
49
+ .update(username)
50
+ .digest('hex');
51
+ const dir = path.join(os.tmpdir(), `${this._name}-${cacheID}`);
52
+ if (!fs.existsSync(dir)) {
53
+ try {
54
+ fs.mkdirSync(dir);
55
+ } catch (error) {
56
+ if (error.code !== 'EEXIST') {
57
+ throw error;
58
+ }
59
+ }
60
+ }
61
+ this._dir = dir;
62
+ }
63
+ return path.join(this._dir, key);
64
+ }
65
+
66
+ getOrCompute(key: string, compute: () => T): T {
67
+ return Profiler.run('RelayCompilerCache.getOrCompute', () => {
68
+ const cacheFile = this._getFile(key);
69
+ if (fs.existsSync(cacheFile)) {
70
+ try {
71
+ return JSON.parse(fs.readFileSync(cacheFile, 'utf8'));
72
+ } catch {
73
+ // ignore
74
+ }
75
+ }
76
+ const value = compute();
77
+ try {
78
+ // $FlowFixMe(>=0.95.0) JSON.stringify can return undefined
79
+ fs.writeFileSync(cacheFile, JSON.stringify(value), 'utf8');
80
+ } catch {
81
+ // ignore
82
+ }
83
+ return value;
84
+ });
85
+ }
86
+ }
87
+
88
+ module.exports = RelayCompilerCache;
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @flow strict
8
+ * @format
9
+ */
10
+
11
+ // flowlint ambiguous-object-type:error
12
+
13
+ 'use strict';
14
+
15
+ let whitelistsByProject: ?Map<string, Set<string>> = null;
16
+
17
+ /**
18
+ * This module helps gradually rolling out changes to the code generation by
19
+ * gradually enabling more buckets representing randomly distributed artifacts.
20
+ */
21
+ function set(newWhitelistsByProject: Map<string, Set<string>>) {
22
+ whitelistsByProject = newWhitelistsByProject;
23
+ }
24
+
25
+ function check(project: string, key: string): boolean {
26
+ if (whitelistsByProject == null) {
27
+ return true;
28
+ }
29
+ const whitelist = whitelistsByProject.get(project);
30
+ if (whitelist == null) {
31
+ return true;
32
+ }
33
+ return whitelist.has(key);
34
+ }
35
+
36
+ module.exports = {
37
+ set,
38
+ check,
39
+ };
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @format
8
+ * @flow strict-local
9
+ * @emails oncall+relay
10
+ */
11
+
12
+ // flowlint ambiguous-object-type:error
13
+
14
+ 'use strict';
15
+
16
+ const {isPromise} = require('relay-runtime');
17
+
18
+ import type {Reporter} from '../reporters/Reporter';
19
+
20
+ function reportTime<T>(reporter: Reporter, message: string, fn: () => T): T {
21
+ return reportAndReturnTime(reporter, message, fn)[0];
22
+ }
23
+
24
+ function reportAndReturnTime<T>(
25
+ reporter: Reporter,
26
+ message: string,
27
+ fn: () => T,
28
+ ): [T, number] {
29
+ const startTime = Date.now();
30
+ const result = fn();
31
+ if (isPromise(result)) {
32
+ throw new Error(
33
+ 'reportAndReturnTime: fn(...) returned an unexpected promise.' +
34
+ ' Please use `reportAndReturnAsyncTime` method instead.',
35
+ );
36
+ }
37
+ const elapsedTime = Date.now() - startTime;
38
+ reporter.reportTime(message, elapsedTime);
39
+ return [result, elapsedTime];
40
+ }
41
+
42
+ async function reportAndReturnAsyncTime<T>(
43
+ reporter: Reporter,
44
+ message: string,
45
+ fn: () => ?Promise<T>,
46
+ ): Promise<[T, number]> {
47
+ const startTime = Date.now();
48
+ const promise = fn();
49
+ if (!isPromise(promise)) {
50
+ throw new Error('reportAsyncTime: fn(...) expected to return a promise.');
51
+ }
52
+ const result = await promise;
53
+ const elapsedTime = Date.now() - startTime;
54
+ reporter.reportTime(message, elapsedTime);
55
+ return [result, elapsedTime];
56
+ }
57
+
58
+ async function reportAsyncTime<T>(
59
+ reporter: Reporter,
60
+ message: string,
61
+ fn: () => ?Promise<T>,
62
+ ): Promise<T> {
63
+ const startTime = Date.now();
64
+ const promise = fn();
65
+ if (!isPromise(promise)) {
66
+ throw new Error('reportAsyncTime: fn(...) expected to return a promise.');
67
+ }
68
+ const result = await promise;
69
+ const elapsedTime = Date.now() - startTime;
70
+ reporter.reportTime(message, elapsedTime);
71
+ return result;
72
+ }
73
+
74
+ module.exports = {
75
+ reportTime,
76
+ reportAndReturnTime,
77
+ reportAsyncTime,
78
+ reportAndReturnAsyncTime,
79
+ };
@@ -0,0 +1,123 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @flow
8
+ * @format
9
+ */
10
+
11
+ // flowlint ambiguous-object-type:error
12
+ 'use strict';
13
+
14
+ const aStackPool = [];
15
+ const bStackPool = [];
16
+
17
+ /**
18
+ * Checks if two values are equal. Values may be primitives, arrays, or objects.
19
+ * Returns true if both arguments have the same keys and values.
20
+ *
21
+ * @see http://underscorejs.org
22
+ * @copyright 2009-2013 Jeremy Ashkenas, DocumentCloud Inc.
23
+ * @license MIT
24
+ */
25
+ function areEqual(a: any, b: any): boolean {
26
+ const aStack = aStackPool.length ? aStackPool.pop() : [];
27
+ const bStack = bStackPool.length ? bStackPool.pop() : [];
28
+ const result = eq(a, b, aStack, bStack);
29
+ aStack.length = 0;
30
+ bStack.length = 0;
31
+ aStackPool.push(aStack);
32
+ bStackPool.push(bStack);
33
+ return result;
34
+ }
35
+
36
+ function eq(a: any, b: any, aStack: Array<any>, bStack: Array<any>): boolean {
37
+ if (a === b) {
38
+ // Identical objects are equal. `0 === -0`, but they aren't identical.
39
+ return a !== 0 || 1 / a === 1 / b;
40
+ }
41
+ if (a == null || b == null) {
42
+ // a or b can be `null` or `undefined`
43
+ return false;
44
+ }
45
+ if (typeof a !== 'object' || typeof b !== 'object') {
46
+ return false;
47
+ }
48
+ const objToStr = Object.prototype.toString;
49
+ const className = objToStr.call(a);
50
+ if (className !== objToStr.call(b)) {
51
+ return false;
52
+ }
53
+ switch (className) {
54
+ case '[object String]':
55
+ return a === String(b);
56
+ case '[object Number]':
57
+ return isNaN(a) || isNaN(b) ? false : a === Number(b);
58
+ case '[object Date]':
59
+ case '[object Boolean]':
60
+ return +a === +b;
61
+ case '[object RegExp]':
62
+ return (
63
+ a.source === b.source &&
64
+ a.global === b.global &&
65
+ a.multiline === b.multiline &&
66
+ a.ignoreCase === b.ignoreCase
67
+ );
68
+ }
69
+ // Assume equality for cyclic structures.
70
+ let length = aStack.length;
71
+ while (length--) {
72
+ if (aStack[length] === a) {
73
+ return bStack[length] === b;
74
+ }
75
+ }
76
+ aStack.push(a);
77
+ bStack.push(b);
78
+ let size = 0;
79
+ // Recursively compare objects and arrays.
80
+ if (className === '[object Array]') {
81
+ size = a.length;
82
+ if (size !== b.length) {
83
+ return false;
84
+ }
85
+ // Deep compare the contents, ignoring non-numeric properties.
86
+ while (size--) {
87
+ if (!eq(a[size], b[size], aStack, bStack)) {
88
+ return false;
89
+ }
90
+ }
91
+ } else {
92
+ if (a.constructor !== b.constructor) {
93
+ return false;
94
+ }
95
+ if (a.hasOwnProperty('valueOf') && b.hasOwnProperty('valueOf')) {
96
+ return a.valueOf() === b.valueOf();
97
+ }
98
+ const keys = Object.keys(a);
99
+ if (keys.length !== Object.keys(b).length) {
100
+ return false;
101
+ }
102
+ for (let i = 0; i < keys.length; i++) {
103
+ if (keys[i] === '_owner') {
104
+ // HACK: Comparing deeply nested React trees is slow since you end up
105
+ // comparing the entire tree (all ancestors and all children) and
106
+ // likely not what you want if you're comparing two elements with
107
+ // areEqual. We bail out here for now.
108
+ continue;
109
+ }
110
+ if (
111
+ !b.hasOwnProperty(keys[i]) ||
112
+ !eq(a[keys[i]], b[keys[i]], aStack, bStack)
113
+ ) {
114
+ return false;
115
+ }
116
+ }
117
+ }
118
+ aStack.pop();
119
+ bStack.pop();
120
+ return true;
121
+ }
122
+
123
+ module.exports = areEqual;
@@ -0,0 +1,152 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @flow
8
+ * @format
9
+ */
10
+
11
+ // flowlint ambiguous-object-type:error
12
+
13
+ 'use strict';
14
+
15
+ /**
16
+ * This function works similar to JSON.stringify except that for the case there
17
+ * are multiple common subtrees, it generates a string for a IIFE that re-uses
18
+ * the same objects for the duplicate subtrees.
19
+ */
20
+ function dedupeJSONStringify(jsonValue: mixed): string {
21
+ const metadataForHash = new Map();
22
+ const metadataForVal = new WeakMap();
23
+ const varDefs = [];
24
+ collectMetadata(jsonValue);
25
+ collectDuplicates(jsonValue);
26
+ const code = printJSCode(false, '', jsonValue);
27
+ return varDefs.length === 0
28
+ ? code
29
+ : `(function(){\nvar ${varDefs.join(',\n')};\nreturn ${code};\n})()`;
30
+
31
+ // Collect common metadata for each object in the value tree, ensuring that
32
+ // equivalent values have the *same reference* to the same metadata. Note that
33
+ // the hashes generated are not exactly JSON, but still identify equivalent
34
+ // values. Runs in linear time due to hashing in a bottom-up recursion.
35
+ function collectMetadata(value): string {
36
+ if (value == null || typeof value !== 'object') {
37
+ // $FlowFixMe - JSON.stringify can return undefined
38
+ return JSON.stringify(value);
39
+ }
40
+ let hash;
41
+ if (Array.isArray(value)) {
42
+ hash = '[';
43
+ for (let i = 0; i < value.length; i++) {
44
+ hash += collectMetadata(value[i]) + ',';
45
+ }
46
+ } else {
47
+ hash = '{';
48
+ for (const k in value) {
49
+ if (value.hasOwnProperty(k) && value[k] !== undefined) {
50
+ hash += k + ':' + collectMetadata(value[k]) + ',';
51
+ }
52
+ }
53
+ }
54
+ let metadata = metadataForHash.get(hash);
55
+ if (!metadata) {
56
+ metadata = ({value, hash, count: 0}: {|
57
+ value: mixed,
58
+ hash: string,
59
+ count: number,
60
+ varName?: string,
61
+ |});
62
+ metadataForHash.set(hash, metadata);
63
+ }
64
+ metadataForVal.set(value, metadata);
65
+ return hash;
66
+ }
67
+
68
+ // Using top-down recursion, linearly scan the JSON tree to determine which
69
+ // values should be deduplicated.
70
+ function collectDuplicates(value) {
71
+ if (value == null || typeof value !== 'object') {
72
+ return;
73
+ }
74
+ const metadata = metadataForVal.get(value);
75
+ // Only consider duplicates with hashes longer than 2 (excludes [] and {}).
76
+ if (metadata && metadata.hash.length > 2) {
77
+ metadata.count++;
78
+ if (metadata.count > 1) {
79
+ return;
80
+ }
81
+ }
82
+ if (Array.isArray(value)) {
83
+ for (let i = 0; i < value.length; i++) {
84
+ collectDuplicates(value[i]);
85
+ }
86
+ } else {
87
+ for (const k in value) {
88
+ if (value.hasOwnProperty(k) && value[k] !== undefined) {
89
+ collectDuplicates(value[k]);
90
+ }
91
+ }
92
+ }
93
+ }
94
+
95
+ // Stringify JS, replacing duplicates with variable references.
96
+ function printJSCode(isDupedVar, depth, value): string {
97
+ if (value == null || typeof value !== 'object') {
98
+ // $FlowFixMe: JSON.stringify can return undefined
99
+ return JSON.stringify(value);
100
+ }
101
+ // Only use variable references at depth beyond the top level.
102
+ if (depth !== '') {
103
+ const metadata = metadataForVal.get(value);
104
+ if (metadata && metadata.count > 1) {
105
+ let varName = metadata.varName;
106
+ if (varName == null) {
107
+ const refCode = printJSCode(true, '', value);
108
+ varName = metadata.varName = 'v' + varDefs.length;
109
+ varDefs.push(metadata.varName + ' = ' + refCode);
110
+ }
111
+ return '(' + varName + '/*: any*/)';
112
+ }
113
+ }
114
+ let str;
115
+ let isEmpty = true;
116
+ const depth2 = depth + ' ';
117
+ if (Array.isArray(value)) {
118
+ // Empty arrays can only have one inferred flow type and then conflict if
119
+ // used in different places, this is unsound if we would write to them but
120
+ // this whole module is based on the idea of a read only JSON tree.
121
+ if (isDupedVar && value.length === 0) {
122
+ return '([]/*: any*/)';
123
+ }
124
+ str = '[';
125
+ for (let i = 0; i < value.length; i++) {
126
+ str +=
127
+ (isEmpty ? '\n' : ',\n') +
128
+ depth2 +
129
+ printJSCode(isDupedVar, depth2, value[i]);
130
+ isEmpty = false;
131
+ }
132
+ str += isEmpty ? ']' : `\n${depth}]`;
133
+ } else {
134
+ str = '{';
135
+ for (const k in value) {
136
+ if (value.hasOwnProperty(k) && value[k] !== undefined) {
137
+ str +=
138
+ (isEmpty ? '\n' : ',\n') +
139
+ depth2 +
140
+ JSON.stringify(k) +
141
+ ': ' +
142
+ printJSCode(isDupedVar, depth2, value[k]);
143
+ isEmpty = false;
144
+ }
145
+ }
146
+ str += isEmpty ? '}' : `\n${depth}}`;
147
+ }
148
+ return str;
149
+ }
150
+ }
151
+
152
+ module.exports = dedupeJSONStringify;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @flow strict
8
+ * @format
9
+ */
10
+
11
+ // flowlint ambiguous-object-type:error
12
+
13
+ 'use strict';
14
+
15
+ const md5 = require('./md5');
16
+
17
+ const {print} = require('graphql');
18
+
19
+ import type {ExecutableDefinitionNode} from 'graphql';
20
+
21
+ function getDefinitionNodeHash(node: ExecutableDefinitionNode): string {
22
+ return md5(print(node));
23
+ }
24
+
25
+ module.exports = getDefinitionNodeHash;
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @flow strict
8
+ * @format
9
+ */
10
+
11
+ // flowlint ambiguous-object-type:error
12
+
13
+ 'use strict';
14
+
15
+ const path = require('path');
16
+
17
+ function getModuleName(filePath: string): string {
18
+ // index.js -> index
19
+ // index.js.flow -> index.js
20
+ let filename = path.basename(filePath, path.extname(filePath));
21
+
22
+ // index.js -> index (when extension has multiple segments)
23
+ // index.react -> index (when extension has multiple segments)
24
+ filename = filename.replace(/(\.(?!ios|android)[_a-zA-Z0-9\\-]+)+/g, '');
25
+
26
+ // /path/to/button/index.js -> button
27
+ let moduleName =
28
+ filename === 'index' ? path.basename(path.dirname(filePath)) : filename;
29
+
30
+ // foo-bar -> fooBar
31
+ // Relay compatibility mode splits on _, so we can't use that here.
32
+ moduleName = moduleName.replace(/[^a-zA-Z0-9]+(\w?)/g, (match, next) =>
33
+ next.toUpperCase(),
34
+ );
35
+
36
+ return moduleName;
37
+ }
38
+
39
+ module.exports = getModuleName;