UNPKG

7.59 kBJavaScriptView Raw
1"use strict";
2
3const {
4 store
5} = require(`./index`);
6/**
7 * Get all nodes from redux store.
8 *
9 * @returns {Array}
10 */
11
12
13const getNodes = () => {
14 const nodes = store.getState().nodes;
15
16 if (nodes) {
17 return Array.from(nodes.values());
18 } else {
19 return [];
20 }
21};
22
23exports.getNodes = getNodes;
24/** Get node by id from store.
25 *
26 * @param {string} id
27 * @returns {Object}
28 */
29
30const getNode = id => store.getState().nodes.get(id);
31
32exports.getNode = getNode;
33/**
34 * Get all nodes of type from redux store.
35 *
36 * @param {string} type
37 * @returns {Array}
38 */
39
40const getNodesByType = type => {
41 const nodes = store.getState().nodesByType.get(type);
42
43 if (nodes) {
44 return Array.from(nodes.values());
45 } else {
46 return [];
47 }
48};
49
50exports.getNodesByType = getNodesByType;
51/**
52 * Get all type names from redux store.
53 *
54 * @returns {Array}
55 */
56
57const getTypes = () => Array.from(store.getState().nodesByType.keys());
58
59exports.getTypes = getTypes;
60/**
61 * Determine if node has changed.
62 *
63 * @param {string} id
64 * @param {string} digest
65 * @returns {boolean}
66 */
67
68exports.hasNodeChanged = (id, digest) => {
69 const node = store.getState().nodes.get(id);
70
71 if (!node) {
72 return true;
73 } else {
74 return node.internal.contentDigest !== digest;
75 }
76};
77/**
78 * Get node and save path dependency.
79 *
80 * @param {string} id
81 * @param {string} path
82 * @returns {Object} node
83 */
84
85
86exports.getNodeAndSavePathDependency = (id, path) => {
87 const createPageDependency = require(`./actions/add-page-dependency`);
88
89 const node = getNode(id);
90 createPageDependency({
91 path,
92 nodeId: id
93 });
94 return node;
95};
96
97exports.saveResolvedNodes = async (nodeTypeNames, resolver) => {
98 for (const typeName of nodeTypeNames) {
99 const nodes = store.getState().nodesByType.get(typeName);
100 const resolvedNodes = new Map();
101
102 if (nodes) {
103 for (const node of nodes.values()) {
104 const resolved = await resolver(node);
105 resolvedNodes.set(node.id, resolved);
106 }
107
108 store.dispatch({
109 type: `SET_RESOLVED_NODES`,
110 payload: {
111 key: typeName,
112 nodes: resolvedNodes
113 }
114 });
115 }
116 }
117};
118/**
119 * Get node and save path dependency.
120 *
121 * @param {string} typeName
122 * @param {string} id
123 * @returns {Object|void} node
124 */
125
126
127const getResolvedNode = (typeName, id) => {
128 const {
129 nodesByType,
130 resolvedNodesCache
131 } = store.getState();
132 const nodes
133 /*: Map<mixed> */
134 = nodesByType.get(typeName);
135
136 if (!nodes) {
137 return null;
138 }
139
140 let node = nodes.get(id);
141
142 if (!node) {
143 return null;
144 }
145
146 const resolvedNodes = resolvedNodesCache.get(typeName);
147
148 if (resolvedNodes) {
149 node.__gatsby_resolved = resolvedNodes.get(id);
150 }
151
152 return node;
153};
154
155exports.getResolvedNode = getResolvedNode;
156
157const addResolvedNodes = (typeName, arr) => {
158 const {
159 nodesByType,
160 resolvedNodesCache
161 } = store.getState();
162 const nodes
163 /*: Map<mixed> */
164 = nodesByType.get(typeName);
165
166 if (!nodes) {
167 return;
168 }
169
170 const resolvedNodes = resolvedNodesCache.get(typeName);
171 nodes.forEach(node => {
172 if (resolvedNodes) {
173 node.__gatsby_resolved = resolvedNodes.get(node.id);
174 }
175
176 arr.push(node);
177 });
178};
179
180exports.addResolvedNodes = addResolvedNodes;
181/**
182 * Given a ("flat") filter path leading up to "eq", a set of node types, and a
183 * cache, create a cache that for each resulting value of the filter contains
184 * all the Nodes in a Set (or, if the property is `id`, just the Nodes).
185 * This cache is used for applying the filter and is a massive improvement over
186 * looping over all the nodes, when the number of pages (/nodes) scale up.
187 *
188 * @param {Array<string>} chain
189 * @param {Array<string>} nodeTypeNames
190 * @param {undefined | Map<string, Map<string | number | boolean, Node>>} typedKeyValueIndexes
191 * This object lives in query/query-runner.js and is passed down runQuery
192 * @returns {undefined}
193 */
194
195const ensureIndexByTypedChain = (chain, nodeTypeNames, typedKeyValueIndexes) => {
196 const chained = chain.join(`+`);
197 const nodeTypeNamePrefix = nodeTypeNames.join(`,`) + `/`; // The format of the typedKey is `type,type/path+to+eqobj`
198
199 const typedKey = nodeTypeNamePrefix + chained;
200 let byKeyValue = typedKeyValueIndexes.get(typedKey);
201
202 if (byKeyValue) {
203 return;
204 }
205
206 const {
207 nodes,
208 resolvedNodesCache
209 } = store.getState();
210 byKeyValue = new Map(); // Map<node.value, Set<all nodes with this value for this key>>
211
212 typedKeyValueIndexes.set(typedKey, byKeyValue);
213 nodes.forEach(node => {
214 if (!nodeTypeNames.includes(node.internal.type)) {
215 return;
216 } // There can be a filter that targets `__gatsby_resolved` so fix that first
217
218
219 if (!node.__gatsby_resolved) {
220 const typeName = node.internal.type;
221 const resolvedNodes = resolvedNodesCache.get(typeName);
222 node.__gatsby_resolved = resolvedNodes === null || resolvedNodes === void 0 ? void 0 : resolvedNodes.get(node.id);
223 }
224
225 let v = node;
226 let i = 0;
227
228 while (i < chain.length && v) {
229 const nextProp = chain[i++];
230 v = v[nextProp];
231 }
232
233 if (typeof v !== `string` && typeof v !== `number` && typeof v !== `boolean` || i !== chain.length) {
234 // Not sure whether this is supposed to happen, but this means that either
235 // - The node chain ended with `undefined`, or
236 // - The node chain ended in something other than a primitive, or
237 // - A part in the chain in the object was not an object
238 return;
239 } // Special case `id` as that bucket never receives more than one element
240
241
242 if (chained === `id`) {
243 // Note: this is not a duplicate from `nodes` because this set only
244 // contains nodes of this type. Page nodes are a subset of all nodes
245 byKeyValue.set(v, node);
246 return;
247 }
248
249 let set = byKeyValue.get(v);
250
251 if (!set) {
252 set = new Set();
253 byKeyValue.set(v, set);
254 }
255
256 set.add(node);
257 });
258};
259
260exports.ensureIndexByTypedChain = ensureIndexByTypedChain;
261/**
262 * Given a ("flat") filter path leading up to "eq", a target value to filter
263 * for, a set of node types, and a pre-generated lookup cache, return the set
264 * of Nodes (or, if the property is `id` just the Node) which pass the filter.
265 * This returns `undefined` if there is Node that passes the filter.
266 *
267 * Basically if the filter was {a: {b: {slug: {eq: "foo/bar"}}}} then it will
268 * return all the nodes that have `node.slug === "foo/bar"`. That usually (but
269 * not always) at most one node for slug, but this filter can apply to anything.
270 *
271 * The only exception is `id`, since internally there can be at most one node
272 * per `id` so there's a minor optimization for that (no need for Sets).
273 *
274 * @param {Array<string>} chain Note: `eq` is assumed to be the leaf prop here
275 * @param {boolean | number | string} value This is the value being filtered for
276 * @param {Array<string>} nodeTypeNames
277 * @param {undefined | Map<string, Map<string | number | boolean, Node>>} typedKeyValueIndexes
278 * This object lives in query/query-runner.js and is passed down runQuery
279 * @returns {Array<Node> | undefined}
280 */
281
282const getNodesByTypedChain = (chain, value, nodeTypeNames, typedKeyValueIndexes) => {
283 const key = chain.join(`+`);
284 const typedKey = nodeTypeNames.join(`,`) + `/` + key;
285 let byTypedKey = typedKeyValueIndexes === null || typedKeyValueIndexes === void 0 ? void 0 : typedKeyValueIndexes.get(typedKey);
286 return byTypedKey === null || byTypedKey === void 0 ? void 0 : byTypedKey.get(value);
287};
288
289exports.getNodesByTypedChain = getNodesByTypedChain;
290//# sourceMappingURL=nodes.js.map
\No newline at end of file