-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathindex.js
94 lines (79 loc) · 2.25 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
/* eslint no-bitwise: 0 */
const { parse } = require('graphql/language/parser');
function nonSecureHash(s) {
let hash = 0;
for (let i = 0; i < s.length; i++) {
let char = s.charCodeAt(i);
const mixed = (hash << 5) - hash;
hash = mixed + char;
hash = hash & hash; // Convert to 32bit integer
}
return hash;
}
class NotFragment {
constructor(value) {
this.name = String(value);
}
collectFragments(acc) {
return acc;
}
}
class Fragment {
constructor(segments, childFragments) {
this.segments = segments;
this.childFragments = childFragments.map(f => {
if (!(f instanceof Fragment)) {
return new NotFragment(f);
}
return f;
});
const hash = nonSecureHash([...segments, ...this.childNames()].join(''));
this.name = `fragment_${Math.abs(hash).toString(36)}`;
}
format() {
return `fragment ${this.name} ${interleaveStrings(
this.segments,
this.childNames()
).replace('...', '')}`;
}
childNames() {
return this.childFragments.map(f => f.name);
}
collectFragments(acc) {
const children = this.childFragments.reduce(
(acc, f) => f.collectFragments(acc),
acc
);
return [this, ...children];
}
}
function createFragment(segments, ...childFragments) {
return new Fragment(segments, childFragments);
}
function interleaveStrings(array1, array2) {
return array1.map((string, i) => string + (array2[i] || '')).join('');
}
function uniqueFragments(collectedFragments) {
const uniqueFragmentMap = {};
for (const fragment of collectedFragments) {
uniqueFragmentMap[fragment.name] = fragment;
}
return Object.keys(uniqueFragmentMap)
.sort()
.map(name => uniqueFragmentMap[name]);
}
function createQuery(segments, ...childFragments) {
const root = new Fragment([], childFragments);
const collectedFragments = root.collectFragments([]);
collectedFragments.shift(); // Skip root
const fragmentsString = uniqueFragments(collectedFragments)
.map(fragment => fragment.format())
.join('\n');
const clonedSegments = segments.slice();
clonedSegments[clonedSegments.length - 1] += fragmentsString;
return parse(interleaveStrings(clonedSegments, root.childNames()));
}
module.exports = {
createQuery,
createFragment
};