This repository was archived by the owner on Feb 23, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 131
/
Copy pathsortReference.js
147 lines (135 loc) · 4.8 KB
/
sortReference.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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
export const compareOrders = (a, b) => a.order - b.order;
export const compareNestedEntries = (a, b) => compareOrders(a[1], b[1]);
export const compareName = (a, b) => {
if (a.name < b.name) {
return -1;
}
if (a.name > b.name) {
return 1;
}
return 0;
};
const makeBlank = () => ({
order: 0,
sections: [],
nested: {},
});
/**
* buildTree recursively builds up a file tree of the API Reference content,
* which we then use to build a sorted flat list. Our sort order is scoped to
* individual folders, so we need to keep that information.
* @param {array} keys An array of file path segments. Each folder in the tree is
* an item in the array.
* @param {node} doc The node from Gatsby we're adding to the tree.
* @param {object} node A mutable object that we build up to complete this part
* of the tree.
* @returns {object} An object with the format of
* {
* [folderName]: {
* nested: { <recurse> }
* sections: [
* { mdxNode }
* ],
* order: 0
* }
* }
*/
const buildTree = (keys, doc, node) => {
if (!node.nested[keys[0]]) {
/* eslint-disable no-param-reassign */
node.nested[keys[0]] = makeBlank();
node.nested[keys[0]].order = doc.folder.order || 0;
/* eslint-enable no-param-reassign */
}
const currentNode = node.nested[keys[0]];
if (keys.length === 1) {
currentNode.sections.push(doc);
currentNode.sections.sort(compareOrders);
return;
}
buildTree(keys.slice(1), doc, currentNode);
};
const recreateFileTree = (docs) =>
docs.reduce((accum, doc) => {
const keys = doc.directory.split("/");
buildTree(keys, doc, accum);
return accum;
}, makeBlank()).nested;
/**
* insert takes an array which is going to be a list of sections,
* index that will put newItems in this specified index,
* and newItems that are going to be flattened and inserted into an arr at specified index
* @param {array} arr An array of sections that is going to be re-ordered based on its folder's order
* @param {number} index The specified index that newItems will be inserted at
* @param {object} newItems Object of items that is going to be inserted
* @returns {array} A flat list of nodes in reorder.
*/
const insert = (arr, index, newItems) => [
// part of the array before the specified index
...arr.slice(0, index),
// run a flattenAndSort() and to insert its flat nested items
...flattenAndSort(newItems),
// part of the array after the specified index
...arr.slice(index),
];
/**
* sortWithNestedOrder takes the nestedNode's items and
* its sister sections that nestedNode's items need to be a part of
* then take the nested items and reorder the sections in the correct spot
* @param {array} sections The array of the sections that current nestedNode needs to be a part of and re-ordered
* @param {object} nestedNode The nested items node that need to be flatten
* @returns {array} A re-ordered flat list of nodes.
*/
const sortWithNestedOrder = (sections, nestedNode) => {
const nestedItems = Object.entries(nestedNode);
nestedItems.forEach((nestedSectionEntry) => {
const nestedItemOrder = nestedSectionEntry[1].order.toString()[0];
const obj = {};
obj[nestedSectionEntry[0]] = nestedSectionEntry[1];
/* eslint-disable no-param-reassign */
sections = insert(sections, nestedItemOrder, obj);
});
return sections;
};
/**
* flattenAndSort takes the file tree we create with `recreateFileTree` and
* squashes it back down to a flat list, with all the items in the correct spot
* as dictated by their `order` and their folder.
* @param {object} node The tree node to flatten.
* @returns {array} A flat list of nodes.
*/
export const flattenAndSort = (node) =>
Object.entries(node)
.sort(compareNestedEntries)
.flatMap((entry) => {
const nestedNode = entry[1];
const hasNestedItems =
Object.values(nestedNode.nested) && Object.values(nestedNode.nested)[0];
const isDoubleNested =
hasNestedItems &&
hasNestedItems.sections[0].directory.split("/").length > 2;
let reorderedItems;
if (isDoubleNested) {
reorderedItems = sortWithNestedOrder(
nestedNode.sections,
nestedNode.nested,
);
return reorderedItems;
}
return [
...nestedNode.sections,
...flattenAndSort(nestedNode.nested),
].map((innerNode) =>
innerNode.sections ? innerNode.sections : innerNode,
);
});
/**
* sortReference takes a list of normalized mdx nodes, and returns that same list
* sorted in order per their `order` metadata and the folder they're contained in.
* @param {array} docs The list of normalized mdx nodes from Gatsby.
* @returns {array} Those same list items in order.
*/
export const sortReference = (docs) => {
const tree = recreateFileTree(docs);
return flattenAndSort(tree);
};