1 | const
|
2 | fs = require('fs'),
|
3 | path = require('path'),
|
4 | colors = require('ansi-colors'),
|
5 | fancyLog = require('fancy-log'),
|
6 | marked = require('marked'),
|
7 | ConfigManager = require('./ConfigManager'),
|
8 |
|
9 | capitalizeString = (str) => {
|
10 | return str.toLowerCase()
|
11 | .replace(/\b\w/g, (matches) => matches.toUpperCase());
|
12 | },
|
13 |
|
14 | getTitleFromName = (str) => {
|
15 | const [basename] = str.split('.');
|
16 | return capitalizeString(basename)
|
17 | .replace(/\d{2,}-|-|_/g, ' ')
|
18 | .trim();
|
19 | },
|
20 |
|
21 | getTitleFromFilename = (filePath) => {
|
22 | return getTitleFromName(path.basename(filePath, path.extname(filePath)));
|
23 | },
|
24 |
|
25 | getTitleFromFoldername = (filePath) => {
|
26 | return getTitleFromName(path.basename(path.dirname(filePath)));
|
27 | },
|
28 |
|
29 | getFileExtension = (filePath) => {
|
30 | return path.extname(filePath)
|
31 | .substr(1);
|
32 | },
|
33 |
|
34 | removeFileExtension = (filePath, onlyLastExt = true) => {
|
35 | const i = onlyLastExt ? filePath.lastIndexOf('.') : filePath.indexOf('.');
|
36 | return (i < 0) ? filePath : filePath.substr(0, i);
|
37 | },
|
38 |
|
39 | replaceFileExtension = (filePath, extension, allExt = false) => {
|
40 | const basePath = removeFileExtension(filePath, !allExt);
|
41 | return basePath === filePath ? filePath : `${basePath}.${extension}`;
|
42 | },
|
43 |
|
44 | getRelatedDataPath = (_filePath, warn) => {
|
45 | let
|
46 | dataExt = ConfigManager.get('dataExt'),
|
47 | defaultDataFileName = ConfigManager.get('defaultDataFileName'),
|
48 | filePath = replaceFileExtension(_filePath, dataExt, true);
|
49 |
|
50 | if (!path.isAbsolute(filePath)) {
|
51 | filePath = path.join(ConfigManager.get('rootPath'), filePath);
|
52 | }
|
53 |
|
54 | if (fs.existsSync(filePath)) {
|
55 | return filePath;
|
56 | }
|
57 |
|
58 | filePath = path.join(path.dirname(removeFileExtension(filePath, false)), `${defaultDataFileName}.${dataExt}`);
|
59 |
|
60 | if (fs.existsSync(filePath)) {
|
61 | return filePath;
|
62 | }
|
63 |
|
64 | if (typeof warn === 'undefined' || warn) {
|
65 | log(`Notice: unable to load resolved data file '${path.relative(path.resolve('./'), filePath)}' `, 'notice');
|
66 | log(`(origin '${path.relative(path.resolve('./'), _filePath)}')`, 'notice');
|
67 | }
|
68 |
|
69 | return false;
|
70 | },
|
71 |
|
72 | readRelatedData = (_filePath, warn) => {
|
73 | let filePath = getRelatedDataPath(_filePath, warn);
|
74 | return filePath ? readJson5File(filePath) : {};
|
75 | },
|
76 |
|
77 | readRelatedMarkdown = (_filePath, isRequired = false) => {
|
78 |
|
79 | filePath = replaceFileExtension(_filePath, ConfigManager.get('markdownExt'));
|
80 |
|
81 | if (!path.isAbsolute(filePath)) {
|
82 | filePath = path.join(ConfigManager.get('rootPath'), filePath);
|
83 | }
|
84 |
|
85 | if (!fs.existsSync(filePath)) {
|
86 | if (isRequired) {
|
87 | log(`sgUtil.readRelatedMarkdown: resolved '${_filePath}' to '${filePath}' but unable to load`, 'notice');
|
88 | }
|
89 | return '';
|
90 | }
|
91 |
|
92 | return readMarkdownFile(filePath);
|
93 | },
|
94 |
|
95 | readFileContents = (absPath, encoding = 'utf8') => {
|
96 |
|
97 | if (!fs.existsSync(absPath)) {
|
98 | log(`sgUtil.readFileContents: ${absPath} not found`, 'warn');
|
99 | log(new Error().stack, 'warn');
|
100 | return '';
|
101 | }
|
102 |
|
103 | if (!fs.lstatSync(absPath)
|
104 | .isFile()) {
|
105 | log(`sgUtil.readFileContents: ${absPath} is no file`, 'warn');
|
106 | return '';
|
107 | }
|
108 |
|
109 | return fs.readFileSync(absPath, encoding);
|
110 | },
|
111 |
|
112 | flatten = (data) => {
|
113 | if (typeof data !== 'object') return data;
|
114 | return Array.from(data.values())
|
115 | .map((item) => flatten(item))
|
116 | .join('\n');
|
117 | },
|
118 |
|
119 | isObject = (val) => {
|
120 | return val &&
|
121 | (typeof val === 'object') &&
|
122 | !Array.isArray(val) &&
|
123 | !(val instanceof RegExp) &&
|
124 | !(val instanceof Date);
|
125 | },
|
126 |
|
127 | createPath = (filePath) => {
|
128 | const targetPath = path.dirname(filePath);
|
129 |
|
130 | targetPath.split(path.sep)
|
131 | .reduce((parentDir, childDir) => {
|
132 | const curDir = path.resolve(parentDir, childDir);
|
133 | if (!fs.existsSync(curDir)) {
|
134 | fs.mkdirSync(curDir);
|
135 | }
|
136 | return curDir;
|
137 | }, path.isAbsolute(targetPath) ? path.sep : '');
|
138 | },
|
139 |
|
140 | copyFile = (sourceFile, targetFile, callback) => {
|
141 | writeFile(targetFile, readFileContents(sourceFile), callback);
|
142 | },
|
143 |
|
144 | writeFile = (absPath, content, callback) => {
|
145 | let contentString;
|
146 |
|
147 | if (!content.hasOwnProperty('values') && typeof content.values === 'function') {
|
148 | contentString = flatten(content);
|
149 | }
|
150 | else {
|
151 | contentString = content.toString();
|
152 | }
|
153 |
|
154 | createPath(absPath);
|
155 |
|
156 | if (typeof callback === 'function') {
|
157 | fs.writeFile(absPath, contentString, callback);
|
158 | }
|
159 | else {
|
160 | fs.writeFileSync(absPath, contentString);
|
161 | }
|
162 | },
|
163 |
|
164 | writeJsonFile = (absPath, content = {}) => {
|
165 | writeFile(absPath, JSON.stringify(content, null, 2));
|
166 | },
|
167 |
|
168 | readJson5File = (filePath) => {
|
169 |
|
170 | if (!path.isAbsolute(filePath)) {
|
171 | filePath = path.join(ConfigManager.get('rootPath'), filePath);
|
172 | }
|
173 |
|
174 | return ConfigManager.util.parseFile(filePath);
|
175 | },
|
176 |
|
177 | readMarkdownFile = (filePath) => {
|
178 | return marked(readFileContents(filePath));
|
179 | },
|
180 |
|
181 | filterFilenameSibling = (filename, otherFilenames) => {
|
182 | const dirname = path.dirname(filename);
|
183 |
|
184 | return otherFilenames.filter((filename) => path.dirname(filename) === dirname);
|
185 | },
|
186 |
|
187 | hashCode = (str) => {
|
188 | let
|
189 | hash = 0,
|
190 | i,
|
191 | chr,
|
192 | len;
|
193 |
|
194 | if (typeof str !== 'string') {
|
195 | str = JSON.stringify(str);
|
196 | }
|
197 |
|
198 | if (str.length === 0) return hash;
|
199 |
|
200 | for (i = 0, len = str.length; i < len; i++) {
|
201 | chr = str.charCodeAt(i);
|
202 | hash = ((hash << 5) - hash) + chr;
|
203 | hash |= 0;
|
204 | }
|
205 | return Math.abs(hash);
|
206 | },
|
207 |
|
208 | log = (message, type) => {
|
209 | switch (type) {
|
210 | case 'info':
|
211 | fancyLog(colors.green(message));
|
212 | break;
|
213 |
|
214 | case 'notice':
|
215 | fancyLog(colors.gray(message));
|
216 | break;
|
217 |
|
218 | case 'warn':
|
219 | fancyLog(colors.yellow(message));
|
220 | break;
|
221 |
|
222 | case 'error':
|
223 | fancyLog(colors.red(message));
|
224 | break;
|
225 |
|
226 | default:
|
227 | fancyLog(message);
|
228 | }
|
229 | },
|
230 |
|
231 | dumpData = (filename, data) => {
|
232 | if (ConfigManager.get('dumpData', false) === true) {
|
233 | writeJsonFile(`.tmp/${this.constructor.name}-${this.hash}.json`, data);
|
234 | }
|
235 | }
|
236 | ;
|
237 |
|
238 | module.exports.capitalizeString = capitalizeString;
|
239 | module.exports.getTitleFromName = getTitleFromName;
|
240 | module.exports.getTitleFromFilename = getTitleFromFilename;
|
241 | module.exports.getTitleFromFoldername = getTitleFromFoldername;
|
242 | module.exports.getFileExtension = getFileExtension;
|
243 | module.exports.removeFileExtension = removeFileExtension;
|
244 | module.exports.replaceFileExtension = replaceFileExtension;
|
245 | module.exports.readFileContents = readFileContents;
|
246 | module.exports.getRelatedDataPath = getRelatedDataPath;
|
247 | module.exports.readRelatedData = readRelatedData;
|
248 | module.exports.readMarkdownFile = readMarkdownFile;
|
249 | module.exports.readRelatedMarkdown = readRelatedMarkdown;
|
250 | module.exports.isObject = isObject;
|
251 | module.exports.createPath = createPath;
|
252 | module.exports.writeFile = writeFile;
|
253 | module.exports.copyFile = copyFile;
|
254 | module.exports.writeJsonFile = writeJsonFile;
|
255 | module.exports.readJson5File = readJson5File;
|
256 | module.exports.filterFilenameSibling = filterFilenameSibling;
|
257 | module.exports.hashCode = hashCode;
|
258 | module.exports.log = log;
|
259 | module.exports.dumpData = dumpData;
|