1 | const
|
2 | path = require('path'),
|
3 | FakeDataLoader = require('./dataLoader/FakeDataLoader'),
|
4 | sgUtil = require('./util');
|
5 |
|
6 | class CollectorStore {
|
7 | constructor({conf}) {
|
8 | this.globOptions = conf.get('globOptions');
|
9 | this.htmlExt = conf.get('htmlExt');
|
10 | this.dataExt = conf.get('dataExt');
|
11 | this.c = conf.get('logLevel', 0);
|
12 | this.sectionOrder = conf.get('sections').map(({title}) => title);
|
13 |
|
14 | this.sections = new Map();
|
15 | this.files = new Map();
|
16 |
|
17 | this.setSection = this.setSection.bind(this);
|
18 | this.setFile = this.setFile.bind(this);
|
19 | this.unsetFile = this.unsetFile.bind(this);
|
20 | this.updateTimestamp = this.updateTimestamp.bind(this);
|
21 | this.setGroupedFile = this.setGroupedFile.bind(this);
|
22 | this.unsetGroupedFile = this.unsetGroupedFile.bind(this);
|
23 | this.getSection = this.getSection.bind(this);
|
24 | this.getFiles = this.getFiles.bind(this);
|
25 | this.getSections = this.getSections.bind(this);
|
26 | this.getSectionFilesData = this.getSectionFilesData.bind(this);
|
27 | this.getUrls = this.getUrls.bind(this);
|
28 | this.getCollectedData = this.getCollectedData.bind(this);
|
29 | }
|
30 |
|
31 | static getGroupPaths(filename, url = false) {
|
32 | const {dir, name} = path.parse(filename);
|
33 | const parentName = path.basename(dir);
|
34 | const base = `${dir}/${parentName}`;
|
35 | const groupUrl = url ? `${url.dirname}/${parentName}${url.extname}` : null;
|
36 |
|
37 | return {
|
38 | base,
|
39 | groupUrl,
|
40 | name,
|
41 | parentName
|
42 | };
|
43 | }
|
44 |
|
45 | static getPageTitle(filename, title, name, parentName) {
|
46 | return (name === 'index' || name === parentName) ? title : sgUtil.getTitleFromFoldername(filename);
|
47 | }
|
48 |
|
49 | getCollectedData() {
|
50 | return [...this.getSections().values()]
|
51 | .map(section => {
|
52 |
|
53 | const needsUpdate = section.getFiles()
|
54 | .filter(({exclude}) => !exclude)
|
55 | .some(({timestamp, _data = {}}) => !section._timestamp || !timestamp || !_data.timestamp || timestamp > section._timestamp || _data.timestamp > section._timestamp);
|
56 |
|
57 | if (needsUpdate) {
|
58 | section._files = this.getSectionFilesData(section);
|
59 | section._timestamp = Date.now();
|
60 | sgUtil.log(`Section: \u001b[1m${section.title} (${section._files.length})\u001b[22m collected.`, 'info');
|
61 | }
|
62 |
|
63 | return {
|
64 | files: section._files,
|
65 | collector: section.collector,
|
66 | route: section.route,
|
67 | title: section.title,
|
68 | url: section.url
|
69 | };
|
70 | }).sort((a, b) => {
|
71 | return this.sectionOrder.indexOf(a.title) - this.sectionOrder.indexOf(b.title);
|
72 | });
|
73 | }
|
74 |
|
75 | getFile(filename) {
|
76 | return this.files.get(sgUtil.removeFileExtension(filename));
|
77 | }
|
78 |
|
79 | getFiles() {
|
80 | return this.files;
|
81 | }
|
82 |
|
83 | getFilesOfSection() {
|
84 | const {files, destDir} = this;
|
85 | return [...files.values()].filter(file => destDir === file.destDir);
|
86 | }
|
87 |
|
88 | getSection(destDir) {
|
89 | const {sections} = this;
|
90 |
|
91 | return sections.get(destDir);
|
92 | }
|
93 |
|
94 | getSectionFilesData({getFiles}) {
|
95 | const {htmlExt, dataExt} = this;
|
96 | const files = getFiles();
|
97 |
|
98 | return getFiles()
|
99 | .filter(({exclude}) => !exclude)
|
100 | .map(({filename, title, componentName, collector, orderValue, url, sectionPath, exclude}) => {
|
101 |
|
102 | if (this.logLevel > 2) {
|
103 | sgUtil.log(`Get Section Files Data: \u001b[1m${componentName}\u001b[22m added.`);
|
104 | }
|
105 |
|
106 | const asyncContentUrls = {
|
107 | source: sgUtil.replaceFileExtension(url, `source.${htmlExt}`),
|
108 | locals: sgUtil.replaceFileExtension(url, dataExt),
|
109 | schema: sgUtil.replaceFileExtension(url, `schema.${dataExt}`)
|
110 | };
|
111 |
|
112 | files
|
113 | .filter((file) => file.componentName.indexOf(`${componentName}\.`) !== -1)
|
114 | .map(({componentName, url}) => {
|
115 | const [, type] = componentName.split('.');
|
116 | asyncContentUrls[type] = sgUtil.replaceFileExtension(url, `source.${htmlExt}`);
|
117 | });
|
118 |
|
119 | return {
|
120 | title,
|
121 | filename,
|
122 | componentName,
|
123 | collector,
|
124 | url,
|
125 | exclude,
|
126 | orderValue,
|
127 | path: sectionPath,
|
128 | asyncContentUrls,
|
129 | dirname: path.dirname(filename)
|
130 | };
|
131 | });
|
132 | }
|
133 |
|
134 | getSections() {
|
135 | return this.sections;
|
136 | }
|
137 |
|
138 | getUrls() {
|
139 | const urls = new Map();
|
140 |
|
141 | this.files.forEach(file => urls.set(sgUtil.removeFileExtension(file.url), file));
|
142 | return urls;
|
143 | }
|
144 |
|
145 | setFile(file) {
|
146 | this.files.set(sgUtil.removeFileExtension(file.filename), file);
|
147 | file.copySource();
|
148 | return file;
|
149 | }
|
150 |
|
151 | setGroupedFile(file) {
|
152 | const
|
153 | {urls, files, constructor} = this,
|
154 | {getGroupPaths, getPageTitle} = constructor,
|
155 | {filename, url, collector, title, destDir, orderValue} = file,
|
156 | {base, groupUrl, name, parentName} = getGroupPaths(filename, url),
|
157 | pageTitle = file.pageTitle = getPageTitle(filename, title, name, parentName);
|
158 |
|
159 | if (name === 'index' || name === parentName || !urls.get(base)) {
|
160 | urls.set(base, {
|
161 | url: groupUrl,
|
162 | title: pageTitle,
|
163 | collector,
|
164 | destDir,
|
165 | orderValue
|
166 | });
|
167 | }
|
168 |
|
169 | if (files.get(groupUrl) === undefined) {
|
170 | files.set(groupUrl, new Map());
|
171 | }
|
172 | files.get(groupUrl).set(name, file);
|
173 |
|
174 | return files.get(groupUrl);
|
175 | }
|
176 |
|
177 | setSection(section) {
|
178 | const {sections, files, constructor, getFilesOfSection} = this;
|
179 | const {destDir} = section;
|
180 |
|
181 | section.getFiles = getFilesOfSection.bind({
|
182 | destDir,
|
183 | files,
|
184 | constructor
|
185 | });
|
186 |
|
187 | sections.set(destDir, section);
|
188 | }
|
189 |
|
190 | unsetFile(filename) {
|
191 | this.updateTimestamp(filename);
|
192 | this.files.delete(sgUtil.removeFileExtension(filename));
|
193 | }
|
194 |
|
195 | unsetGroupedFile(filename) {
|
196 | const
|
197 | {constructor, urls, files} = this,
|
198 | {base, name} = constructor.getGroupPaths(filename);
|
199 |
|
200 | files.get(filename).delete(name);
|
201 |
|
202 | const {size = 0} = files.get(filename);
|
203 |
|
204 | if (size === 0) {
|
205 | urls.delete(base);
|
206 | files.delete(filename);
|
207 | }
|
208 | }
|
209 |
|
210 | updateFile(filename) {
|
211 | const {copySource} = this.getFile(filename) || {};
|
212 | if (copySource) {
|
213 | copySource();
|
214 | }
|
215 | }
|
216 |
|
217 | updateTimestamp(filename, newTimestamp = Date.now()) {
|
218 | const file = this.getFile(filename) || this.getFile(`${path.dirname(filename)}/_${path.basename(filename)}`);
|
219 | const {componentName, timestamp, parentComponents} = file || {};
|
220 |
|
221 | if (!componentName) {
|
222 | if (this.logLevel > 2) {
|
223 | sgUtil.log(`Update Timestamp: no file object for filename ${filename}`, 'warn');
|
224 | }
|
225 | return false;
|
226 | }
|
227 |
|
228 | if (timestamp === newTimestamp) {
|
229 | if (this.logLevel > 3) {
|
230 | sgUtil.log(`Update Timestamp: ${componentName} was already updated`, 'notice');
|
231 | }
|
232 |
|
233 | return false;
|
234 | }
|
235 |
|
236 | file.timestamp = newTimestamp;
|
237 |
|
238 | if (this.logLevel > 3) {
|
239 | sgUtil.log(`Update Timestamp: ${componentName} updated`, 'info');
|
240 | }
|
241 |
|
242 | if (FakeDataLoader.getCache()[componentName]) {
|
243 | delete FakeDataLoader.getCache()[componentName];
|
244 | }
|
245 |
|
246 | if (file._data) {
|
247 | file._data.timestamp = 0;
|
248 | }
|
249 |
|
250 | return parentComponents.reduce((carry, {filename}) => {
|
251 | return carry.concat(this.updateTimestamp(filename, newTimestamp) || []);
|
252 | }, [componentName]);
|
253 | }
|
254 | }
|
255 |
|
256 | module.exports = CollectorStore;
|