UNPKG

7.11 kBJavaScriptView Raw
1const
2 fs = require('fs'),
3 path = require('path'),
4 glob = require('glob'),
5 sgUtil = require('../util');
6
7class Collector {
8 constructor({conf, CollectorStore, CollectorPaths, TemplateEngine, DataLoader}) {
9 this.conf = conf;
10 this.CollectorStore = CollectorStore;
11 this.CollectorPaths = CollectorPaths;
12 this.TemplateEngine = TemplateEngine;
13 this.DataLoader = DataLoader;
14
15 this.copyExtend = conf.copyExtend;
16 this.baseDir = conf.get('baseDir');
17 this.viewerRootPath = conf.get('app.viewerRootPath');
18 this.templateExt = conf.get('templateExt');
19 this.htmlExt = conf.get('htmlExt');
20 this.globOptions = conf.get('globOptions');
21 this.logLevel = conf.get('logLevel', 0);
22 this.warnOnMissingDataFile = this.logLevel > 2;
23 this.globPattern = path.join('**', '**', `*.${this.templateExt}`);
24 this.logLevel = conf.get('logLevel', 0);
25 }
26
27 touchFileSystem(sourceDir) {
28 const {globPattern, globOptions} = this;
29 return glob.sync(path.join(sourceDir, globPattern), globOptions);
30 }
31
32 collectMatchingSections(sections, collector) {
33 sections
34 .filter((sectionConfig) => sectionConfig.collector === collector)
35 .map((sectionConfig) => this.collectSection.call(this, sectionConfig));
36 }
37
38 collectSection(sectionConfig) {
39 const {
40 baseDir, viewerRootPath, htmlExt, globPattern, warnOnMissingDataFile, CollectorStore,
41 setFile, unsetFile, updateFile, touchFileSystem, initDataLoader
42 } = this;
43 const {title, source, dest, collector} = sectionConfig;
44 const sourceDir = path.resolve(path.join(baseDir, source));
45 const destDir = dest || source;
46 const dataLoader = initDataLoader.call(this, sectionConfig);
47 const section = {
48 collector,
49 title,
50 destDir,
51 sourceDir,
52 dataLoader,
53 globPattern,
54 warnOnMissingDataFile,
55 watchPattern: path.join(baseDir, source, '**', '*'),
56 url: `/${viewerRootPath}/${destDir}`,
57 route: `/${viewerRootPath}/${destDir}/*.${htmlExt}`,
58 setFile: setFile.bind(this),
59 unsetFile: unsetFile.bind(this),
60 updateFile: updateFile.bind(this)
61 };
62
63 touchFileSystem
64 .call(this, sourceDir)
65 .map((filename) => {
66 setFile.call(this, {filename, section})
67 });
68
69 CollectorStore.setSection(section);
70
71 return section;
72 }
73
74 unsetFile(filename) {
75 this.CollectorStore.unsetFile(filename);
76 }
77
78 setFile(fileOptions) {
79 return this.CollectorStore.setFile(this.createFileObj(fileOptions));
80 }
81
82 updateFile(filename) {
83 this.CollectorStore.updateFile(filename);
84 }
85
86 createFileObj({filename, section: {sourceDir, destDir, url: sectionUrl, dataLoader, collector, warnOnMissingDataFile}}) {
87 const {
88 constructor: {name: instance}, logLevel,
89 getSaveHtmlFunction, getSaveLocalsFunction, getComponentName,
90 getCssFiles, getRenderHookFunction, getCopySourceFunction,
91 isExcluded, CollectorPaths, TemplateEngine
92 } = this;
93
94 CollectorPaths.set(filename, sourceDir, destDir);
95
96 const url = CollectorPaths.resolveUrl(filename);
97 const sectionPath = path.relative(sectionUrl, path.dirname(url));
98 const componentName = getComponentName.call(this, sourceDir, filename);
99
100 return {
101 filename,
102 collector,
103 destDir,
104 componentName,
105 instance,
106 sectionPath,
107 url,
108 warnOnMissingDataFile,
109 timestamp: Date.now(),
110 childComponents: [],
111 parentComponents: [],
112 exclude: isExcluded(filename, componentName),
113 extension: sgUtil.getFileExtension(filename),
114 cssFiles: getCssFiles.call(this),
115 saveHtml: getSaveHtmlFunction.call(this, filename),
116 saveLocals: getSaveLocalsFunction.call(this, filename),
117 renderHook: getRenderHookFunction.call(this),
118 copySource: getCopySourceFunction.call(this, filename, componentName),
119 get template() {
120 if (!this._template || this._template.timestamp !== this.timestamp) {
121
122 if (!fs.existsSync(this.filename)) {
123 return '';
124 }
125
126 this._template = {
127 content: sgUtil.readFileContents(this.filename),
128 timestamp: this.timestamp
129 };
130 }
131 return this._template.content;
132 },
133 get orderValue() {
134 return this.data.orderValue || sectionPath;
135 },
136 get data() {
137 if (!this._data || this._data.timestamp !== this.timestamp) {
138 this._data = dataLoader ? dataLoader.getData(this) : {};
139 this._data.title = this.title;
140 this._data.pageTitle = this.pageTitle || this._data.title;
141 this._data.instance = this.instance;
142 this._data.collector = this.collector;
143 this._data.timestamp = this.timestamp;
144
145 if (logLevel > 1) {
146 sgUtil.log(`Data: \u001b[1m${this.componentName}\u001b[22m generated. (${this.timestamp})`, 'info');
147 }
148 }
149 else if (logLevel > 1) {
150 sgUtil.log(`Data: \u001b[1m${this.componentName}\u001b[22m use cached. (${this.timestamp})`);
151 }
152 return this._data;
153 },
154 get render() {
155 return TemplateEngine.render(this);
156 },
157 get title() {
158 if (!this._title || !this._data || this._data.timestamp !== this.timestamp) {
159 const {title = sgUtil.getTitleFromFilename(this.filename)} =
160 sgUtil.readRelatedData(this.filename, this.warnOnMissingDataFile);
161 this._title = title;
162 }
163 return this._title;
164 }
165 };
166 }
167
168 readRelatedData(filename) {
169 return filename ? sgUtil.readJson5File(filename) : {};
170 }
171
172 initDataLoader(sectionConfig) {
173 return new this.DataLoader(this.copyExtend(sectionConfig), this.warnOnMissingDataFile);
174 }
175
176 getSaveHtmlFunction(filename) {
177 filename = this.CollectorPaths.resolveDestHtml(filename);
178 return ({html}) => sgUtil.writeFile(filename, html);
179 }
180
181 getSaveLocalsFunction(filename) {
182 filename = this.CollectorPaths.resolveDestData(filename);
183 return ({locals}) => sgUtil.writeJsonFile(filename, locals);
184 }
185
186 getRenderHookFunction() {
187 return ({data: {locals = {}}}, source) => ({source, locals});
188 }
189
190 getCopySourceFunction(_filename, _componentName) {
191 return (filename = _filename, componentName = _componentName) => {
192 const dest = this.CollectorPaths.resolveTemplateSourceDest(componentName);
193 sgUtil.copyFile(filename, dest, () => {});
194 };
195 }
196
197 getCssFiles() {
198 return [`/${this.viewerRootPath}/css/app.css`];
199 }
200
201 getGetSectionDataFunction() {
202 const {title, instance, cssFiles, sectionFiles} = this;
203 return {title, instance, app: {cssFiles}, locals: {files: sectionFiles}};
204 }
205
206 getComponentName(sourceDir, filename) {
207 const componentType = path.basename(sourceDir);
208 const componentName = path.basename(sgUtil.removeFileExtension(filename)).replace(/_/g, '');
209
210 return `${componentType}-${componentName}`;
211 }
212
213 isExcluded(filename, componentName) {
214 return path.basename(filename).substr(0, 1) === '_' || sgUtil.getFileExtension(componentName) !== '';
215 }
216}
217
218module.exports = Collector;