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.
Files changed (73) hide show
  1. package/README.md +5 -18
  2. package/asset/css/github-calendar.css +41 -0
  3. package/asset/js/algolia.js +18 -69
  4. package/asset/js/github-calendar.js +185 -0
  5. package/asset/js/google_cse.js +19 -68
  6. package/asset/js/insight.js +45 -208
  7. package/lib/core/commented_yaml.js +35 -0
  8. package/lib/core/default_value.js +150 -0
  9. package/lib/core/schema.js +8 -196
  10. package/lib/core/schema_util.js +14 -0
  11. package/lib/hexo/helper/cdn.js +10 -97
  12. package/lib/hexo/tag/tabs.js +4 -84
  13. package/lib/schema/comment/artalk.json +7 -1
  14. package/lib/schema/comment/cusdis.json +1 -1
  15. package/lib/schema/comment/facebook.json +1 -1
  16. package/lib/schema/comment/gitalk.json +23 -6
  17. package/lib/schema/comment/gitment.json +1 -1
  18. package/lib/schema/comment/livere.json +9 -3
  19. package/lib/schema/comment/twikoo.json +3 -3
  20. package/lib/schema/comment/waline.json +28 -3
  21. package/lib/schema/misc/open_graph.json +2 -1
  22. package/lib/schema/plugin/cookie_consent.json +2 -2
  23. package/lib/schema/plugin/mathjax.json +1 -1
  24. package/lib/schema/plugin/outdated_browser.json +1 -1
  25. package/lib/schema/share/bdshare.json +1 -1
  26. package/lib/schema/share/sharejs.json +1 -1
  27. package/lib/schema/share/web_share.json +13 -0
  28. package/lib/schema/widget/github_calendar.json +30 -0
  29. package/lib/schema/widget/profile.json +67 -0
  30. package/lib/util/archives.js +86 -0
  31. package/lib/util/categories.js +102 -0
  32. package/lib/util/cdn-rules.js +109 -0
  33. package/lib/util/cdn.js +116 -0
  34. package/lib/util/consent.js +122 -0
  35. package/lib/util/deprecate.js +1 -1
  36. package/lib/util/gallery.js +227 -0
  37. package/lib/util/insight-search.js +98 -0
  38. package/lib/util/searchbox.js +88 -0
  39. package/lib/util/tab-options.js +109 -0
  40. package/lib/view/comment/artalk.js +24 -6
  41. package/lib/view/comment/cusdis.js +4 -0
  42. package/lib/view/comment/disqus.js +1 -1
  43. package/lib/view/comment/disqusjs.js +7 -6
  44. package/lib/view/comment/facebook.js +3 -16
  45. package/lib/view/comment/gitalk.js +18 -15
  46. package/lib/view/comment/gitment.js +2 -2
  47. package/lib/view/comment/livere.js +25 -4
  48. package/lib/view/comment/twikoo.js +5 -3
  49. package/lib/view/comment/valine.js +4 -3
  50. package/lib/view/comment/waline.js +8 -6
  51. package/lib/view/misc/open_graph.js +3 -5
  52. package/lib/view/plugin/cookie_consent.js +8 -7
  53. package/lib/view/plugin/gallery.js +42 -19
  54. package/lib/view/plugin/katex.js +4 -4
  55. package/lib/view/plugin/mathjax.js +10 -7
  56. package/lib/view/plugin/outdated_browser.js +59 -45
  57. package/lib/view/plugin/progressbar.js +6 -1
  58. package/lib/view/plugin/waline_pageview.js +2 -2
  59. package/lib/view/search/algolia.js +8 -3
  60. package/lib/view/search/google_cse.js +13 -10
  61. package/lib/view/search/insight.js +9 -2
  62. package/lib/view/share/addthis.js +4 -9
  63. package/lib/view/share/addtoany.js +23 -5
  64. package/lib/view/share/bdshare.js +9 -30
  65. package/lib/view/share/sharejs.js +7 -34
  66. package/lib/view/share/sharethis.js +21 -6
  67. package/lib/view/share/web_share.js +153 -0
  68. package/lib/view/widget/archives.js +19 -71
  69. package/lib/view/widget/categories.js +20 -67
  70. package/lib/view/widget/github_calendar.js +94 -0
  71. package/lib/view/widget/profile.js +194 -0
  72. package/lib/view/widget/subscribe_email.js +4 -26
  73. package/package.json +6 -4
