hexo-component-inferno 4.2.2 → 5.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -18
- package/asset/css/github-calendar.css +41 -0
- package/asset/js/algolia.js +18 -69
- package/asset/js/github-calendar.js +185 -0
- package/asset/js/google_cse.js +19 -68
- package/asset/js/insight.js +45 -208
- package/lib/core/commented_yaml.js +35 -0
- package/lib/core/default_value.js +150 -0
- package/lib/core/schema.js +8 -196
- package/lib/core/schema_util.js +14 -0
- package/lib/hexo/helper/cdn.js +10 -97
- package/lib/hexo/tag/tabs.js +4 -84
- package/lib/schema/comment/artalk.json +7 -1
- package/lib/schema/comment/cusdis.json +1 -1
- package/lib/schema/comment/facebook.json +1 -1
- package/lib/schema/comment/gitalk.json +23 -6
- package/lib/schema/comment/gitment.json +1 -1
- package/lib/schema/comment/livere.json +9 -3
- package/lib/schema/comment/twikoo.json +3 -3
- package/lib/schema/comment/waline.json +28 -3
- package/lib/schema/misc/open_graph.json +2 -1
- package/lib/schema/plugin/cookie_consent.json +2 -2
- package/lib/schema/plugin/mathjax.json +1 -1
- package/lib/schema/plugin/outdated_browser.json +1 -1
- package/lib/schema/share/bdshare.json +1 -1
- package/lib/schema/share/sharejs.json +1 -1
- package/lib/schema/share/web_share.json +13 -0
- package/lib/schema/widget/github_calendar.json +30 -0
- package/lib/schema/widget/profile.json +67 -0
- package/lib/util/archives.js +86 -0
- package/lib/util/categories.js +102 -0
- package/lib/util/cdn-rules.js +109 -0
- package/lib/util/cdn.js +116 -0
- package/lib/util/consent.js +122 -0
- package/lib/util/deprecate.js +1 -1
- package/lib/util/gallery.js +227 -0
- package/lib/util/insight-search.js +98 -0
- package/lib/util/searchbox.js +88 -0
- package/lib/util/tab-options.js +109 -0
- package/lib/view/comment/artalk.js +24 -6
- package/lib/view/comment/cusdis.js +4 -0
- package/lib/view/comment/disqus.js +1 -1
- package/lib/view/comment/disqusjs.js +7 -6
- package/lib/view/comment/facebook.js +3 -16
- package/lib/view/comment/gitalk.js +18 -15
- package/lib/view/comment/gitment.js +2 -2
- package/lib/view/comment/livere.js +25 -4
- package/lib/view/comment/twikoo.js +5 -3
- package/lib/view/comment/valine.js +4 -3
- package/lib/view/comment/waline.js +8 -6
- package/lib/view/misc/open_graph.js +3 -5
- package/lib/view/plugin/cookie_consent.js +8 -7
- package/lib/view/plugin/gallery.js +42 -19
- package/lib/view/plugin/katex.js +4 -4
- package/lib/view/plugin/mathjax.js +10 -7
- package/lib/view/plugin/outdated_browser.js +59 -45
- package/lib/view/plugin/progressbar.js +6 -1
- package/lib/view/plugin/waline_pageview.js +2 -2
- package/lib/view/search/algolia.js +8 -3
- package/lib/view/search/google_cse.js +13 -10
- package/lib/view/search/insight.js +9 -2
- package/lib/view/share/addthis.js +4 -9
- package/lib/view/share/addtoany.js +23 -5
- package/lib/view/share/bdshare.js +9 -30
- package/lib/view/share/sharejs.js +7 -34
- package/lib/view/share/sharethis.js +21 -6
- package/lib/view/share/web_share.js +153 -0
- package/lib/view/widget/archives.js +19 -71
- package/lib/view/widget/categories.js +20 -67
- package/lib/view/widget/github_calendar.js +94 -0
- package/lib/view/widget/profile.js +194 -0
- package/lib/view/widget/subscribe_email.js +4 -26
- package/package.json +6 -4
package/asset/js/insight.js
CHANGED
|
@@ -4,9 +4,43 @@
|
|
|
4
4
|
*/
|
|
5
5
|
// eslint-disable-next-line no-unused-vars
|
|
6
6
|
function loadInsight(config, translation) {
|
|
7
|
+
const search = window.searchInsight;
|
|
7
8
|
const $main = $('.searchbox');
|
|
8
|
-
|
|
9
|
-
const
|
|
9
|
+
let $input, $container;
|
|
10
|
+
const controller = window.loadSearchbox($main, {
|
|
11
|
+
touch: true,
|
|
12
|
+
onDestroy: () => {
|
|
13
|
+
$(document).off('.insightSearch');
|
|
14
|
+
$input.off('.insightSearch');
|
|
15
|
+
},
|
|
16
|
+
onKeyDown: (e) => {
|
|
17
|
+
switch (e.keyCode) {
|
|
18
|
+
case 38: // UP
|
|
19
|
+
selectItemByDiff(-1);
|
|
20
|
+
break;
|
|
21
|
+
case 40: // DOWN
|
|
22
|
+
selectItemByDiff(1);
|
|
23
|
+
break;
|
|
24
|
+
case 13: // ENTER
|
|
25
|
+
gotoLink($container.find('.searchbox-result-item.active').eq(0));
|
|
26
|
+
break;
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// Replacing the controller disposes the previous engine, which may remove its input widget.
|
|
32
|
+
// Both search views keep this header container; Insight owns a plain text input inside it.
|
|
33
|
+
$input = $main.find('.searchbox-input');
|
|
34
|
+
if (!$input.length) {
|
|
35
|
+
$input = $('<input>').attr({
|
|
36
|
+
type: 'text',
|
|
37
|
+
class: 'searchbox-input',
|
|
38
|
+
placeholder: translation.hint,
|
|
39
|
+
});
|
|
40
|
+
$main.find('.searchbox-header .searchbox-input-container').first().append($input);
|
|
41
|
+
}
|
|
42
|
+
$container = $main.find('.searchbox-body');
|
|
43
|
+
if ($main.hasClass('show')) $input.focus();
|
|
10
44
|
|
|
11
45
|
function section(title) {
|
|
12
46
|
return $('<section>').addClass('searchbox-result-section').append($('<header>').text(title));
|
|
@@ -145,136 +179,10 @@ function loadInsight(config, translation) {
|
|
|
145
179
|
return section(sectionTitle).append($searchItems);
|
|
146
180
|
}
|
|
147
181
|
|
|
148
|
-
function parseKeywords(keywords) {
|
|
149
|
-
return keywords
|
|
150
|
-
.split(' ')
|
|
151
|
-
.filter((keyword) => {
|
|
152
|
-
return !!keyword;
|
|
153
|
-
})
|
|
154
|
-
.map((keyword) => {
|
|
155
|
-
return keyword.toLowerCase();
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
/**
|
|
160
|
-
* Judge if a given post/page/category/tag contains all of the keywords.
|
|
161
|
-
* @param Object obj Object to be weighted
|
|
162
|
-
* @param Array<String> fields Object's fields to find matches
|
|
163
|
-
*/
|
|
164
|
-
function filter(keywords, obj, fields) {
|
|
165
|
-
const keywordArray = parseKeywords(keywords);
|
|
166
|
-
const containKeywords = keywordArray.filter((keyword) => {
|
|
167
|
-
const containFields = fields.filter((field) => {
|
|
168
|
-
if (!Object.prototype.hasOwnProperty.call(obj, field)) {
|
|
169
|
-
return false;
|
|
170
|
-
}
|
|
171
|
-
if (obj[field].toLowerCase().indexOf(keyword) > -1) {
|
|
172
|
-
return true;
|
|
173
|
-
}
|
|
174
|
-
return false;
|
|
175
|
-
});
|
|
176
|
-
if (containFields.length > 0) {
|
|
177
|
-
return true;
|
|
178
|
-
}
|
|
179
|
-
return false;
|
|
180
|
-
});
|
|
181
|
-
return containKeywords.length === keywordArray.length;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
function filterFactory(keywords) {
|
|
185
|
-
return {
|
|
186
|
-
post: function (obj) {
|
|
187
|
-
return filter(keywords, obj, ['title', 'text']);
|
|
188
|
-
},
|
|
189
|
-
page: function (obj) {
|
|
190
|
-
return filter(keywords, obj, ['title', 'text']);
|
|
191
|
-
},
|
|
192
|
-
category: function (obj) {
|
|
193
|
-
return filter(keywords, obj, ['name', 'slug']);
|
|
194
|
-
},
|
|
195
|
-
tag: function (obj) {
|
|
196
|
-
return filter(keywords, obj, ['name', 'slug']);
|
|
197
|
-
},
|
|
198
|
-
};
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
/**
|
|
202
|
-
* Calculate the weight of a matched post/page/category/tag.
|
|
203
|
-
* @param Object obj Object to be weighted
|
|
204
|
-
* @param Array<String> fields Object's fields to find matches
|
|
205
|
-
* @param Array<Integer> weights Weight of every field
|
|
206
|
-
*/
|
|
207
|
-
function weight(keywords, obj, fields, weights) {
|
|
208
|
-
let value = 0;
|
|
209
|
-
parseKeywords(keywords).forEach((keyword) => {
|
|
210
|
-
fields.forEach((field, index) => {
|
|
211
|
-
if (Object.prototype.hasOwnProperty.call(obj, field)) {
|
|
212
|
-
value += countMatches(obj[field].toLowerCase(), keyword) * weights[index];
|
|
213
|
-
}
|
|
214
|
-
});
|
|
215
|
-
});
|
|
216
|
-
return value;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
// Count the occurrences of a lowercase keyword, which is plain text, not a regular expression
|
|
220
|
-
function countMatches(text, keyword) {
|
|
221
|
-
let count = 0;
|
|
222
|
-
for (let i = text.indexOf(keyword); i !== -1; i = text.indexOf(keyword, i + keyword.length)) {
|
|
223
|
-
count++;
|
|
224
|
-
}
|
|
225
|
-
return count;
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
function weightFactory(keywords) {
|
|
229
|
-
return {
|
|
230
|
-
post: function (obj) {
|
|
231
|
-
return weight(keywords, obj, ['title', 'text'], [3, 1]);
|
|
232
|
-
},
|
|
233
|
-
page: function (obj) {
|
|
234
|
-
return weight(keywords, obj, ['title', 'text'], [3, 1]);
|
|
235
|
-
},
|
|
236
|
-
category: function (obj) {
|
|
237
|
-
return weight(keywords, obj, ['name', 'slug'], [1, 1]);
|
|
238
|
-
},
|
|
239
|
-
tag: function (obj) {
|
|
240
|
-
return weight(keywords, obj, ['name', 'slug'], [1, 1]);
|
|
241
|
-
},
|
|
242
|
-
};
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
// Weigh each matching item once, instead of in every comparison of the sort
|
|
246
|
-
function topItems(items, filter, weigh) {
|
|
247
|
-
return items
|
|
248
|
-
.filter(filter)
|
|
249
|
-
.map((item) => {
|
|
250
|
-
return { item, weight: weigh(item) };
|
|
251
|
-
})
|
|
252
|
-
.sort((a, b) => {
|
|
253
|
-
return b.weight - a.weight;
|
|
254
|
-
})
|
|
255
|
-
.slice(0, 5)
|
|
256
|
-
.map((result) => {
|
|
257
|
-
return result.item;
|
|
258
|
-
});
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
function search(json, keywords) {
|
|
262
|
-
const weights = weightFactory(keywords);
|
|
263
|
-
const filters = filterFactory(keywords);
|
|
264
|
-
return {
|
|
265
|
-
posts: topItems(json.posts, filters.post, weights.post),
|
|
266
|
-
pages: topItems(json.pages, filters.page, weights.page),
|
|
267
|
-
categories: topItems(json.categories, filters.category, weights.category),
|
|
268
|
-
tags: topItems(json.tags, filters.tag, weights.tag),
|
|
269
|
-
};
|
|
270
|
-
}
|
|
271
|
-
|
|
272
182
|
function searchResultToDOM(keywords, searchResult) {
|
|
273
183
|
$container.empty();
|
|
274
184
|
for (const key in searchResult) {
|
|
275
|
-
$container.append(
|
|
276
|
-
sectionFactory(parseKeywords(keywords), key.toUpperCase(), searchResult[key]),
|
|
277
|
-
);
|
|
185
|
+
$container.append(sectionFactory(keywords, key.toUpperCase(), searchResult[key]));
|
|
278
186
|
}
|
|
279
187
|
}
|
|
280
188
|
|
|
@@ -305,39 +213,6 @@ function loadInsight(config, translation) {
|
|
|
305
213
|
scrollTo($($items[nextPosition]));
|
|
306
214
|
}
|
|
307
215
|
|
|
308
|
-
let opener = null;
|
|
309
|
-
|
|
310
|
-
function open() {
|
|
311
|
-
if (!$main.hasClass('show')) {
|
|
312
|
-
opener = document.activeElement;
|
|
313
|
-
$main.addClass('show');
|
|
314
|
-
}
|
|
315
|
-
$input.focus();
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
// Return the focus to the element that opened the search box, unless it moved elsewhere
|
|
319
|
-
function close(restoreFocus = true) {
|
|
320
|
-
$main.removeClass('show');
|
|
321
|
-
if (restoreFocus && opener && document.contains(opener)) {
|
|
322
|
-
opener.focus();
|
|
323
|
-
}
|
|
324
|
-
opener = null;
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
// Open the search box with "/" (unless typing in a field) or Ctrl/Cmd+K
|
|
328
|
-
function isSearchShortcut(e) {
|
|
329
|
-
if (e.altKey) {
|
|
330
|
-
return false;
|
|
331
|
-
}
|
|
332
|
-
if (e.ctrlKey || e.metaKey) {
|
|
333
|
-
return !e.shiftKey && typeof e.key === 'string' && e.key.toLowerCase() === 'k';
|
|
334
|
-
}
|
|
335
|
-
// e.key is "/" whatever keys type it on the keyboard layout, so do not check e.shiftKey
|
|
336
|
-
const target = e.target;
|
|
337
|
-
const typing = target.isContentEditable || /^(input|textarea|select)$/i.test(target.tagName);
|
|
338
|
-
return e.key === '/' && !typing;
|
|
339
|
-
}
|
|
340
|
-
|
|
341
216
|
function gotoLink($item) {
|
|
342
217
|
if ($item && $item.length) {
|
|
343
218
|
location.href = $item.attr('href');
|
|
@@ -345,69 +220,31 @@ function loadInsight(config, translation) {
|
|
|
345
220
|
}
|
|
346
221
|
|
|
347
222
|
$.getJSON(config.contentUrl, (json) => {
|
|
223
|
+
if (!controller.isCurrent()) return;
|
|
348
224
|
if (location.hash.trim() === '#insight-search') {
|
|
349
225
|
$main.addClass('show');
|
|
350
226
|
}
|
|
351
|
-
$input.on('input', function () {
|
|
352
|
-
const
|
|
353
|
-
searchResultToDOM(keywords,
|
|
227
|
+
$input.on('input.insightSearch', function () {
|
|
228
|
+
const result = search(json, $(this).val());
|
|
229
|
+
searchResultToDOM(result.keywords, result.results);
|
|
354
230
|
});
|
|
355
231
|
$input.trigger('input');
|
|
356
232
|
});
|
|
357
233
|
|
|
358
234
|
let touch = false;
|
|
359
235
|
$(document)
|
|
360
|
-
.on('click', '.
|
|
361
|
-
|
|
236
|
+
.on('click.insightSearch touchend.insightSearch', '.searchbox-result-item', function (e) {
|
|
237
|
+
if (!controller.isCurrent()) return;
|
|
362
238
|
if (e.type !== 'click' && !touch) {
|
|
363
239
|
return;
|
|
364
240
|
}
|
|
365
241
|
gotoLink($(this));
|
|
366
242
|
touch = false;
|
|
367
243
|
})
|
|
368
|
-
.on('
|
|
369
|
-
if (e.type !== 'click' && !touch) {
|
|
370
|
-
return;
|
|
371
|
-
}
|
|
372
|
-
$('.navbar-main').css('pointer-events', 'none');
|
|
373
|
-
setTimeout(() => {
|
|
374
|
-
$('.navbar-main').css('pointer-events', 'auto');
|
|
375
|
-
}, 400);
|
|
376
|
-
close();
|
|
377
|
-
touch = false;
|
|
378
|
-
})
|
|
379
|
-
.on('focusin', (e) => {
|
|
380
|
-
// Close the search box when the focus moves to the rest of the page, e.g., by Tab
|
|
381
|
-
if ($main.hasClass('show') && !$main[0].contains(e.target)) {
|
|
382
|
-
close(false);
|
|
383
|
-
}
|
|
384
|
-
})
|
|
385
|
-
.on('keydown', (e) => {
|
|
386
|
-
if (isSearchShortcut(e)) {
|
|
387
|
-
e.preventDefault();
|
|
388
|
-
open();
|
|
389
|
-
return;
|
|
390
|
-
}
|
|
391
|
-
if (!$main.hasClass('show')) return;
|
|
392
|
-
switch (e.keyCode) {
|
|
393
|
-
case 27: // ESC
|
|
394
|
-
close();
|
|
395
|
-
break;
|
|
396
|
-
case 38: // UP
|
|
397
|
-
selectItemByDiff(-1);
|
|
398
|
-
break;
|
|
399
|
-
case 40: // DOWN
|
|
400
|
-
selectItemByDiff(1);
|
|
401
|
-
break;
|
|
402
|
-
case 13: // ENTER
|
|
403
|
-
gotoLink($container.find('.searchbox-result-item.active').eq(0));
|
|
404
|
-
break;
|
|
405
|
-
}
|
|
406
|
-
})
|
|
407
|
-
.on('touchstart', (e) => {
|
|
244
|
+
.on('touchstart.insightSearch', () => {
|
|
408
245
|
touch = true;
|
|
409
246
|
})
|
|
410
|
-
.on('touchmove', (
|
|
247
|
+
.on('touchmove.insightSearch', () => {
|
|
411
248
|
touch = false;
|
|
412
249
|
});
|
|
413
250
|
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Serialize the comment markers produced by DefaultValue as YAML comments.
|
|
3
|
+
* @module core/commented_yaml
|
|
4
|
+
*/
|
|
5
|
+
const yaml = require('../util/yaml');
|
|
6
|
+
|
|
7
|
+
/** A magic string for reformatting comment lines in the YAML output. */
|
|
8
|
+
const MAGIC = 'c823d4d4';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @param {any} value The commented object or array.
|
|
12
|
+
* @returns {string} The formatted YAML string.
|
|
13
|
+
*/
|
|
14
|
+
function stringify(value) {
|
|
15
|
+
// The YAML writer may quote comments. Parse them rather than removing quotes by hand.
|
|
16
|
+
const property = new RegExp(`^(\\s*)(['"]?)${MAGIC}.*?\\2: (.*)$`);
|
|
17
|
+
const element = new RegExp(`^(\\s*)- (.*${MAGIC}.*)$`);
|
|
18
|
+
const comment = (indent, text) => `${indent}# ${text === null || text === undefined ? '' : text}`;
|
|
19
|
+
return yaml.stringify(value).split('\n').map(line => {
|
|
20
|
+
let match = property.exec(line);
|
|
21
|
+
if (match) {
|
|
22
|
+
return comment(match[1], yaml.parse(match[3]));
|
|
23
|
+
}
|
|
24
|
+
match = element.exec(line);
|
|
25
|
+
if (match) {
|
|
26
|
+
const text = String(yaml.parse(match[2]));
|
|
27
|
+
return comment(match[1], text.slice(text.indexOf(': ') + 2));
|
|
28
|
+
}
|
|
29
|
+
return line;
|
|
30
|
+
}).join('\n');
|
|
31
|
+
}
|
|
32
|
+
module.exports = {
|
|
33
|
+
MAGIC,
|
|
34
|
+
stringify
|
|
35
|
+
};
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default value wrappers, merging, and comment annotation, independent of schema loading/validation.
|
|
3
|
+
* @module core/default_value
|
|
4
|
+
*/
|
|
5
|
+
const {
|
|
6
|
+
typeOf,
|
|
7
|
+
hasOwnProperty
|
|
8
|
+
} = require('./schema_util');
|
|
9
|
+
const {
|
|
10
|
+
MAGIC,
|
|
11
|
+
stringify
|
|
12
|
+
} = require('./commented_yaml');
|
|
13
|
+
|
|
14
|
+
/** The default value wrapper class. */
|
|
15
|
+
class DefaultValue {
|
|
16
|
+
/**
|
|
17
|
+
* @param {any} value The wrapped default value.
|
|
18
|
+
* @param {string} description A description used to produce the comment string.
|
|
19
|
+
*/
|
|
20
|
+
constructor(value, description) {
|
|
21
|
+
this.value = value;
|
|
22
|
+
this.description = description;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Duplicate this wrapper, shallow-copying its wrapped arrays and objects.
|
|
27
|
+
* @returns {DefaultValue} A new wrapper.
|
|
28
|
+
*/
|
|
29
|
+
clone() {
|
|
30
|
+
const result = new DefaultValue(this.value, this.description);
|
|
31
|
+
if (result.value instanceof DefaultValue) {
|
|
32
|
+
result.value = result.value.clone();
|
|
33
|
+
} else if (typeOf(result.value) === 'array') {
|
|
34
|
+
result.value = [].concat(result.value);
|
|
35
|
+
} else if (typeOf(result.value) === 'object') {
|
|
36
|
+
result.value = Object.assign({}, result.value);
|
|
37
|
+
}
|
|
38
|
+
return result;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Unwrap nested wrappers, preferring the innermost non-empty description. */
|
|
42
|
+
flatten() {
|
|
43
|
+
if (this.value instanceof DefaultValue) {
|
|
44
|
+
this.value.flatten();
|
|
45
|
+
if (hasOwnProperty(this.value, 'description') && this.value.description) {
|
|
46
|
+
this.description = this.value.description;
|
|
47
|
+
}
|
|
48
|
+
this.value = this.value.value;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Merge a wrapper with the same value type, concatenating arrays and assigning object properties.
|
|
54
|
+
* @param {DefaultValue} source The wrapper to merge.
|
|
55
|
+
*/
|
|
56
|
+
merge(source) {
|
|
57
|
+
if (hasOwnProperty(source, 'value') && source.value !== null) {
|
|
58
|
+
this.flatten();
|
|
59
|
+
if (source.value instanceof DefaultValue) {
|
|
60
|
+
source = source.clone();
|
|
61
|
+
source.flatten();
|
|
62
|
+
}
|
|
63
|
+
if (typeOf(source.value) === typeOf(this.value)) {
|
|
64
|
+
if (typeOf(this.value) === 'array') {
|
|
65
|
+
this.value = this.value.concat(source.value);
|
|
66
|
+
} else if (typeOf(this.value) === 'object') {
|
|
67
|
+
Object.keys(source.value).forEach(key => {
|
|
68
|
+
this.value[key] = source.value[key];
|
|
69
|
+
});
|
|
70
|
+
} else {
|
|
71
|
+
this.value = source.value;
|
|
72
|
+
}
|
|
73
|
+
} else if (typeOf(this.value) === 'undefined' || typeOf(this.value) === 'null') {
|
|
74
|
+
this.value = source.value;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (hasOwnProperty(source, 'description') && source.description) {
|
|
78
|
+
this.description = source.description;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Insert description markers before each wrapped array element.
|
|
84
|
+
* @returns {Array} A new array of comments and annotated values.
|
|
85
|
+
*/
|
|
86
|
+
toCommentedArray() {
|
|
87
|
+
return [].concat(...this.value.map(item => {
|
|
88
|
+
if (item instanceof DefaultValue) {
|
|
89
|
+
if (typeOf(item.description) !== 'string' || !item.description.trim()) {
|
|
90
|
+
return [item.toCommented()];
|
|
91
|
+
}
|
|
92
|
+
return item.description.split('\n').map((line, i) => {
|
|
93
|
+
return MAGIC + i + ': ' + line;
|
|
94
|
+
}).concat(item.toCommented());
|
|
95
|
+
} else if (typeOf(item) === 'array' || typeOf(item) === 'object') {
|
|
96
|
+
return new DefaultValue(item).toCommented();
|
|
97
|
+
}
|
|
98
|
+
return [item];
|
|
99
|
+
}));
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Insert description markers before each wrapped object property.
|
|
104
|
+
* @returns {Object} A new object of comments and annotated values.
|
|
105
|
+
*/
|
|
106
|
+
toCommentedObject() {
|
|
107
|
+
if (this.value instanceof DefaultValue) {
|
|
108
|
+
return this.value.toCommented();
|
|
109
|
+
}
|
|
110
|
+
const result = {};
|
|
111
|
+
for (const key in this.value) {
|
|
112
|
+
const item = this.value[key];
|
|
113
|
+
if (item instanceof DefaultValue) {
|
|
114
|
+
if (typeOf(item.description) === 'string' && item.description.trim()) {
|
|
115
|
+
item.description.split('\n').forEach((line, i) => {
|
|
116
|
+
result[MAGIC + key + i] = line;
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
result[key] = item.toCommented();
|
|
120
|
+
} else if (typeOf(item) === 'array' || typeOf(item) === 'object') {
|
|
121
|
+
result[key] = new DefaultValue(item).toCommented();
|
|
122
|
+
} else {
|
|
123
|
+
result[key] = item;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return result;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Annotate arrays and objects with comment markers, or return a primitive value unchanged.
|
|
131
|
+
* @returns {any} The annotated value.
|
|
132
|
+
*/
|
|
133
|
+
toCommented() {
|
|
134
|
+
if (typeOf(this.value) === 'array') {
|
|
135
|
+
return this.toCommentedArray();
|
|
136
|
+
} else if (typeOf(this.value) === 'object') {
|
|
137
|
+
return this.toCommentedObject();
|
|
138
|
+
}
|
|
139
|
+
return this.value;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Create YAML including the descriptions of nested values as comments.
|
|
144
|
+
* @returns {string} The formatted YAML string.
|
|
145
|
+
*/
|
|
146
|
+
toYaml() {
|
|
147
|
+
return stringify(this.toCommented());
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
module.exports = DefaultValue;
|