@@ -59,7 +59,8 @@
59
59
  },
60
60
  "google_plus": {
61
61
  "type": "string",
62
- "description": "Google+ profile link (deprecated)",
62
+ "description": "Google+ profile link (deprecated; ignored)",
63
+ "deprecated": true,
63
64
  "nullable": true
64
65
  },
65
66
  "fb_admins": {
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "$schema": "http://json-schema.org/draft-07/schema#",
3
3
  "$id": "/plugin/cookie_consent.json",
4
- "description": "Alerting users about the use of cookies\nhttps://www.osano.com/cookieconsent/",
4
+ "description": "Cookie notice and tracking consent\nhttps://www.osano.com/cookieconsent/",
5
5
  "type": "object",
6
6
  "properties": {
7
7
  "type": {
8
8
  "type": "string",
9
- "description": "The compliance type. Can be \"info\", \"opt-in\", or \"opt-out\"",
9
+ "description": "info: notice only; opt-in: load after consent; opt-out: load until denied",
10
10
  "default": "info",
11
11
  "nullable": true
12
12
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "http://json-schema.org/draft-07/schema#",
3
3
  "$id": "/plugin/mathjax.json",
4
- "description": "Enable the MathJax math typesetting support\nhttps://www.mathjax.org/",
4
+ "description": "Enable MathJax math typesetting\nhttps://www.mathjax.org/",
5
5
  "type": "boolean",
6
6
  "default": false
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "http://json-schema.org/draft-07/schema#",
3
3
  "$id": "/plugin/outdated_browser.json",
4
- "description": "Enable the Outdated Browser plugin\nhttp://outdatedbrowser.com/",
4
+ "description": "Warn when required CSS features are unsupported",
5
5
  "type": "boolean",
6
6
  "default": false
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "http://json-schema.org/draft-07/schema#",
3
3
  "$id": "/share/bdshare.json",
4
- "description": "Enable Baidu share buttons",
4
+ "description": "Baidu share buttons (deprecated)",
5
5
  "type": "object",
6
6
  "properties": {
7
7
  "type": {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "http://json-schema.org/draft-07/schema#",
3
3
  "$id": "/share/sharejs.json",
4
- "description": "Enable Share.js share buttons\nhttps://github.com/overtrue/share.js/",
4
+ "description": "Share.js (retired; select web_share or addtoany)",
5
5
  "type": "object",
6
6
  "properties": {
7
7
  "type": {
@@ -0,0 +1,13 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "/share/web_share.json",
4
+ "description": "Social sharing links and a native Web Share button",
5
+ "type": "object",
6
+ "properties": {
7
+ "type": {
8
+ "type": "string",
9
+ "const": "web_share"
10
+ }
11
+ },
12
+ "required": ["type"]
13
+ }
@@ -0,0 +1,30 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "/widget/github_calendar.json",
4
+ "description": "Responsive GitHub contribution calendar. Data is loaded from the third-party github-contributions-api.jogruber.de service; no GitHub token is needed",
5
+ "type": "object",
6
+ "properties": {
7
+ "type": {
8
+ "type": "string",
9
+ "const": "github_calendar"
10
+ },
11
+ "username": {
12
+ "type": "string",
13
+ "description": "GitHub username. Leave empty to hide this widget",
14
+ "pattern": "^$|^[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,37}[a-zA-Z0-9])?$",
15
+ "nullable": true
16
+ },
17
+ "title": {
18
+ "type": "string",
19
+ "description": "Widget title. Leave empty to use the translated default",
20
+ "nullable": true
21
+ },
22
+ "color": {
23
+ "type": "string",
24
+ "description": "Optional six-digit hex color, for example '#40c463'. Leave empty to use the theme's calendar palette",
25
+ "pattern": "^$|^#?[a-fA-F0-9]{6}$",
26
+ "nullable": true
27
+ }
28
+ },
29
+ "required": ["type"]
30
+ }
@@ -0,0 +1,67 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "/widget/profile.json",
4
+ "description": "Profile widget configurations",
5
+ "type": "object",
6
+ "properties": {
7
+ "type": {
8
+ "type": "string",
9
+ "const": "profile",
10
+ "nullable": true
11
+ },
12
+ "author": {
13
+ "type": "string",
14
+ "description": "Author name",
15
+ "examples": ["Your name"],
16
+ "nullable": true
17
+ },
18
+ "author_title": {
19
+ "type": "string",
20
+ "description": "Author title",
21
+ "examples": ["Your title"],
22
+ "nullable": true
23
+ },
24
+ "location": {
25
+ "type": "string",
26
+ "description": "Author's current location",
27
+ "examples": ["Your location"],
28
+ "nullable": true
29
+ },
30
+ "avatar": {
31
+ "type": "string",
32
+ "description": "URL or path to the avatar image",
33
+ "nullable": true
34
+ },
35
+ "avatar_rounded": {
36
+ "type": "boolean",
37
+ "description": "Whether show the rounded avatar image",
38
+ "default": false,
39
+ "nullable": true
40
+ },
41
+ "gravatar": {
42
+ "type": "string",
43
+ "description": "Email address for the Gravatar",
44
+ "nullable": true
45
+ },
46
+ "follow_link": {
47
+ "type": "string",
48
+ "description": "URL or path for the follow button",
49
+ "examples": ["https://github.com/ppoffice"],
50
+ "nullable": true
51
+ },
52
+ "social_links": {
53
+ "$ref": "/misc/poly_links.json",
54
+ "description": "Links to be shown on the bottom of the profile widget",
55
+ "examples": [
56
+ {
57
+ "Github": { "icon": "fab fa-github", "url": "https://github.com/ppoffice" },
58
+ "Facebook": { "icon": "fab fa-facebook", "url": "https://facebook.com" },
59
+ "Twitter": { "icon": "fab fa-twitter", "url": "https://twitter.com" },
60
+ "Dribbble": { "icon": "fab fa-dribbble", "url": "https://dribbble.com" },
61
+ "RSS": { "icon": "fas fa-rss", "url": "/" }
62
+ }
63
+ ]
64
+ }
65
+ },
66
+ "required": ["type"]
67
+ }
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Internal option and grouping logic for the archives widget. No Hexo imports, helpers or JSX.
3
+ * @module util/archives
4
+ * @private
5
+ */
6
+
7
+ function firstSet(...values) {
8
+ return values.find(value => value !== null && typeof value !== 'undefined');
9
+ }
10
+
11
+ /**
12
+ * Resolve archive option aliases/defaults without coercing false, zero or empty strings.
13
+ * @param {Object} widget Archives widget options.
14
+ * @returns {Object} Resolved grouping, ordering, formatting, limit and count-display options.
15
+ */
16
+ function resolveArchiveOptions(widget) {
17
+ const groupBy = firstSet(widget.group_by, 'monthly');
18
+ const order = firstSet(widget.order, -1);
19
+ const {
20
+ format,
21
+ amount
22
+ } = widget;
23
+ const showCount = firstSet(widget.show_count, widget.showCount, true);
24
+ return {
25
+ groupBy,
26
+ order,
27
+ format,
28
+ amount,
29
+ showCount
30
+ };
31
+ }
32
+
33
+ // Same conversion as Hexo's toMomentLocale, without depending on Hexo's private modules.
34
+ function toMomentLocale(lang) {
35
+ if (lang === undefined) return undefined;
36
+ if (!lang || lang === 'en' || lang === 'default') return 'en';
37
+ return lang.toLowerCase().replace('_', '-');
38
+ }
39
+
40
+ /**
41
+ * Group already ordered posts by consecutive formatted names and apply the archive limit.
42
+ * The first date in each group supplies its year/month even when a custom format merges years.
43
+ * Sorting stays with the Hexo collection adapter; this function only needs forEach and date.clone.
44
+ * @param {{forEach: Function}} posts Ordered records with Moment-compatible date values.
45
+ * @param {Object} options groupBy/format/amount plus the selected language code and timezone.
46
+ * @returns {Object} Selected groups ({name, year, month, count}) and hasMore; URLs remain unresolved.
47
+ */
48
+ function groupArchives(posts, options) {
49
+ const {
50
+ groupBy,
51
+ format,
52
+ amount,
53
+ timezone
54
+ } = options;
55
+ const language = toMomentLocale(options.language);
56
+ const groups = [];
57
+ let length = 0;
58
+ posts.forEach(post => {
59
+ let date = post.date.clone();
60
+ if (timezone) date = date.tz(timezone);
61
+ if (language) date = date.locale(language);
62
+ const year = date.year();
63
+ const month = date.month() + 1;
64
+ const name = date.format(format || (groupBy === 'monthly' ? 'MMMM YYYY' : 'YYYY'));
65
+ const last = groups[length - 1];
66
+ if (!last || last.name !== name) {
67
+ length = groups.push({
68
+ name,
69
+ year,
70
+ month,
71
+ count: 1
72
+ });
73
+ } else {
74
+ last.count++;
75
+ }
76
+ });
77
+ const hasMore = amount > 0 && groups.length > amount;
78
+ return {
79
+ groups: hasMore ? groups.slice(0, amount) : groups,
80
+ hasMore
81
+ };
82
+ }
83
+ module.exports = {
84
+ resolveArchiveOptions,
85
+ groupArchives
86
+ };
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Internal category option and tree preparation, independent of Hexo initialization and JSX.
3
+ * @module util/categories
4
+ * @private
5
+ */
6
+
7
+ function firstSet(...values) {
8
+ return values.find(value => value !== null && typeof value !== 'undefined');
9
+ }
10
+
11
+ /**
12
+ * Resolve aliases/defaults without coercing explicit false, zero or empty strings.
13
+ * @param {Object} widget Categories widget options.
14
+ * @returns {Object} order, orderBy, showCurrent and showCount.
15
+ */
16
+ function resolveCategoryOptions(widget) {
17
+ const order = firstSet(widget.order, 1);
18
+ const orderBy = firstSet(widget.order_by, widget.orderBy, 'name');
19
+ const showCurrent = firstSet(widget.show_current, widget.showCurrent, false);
20
+ const showCount = firstSet(widget.show_count, widget.showCount, true);
21
+ return {
22
+ order,
23
+ orderBy,
24
+ showCurrent,
25
+ showCount
26
+ };
27
+ }
28
+
29
+ /**
30
+ * Parse depth only after the caller's empty-source check, retaining parseInt and zero-as-unlimited.
31
+ * @param {*} depth Widget depth.
32
+ * @param {*} fallback Legacy top-level props.depth.
33
+ * @returns {number} Parsed depth, or zero for an unset/unparseable value.
34
+ */
35
+ function resolveCategoryDepth(depth, fallback) {
36
+ return parseInt(firstSet(depth, fallback), 10) || 0;
37
+ }
38
+ function prepareQuery(categories, parent, orderBy, order) {
39
+ const query = {};
40
+ if (parent) query.parent = parent;else query.parent = {
41
+ $exists: false
42
+ };
43
+ return categories.find(query).sort(orderBy, order).filter(cat => cat.length);
44
+ }
45
+ function currentCategory(cat, page) {
46
+ let isCurrent = false;
47
+ for (let j = 0; j < cat.length; j++) {
48
+ const post = cat.posts.data[j];
49
+ if (post && post._id === page._id) {
50
+ isCurrent = true;
51
+ break;
52
+ }
53
+ }
54
+ // Preserve both the raw prefix test and its falsey/unset result, rather than coercing to boolean.
55
+ return isCurrent || page.base && page.base.startsWith(cat.path);
56
+ }
57
+
58
+ /**
59
+ * Prepare the category tree through the collection's existing find/sort/filter/map contract.
60
+ * URLs are resolved in the original depth-first postorder, even for subsequently hidden roots.
61
+ * Keeping the URL helper at this point also preserves helper calls before later query/current errors.
62
+ * @param {Object} categories Queryable source with the existing find/sort/filter/map contract.
63
+ * @param {Object} options Resolved order/orderBy/showCurrent/depth plus raw amount.
64
+ * @param {Object} page Current page; an unset page skips current checks.
65
+ * @param {Function} url_for Existing URL helper, not a generic node projection.
66
+ * @returns {Object} Selected categories ({children, isCurrent, name, count, url}) and hasMore.
67
+ */
68
+ function prepareCategories(categories, options, page, url_for) {
69
+ const {
70
+ order,
71
+ orderBy,
72
+ showCurrent,
73
+ depth,
74
+ amount
75
+ } = options;
76
+ function hierarchicalList(level, parent) {
77
+ return prepareQuery(categories, parent, orderBy, order).map(cat => {
78
+ let children = [];
79
+ if (!depth || level + 1 < depth) children = hierarchicalList(level + 1, cat._id);
80
+ let isCurrent = false;
81
+ if (showCurrent && page) isCurrent = currentCategory(cat, page);
82
+ return {
83
+ children,
84
+ isCurrent,
85
+ name: cat.name,
86
+ count: cat.length,
87
+ url: url_for(cat.path)
88
+ };
89
+ });
90
+ }
91
+ const list = hierarchicalList(0);
92
+ const hasMore = amount > 0 && list.length > amount;
93
+ return {
94
+ categories: hasMore ? list.slice(0, amount) : list,
95
+ hasMore
96
+ };
97
+ }
98
+ module.exports = {
99
+ resolveCategoryOptions,
100
+ resolveCategoryDepth,
101
+ prepareCategories
102
+ };
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Provider templates and package compatibility rules, private to the URL resolver.
3
+ * @module util/cdn-rules
4
+ * @private
5
+ */
6
+ const PROVIDERS = {
7
+ LIBRARY: {
8
+ cdnjs: '[cdnjs]https://cdnjs.cloudflare.com/ajax/libs/${ package }/${ version }/${ filename }',
9
+ loli: '[cdnjs]https://cdnjs.loli.net/ajax/libs/${ package }/${ version }/${ filename }',
10
+ jsdelivr: 'https://cdn.jsdelivr.net/npm/${ package }@${ version }/${ filename }',
11
+ unpkg: 'https://unpkg.com/${ package }@${ version }/${ filename }'
12
+ },
13
+ FONT: {
14
+ google: 'https://fonts.googleapis.com/${ type }?family=${ fontname }',
15
+ loli: 'https://fonts.loli.net/${ type }?family=${ fontname }',
16
+ fontim: 'https://fonts.font.im/${ type }?family=${ fontname }',
17
+ ustc: 'https://fonts.lug.ustc.edu.cn/${ type }?family=${ fontname }'
18
+ },
19
+ ICON: {
20
+ loli: 'https://cdnjs.loli.net/ajax/libs/font-awesome/6.0.0/css/all.min.css',
21
+ fontawesome: 'https://use.fontawesome.com/releases/v6.0.0/css/all.css'
22
+ }
23
+ };
24
+ function stripPrefix(filename, prefix) {
25
+ return filename.startsWith(prefix) ? filename.substr(prefix.length) : filename;
26
+ }
27
+ function stripMin(filename) {
28
+ return filename.indexOf('.min.') > -1 ? filename.replace(/\.min\./gi, '.') : filename;
29
+ }
30
+
31
+ // An absent mapping preserves the npm path; null means the provider lacks the package.
32
+ const PACKAGE_RULES = {
33
+ 'justified-gallery': {
34
+ cdnjs: null
35
+ },
36
+ '@mathjax/mathjax-newcm-font': {
37
+ cdnjs: null
38
+ },
39
+ lightgallery: {
40
+ // cdnjs itself serves this release, but its loli mirror lacks the CSS, core and plugins.
41
+ unavailable: [{
42
+ provider: 'loli',
43
+ version: '3.0.0'
44
+ }]
45
+ },
46
+ disqusjs: {
47
+ cdnjs: {
48
+ filename: file => stripPrefix(file, 'dist/browser/')
49
+ },
50
+ unpkg: {
51
+ filename: file => file.startsWith('dist/browser/') ? file : file.replace(/\.min\./gi, '.')
52
+ }
53
+ },
54
+ moment: {
55
+ cdnjs: {
56
+ package: 'moment.js',
57
+ filename: file => stripPrefix(file, 'min/')
58
+ }
59
+ },
60
+ outdatedbrowser: {
61
+ cdnjs: {
62
+ package: 'outdated-browser',
63
+ filename: file => stripPrefix(file, 'outdatedbrowser/')
64
+ }
65
+ },
66
+ 'highlight.js': {
67
+ cdnjs: {
68
+ filename: file => file.endsWith('.css') && file.indexOf('.min.') === -1 ? file.substr(0, file.length - 4) + '.min.css' : file
69
+ }
70
+ },
71
+ mathjax: {
72
+ cdnjs: {
73
+ filename: file => stripMin(stripPrefix(file, 'unpacked/'))
74
+ },
75
+ unpkg: {
76
+ filename: stripMin
77
+ }
78
+ },
79
+ katex: {
80
+ cdnjs: {
81
+ package: 'KaTeX'
82
+ }
83
+ },
84
+ 'pace-js': {
85
+ cdnjs: {
86
+ package: 'pace'
87
+ }
88
+ },
89
+ clipboard: {
90
+ cdnjs: {
91
+ package: 'clipboard.js'
92
+ }
93
+ },
94
+ cookieconsent: {
95
+ cdnjs: {
96
+ filename: file => stripPrefix(file, 'build/')
97
+ }
98
+ },
99
+ '@waline/client': {
100
+ cdnjs: {
101
+ package: 'waline'
102
+ }
103
+ }
104
+ };
105
+ module.exports = {
106
+ PROVIDERS,
107
+ PACKAGE_RULES,
108
+ stripPrefix
109
+ };
@@ -0,0 +1,116 @@
1
+ /**
2
+ * Pure CDN URL resolution. Hexo registration and package compatibility rules stay separate.
3
+ * @module util/cdn
4
+ * @private
5
+ */
6
+ const {
7
+ PROVIDERS,
8
+ PACKAGE_RULES,
9
+ stripPrefix
10
+ } = require('./cdn-rules');
11
+ function selectLibraryProvider(providers, name) {
12
+ const {
13
+ cdn_overrides: overrides
14
+ } = providers;
15
+ return typeof overrides === 'object' && overrides !== null && overrides[name] ? overrides[name] : providers.cdn || 'jsdelivr';
16
+ }
17
+ function packageRule(name) {
18
+ return Object.prototype.hasOwnProperty.call(PACKAGE_RULES, name) ? PACKAGE_RULES[name] : {};
19
+ }
20
+ function resolveLibraryAsset(provider, asset) {
21
+ let template = provider in PROVIDERS.LIBRARY ? PROVIDERS.LIBRARY[provider] : provider;
22
+ const unavailable = typeof asset.package === 'string' && packageRule(asset.package).unavailable;
23
+ if (unavailable && unavailable.some(entry => entry.provider === provider && entry.version === asset.version)) {
24
+ return {
25
+ template: PROVIDERS.LIBRARY.jsdelivr,
26
+ asset
27
+ };
28
+ }
29
+ let family = provider === 'unpkg' ? 'unpkg' : null;
30
+ if (template.startsWith('[cdnjs]')) {
31
+ family = 'cdnjs';
32
+ template = template.substr(7);
33
+ }
34
+ if (!family) return {
35
+ template,
36
+ asset
37
+ };
38
+ try {
39
+ const mapping = packageRule(asset.package)[family];
40
+ if (mapping === null) return {
41
+ template: PROVIDERS.LIBRARY.jsdelivr,
42
+ asset
43
+ };
44
+ if (mapping) {
45
+ // Commit a mapping only after its path conversion succeeds. Later failures retain renames.
46
+ asset = {
47
+ package: mapping.package || asset.package,
48
+ version: asset.version,
49
+ filename: mapping.filename ? mapping.filename(asset.filename) : asset.filename
50
+ };
51
+ }
52
+ if (family === 'cdnjs') asset.filename = stripPrefix(asset.filename, 'dist/');
53
+ } catch (e) {
54
+ template = PROVIDERS.LIBRARY.jsdelivr;
55
+ }
56
+ return {
57
+ template,
58
+ asset
59
+ };
60
+ }
61
+ function formatLibraryUrl({
62
+ template,
63
+ asset
64
+ }) {
65
+ return template.replace(/\${\s*package\s*}/gi, asset.package).replace(/\${\s*version\s*}/gi, asset.version).replace(/\${\s*filename\s*}/gi, asset.filename);
66
+ }
67
+
68
+ /**
69
+ * Resolve a library URL with optional per-package provider overrides.
70
+ * @param {Object} providers Provider configuration.
71
+ * @param {string} _package npm package name.
72
+ * @param {string} version Library version.
73
+ * @param {string} filename Path in the npm package.
74
+ * @returns {string} The resolved URL.
75
+ */
76
+ function resolveCdn(providers, _package, version, filename) {
77
+ const provider = selectLibraryProvider(providers, _package);
78
+ return formatLibraryUrl(resolveLibraryAsset(provider, {
79
+ package: _package,
80
+ version,
81
+ filename
82
+ }));
83
+ }
84
+
85
+ /**
86
+ * Resolve a web font URL; only undefined selects provider/type defaults.
87
+ * @param {Object} providers Provider configuration.
88
+ * @param {string} fontName Font family expression, unchanged by URL encoding.
89
+ * @param {string} [type=css] Google Fonts endpoint type.
90
+ * @returns {string} The resolved font URL.
91
+ */
92
+ function resolveFontCdn(providers, fontName, type = 'css') {
93
+ let {
94
+ fontcdn = 'google'
95
+ } = providers;
96
+ if (fontcdn in PROVIDERS.FONT) fontcdn = PROVIDERS.FONT[fontcdn];
97
+ return fontcdn.replace(/\${\s*fontname\s*}/gi, fontName).replace(/\${\s*type\s*}/gi, type);
98
+ }
99
+
100
+ /**
101
+ * Select an icon provider URL without interpolating/coercing a custom value.
102
+ * @param {Object} providers Provider configuration.
103
+ * @returns {*} The known URL or original custom value.
104
+ */
105
+ function resolveIconCdn(providers) {
106
+ let {
107
+ iconcdn = 'fontawesome'
108
+ } = providers;
109
+ if (iconcdn in PROVIDERS.ICON) iconcdn = PROVIDERS.ICON[iconcdn];
110
+ return iconcdn;
111
+ }
112
+ module.exports = {
113
+ resolveCdn,
114
+ resolveFontCdn,
115
+ resolveIconCdn
116
+ };