hexo-theme-stellar 1.44.0 → 2.0.0-rc.2

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 (377) hide show
  1. package/CHANGELOG.md +63 -5
  2. package/CONTRIBUTING.md +29 -120
  3. package/README.md +66 -73
  4. package/README_EN.md +66 -73
  5. package/_config.yml +890 -743
  6. package/_data/icons.yml +43 -171
  7. package/_data/widgets.yml +1 -1
  8. package/assets/icon-v2-x512.webp +0 -0
  9. package/languages/en.yml +59 -2
  10. package/languages/zh-CN.yml +59 -2
  11. package/languages/zh-TW.yml +59 -2
  12. package/layout/404.ejs +7 -4
  13. package/layout/_partial/comments/artalk/layout.ejs +3 -2
  14. package/layout/_partial/comments/beaudar/layout.ejs +2 -2
  15. package/layout/_partial/comments/giscus/layout.ejs +2 -5
  16. package/layout/_partial/comments/layout.ejs +11 -40
  17. package/layout/_partial/comments/twikoo/layout.ejs +3 -2
  18. package/layout/_partial/comments/utterances/layout.ejs +2 -2
  19. package/layout/_partial/comments/waline/layout.ejs +3 -2
  20. package/layout/_partial/components/collection-item.ejs +30 -13
  21. package/layout/_partial/components/collection.ejs +2 -2
  22. package/layout/_partial/cover/index.ejs +5 -2
  23. package/layout/_partial/cover/wiki_cover.ejs +39 -28
  24. package/layout/_partial/dropdown.ejs +26 -14
  25. package/layout/_partial/head.ejs +96 -69
  26. package/layout/_partial/main/article/contributors.ejs +12 -9
  27. package/layout/_partial/main/article/post_footer.ejs +47 -0
  28. package/layout/_partial/main/article/post_read_next.ejs +22 -0
  29. package/layout/_partial/main/article/post_related.ejs +14 -0
  30. package/layout/_partial/main/article/post_tags.ejs +12 -0
  31. package/layout/_partial/main/article/share.ejs +55 -0
  32. package/layout/_partial/main/footer.ejs +11 -10
  33. package/layout/_partial/main/{navbar/nav_tabs_blog.ejs → listing_nav/blog.ejs} +21 -18
  34. package/layout/_partial/main/listing_nav/wiki.ejs +56 -0
  35. package/layout/_partial/main/navbar/article_banner.ejs +39 -35
  36. package/layout/_partial/main/navbar/breadcrumb/blog.ejs +15 -28
  37. package/layout/_partial/main/navbar/breadcrumb/note.ejs +12 -5
  38. package/layout/_partial/main/navbar/breadcrumb/wiki.ejs +15 -11
  39. package/layout/_partial/main/navbar/dateinfo.ejs +28 -12
  40. package/layout/_partial/main/navbar/ghinfo.ejs +5 -3
  41. package/layout/_partial/main/notebook/note_card.ejs +12 -17
  42. package/layout/_partial/main/notebook/note_tags.ejs +3 -4
  43. package/layout/_partial/main/notebook/notebook_card.ejs +11 -4
  44. package/layout/_partial/main/pin_slider.ejs +48 -43
  45. package/layout/_partial/main/post_list/archive_item.ejs +8 -4
  46. package/layout/_partial/main/post_list/latest_post_card.ejs +10 -4
  47. package/layout/_partial/main/post_list/post_card.ejs +39 -90
  48. package/layout/_partial/main/post_list/topic_card.ejs +7 -5
  49. package/layout/_partial/main/post_list/wiki_card.ejs +16 -13
  50. package/layout/_partial/menubtn.ejs +3 -3
  51. package/layout/_partial/primitives/item.ejs +8 -0
  52. package/layout/_partial/primitives/navigation.ejs +17 -0
  53. package/layout/_partial/primitives/region.ejs +16 -0
  54. package/layout/_partial/primitives/section.ejs +8 -0
  55. package/layout/_partial/primitives/shell.ejs +35 -0
  56. package/layout/_partial/regions/widgets.ejs +84 -0
  57. package/layout/_partial/scripts/defines.ejs +46 -76
  58. package/layout/_partial/scripts/runtime.ejs +55 -0
  59. package/layout/_partial/scripts.ejs +18 -42
  60. package/layout/_partial/search/dialog.ejs +33 -0
  61. package/layout/_partial/search/shortcut.ejs +1 -0
  62. package/layout/_partial/sidebar/brand.ejs +127 -0
  63. package/layout/_partial/sidebar/menu.ejs +59 -14
  64. package/layout/_partial/sidebar/search.ejs +58 -41
  65. package/layout/_partial/widgets/actions.ejs +25 -0
  66. package/layout/_partial/widgets/author.ejs +9 -5
  67. package/layout/_partial/widgets/components/linklist.ejs +1 -2
  68. package/layout/_partial/widgets/ghissues.ejs +7 -10
  69. package/layout/_partial/widgets/ghrepo.ejs +23 -16
  70. package/layout/_partial/widgets/ghuser.ejs +3 -3
  71. package/layout/_partial/widgets/recent.ejs +25 -21
  72. package/layout/_partial/widgets/related.ejs +25 -34
  73. package/layout/_partial/widgets/settings.ejs +17 -0
  74. package/layout/_partial/widgets/tagtree.ejs +18 -10
  75. package/layout/_partial/widgets/toc.ejs +17 -9
  76. package/layout/_partial/widgets/tree.ejs +12 -13
  77. package/layout/archive.ejs +20 -13
  78. package/layout/categories.ejs +4 -3
  79. package/layout/collection-preview.ejs +8 -9
  80. package/layout/index.ejs +32 -43
  81. package/layout/index_topic.ejs +6 -13
  82. package/layout/index_wiki.ejs +17 -34
  83. package/layout/layout.ejs +195 -65
  84. package/layout/notebooks.ejs +3 -3
  85. package/layout/notes.ejs +4 -4
  86. package/layout/page.ejs +95 -50
  87. package/layout/settings.ejs +109 -0
  88. package/layout/tags.ejs +4 -3
  89. package/{THIRD-PARTY-NOTICES.md → legal/THIRD-PARTY-NOTICES.md} +8 -4
  90. package/package.json +28 -6
  91. package/scripts/commands/stellar.js +55 -0
  92. package/scripts/events/index.js +15 -9
  93. package/scripts/events/lib/authors.js +9 -7
  94. package/scripts/events/lib/config-hot-reload.js +65 -0
  95. package/scripts/events/lib/config-schema.js +20 -0
  96. package/scripts/events/lib/config.js +22 -63
  97. package/scripts/events/lib/content-config.js +5 -0
  98. package/scripts/events/lib/doc_tree.js +99 -9
  99. package/scripts/events/lib/links.js +6 -3
  100. package/scripts/events/lib/notebooks.js +200 -8
  101. package/scripts/events/lib/utils.js +4 -4
  102. package/scripts/events/lib/version-check.js +57 -3
  103. package/scripts/filters/index.js +2 -27
  104. package/scripts/filters/lib/img_lazyload.js +4 -126
  105. package/scripts/filters/lib/img_onerror.js +14 -17
  106. package/scripts/filters/lib/page-view-model.js +152 -0
  107. package/scripts/generators/404.js +13 -8
  108. package/scripts/generators/author.js +16 -11
  109. package/scripts/generators/notebooks.js +68 -39
  110. package/scripts/generators/search.js +62 -67
  111. package/scripts/generators/settings.js +43 -0
  112. package/scripts/generators/stellar-icons.js +13 -5
  113. package/scripts/generators/topic.js +24 -13
  114. package/scripts/generators/wiki.js +49 -21
  115. package/scripts/helpers/ai_label.js +6 -12
  116. package/scripts/helpers/brand.js +17 -0
  117. package/scripts/helpers/browser_runtime_manifest.js +12 -0
  118. package/scripts/helpers/caption.js +8 -0
  119. package/scripts/helpers/category_color.js +13 -13
  120. package/scripts/helpers/collection.js +18 -0
  121. package/scripts/helpers/comments_model.js +14 -0
  122. package/scripts/helpers/extension_assets.js +8 -0
  123. package/scripts/helpers/json_ld.js +16 -7
  124. package/scripts/helpers/mdrender.js +3 -9
  125. package/scripts/helpers/menu.js +9 -0
  126. package/scripts/helpers/post_view_model.js +23 -0
  127. package/scripts/helpers/regions.js +37 -0
  128. package/scripts/helpers/scrollreveal.js +7 -7
  129. package/scripts/helpers/search_domain.js +34 -0
  130. package/scripts/helpers/service_provider.js +9 -0
  131. package/scripts/helpers/settings.js +16 -0
  132. package/scripts/helpers/share_action.js +8 -0
  133. package/scripts/helpers/stellar_config.js +12 -0
  134. package/scripts/helpers/stellar_data.js +8 -0
  135. package/scripts/helpers/stellar_info.js +21 -16
  136. package/scripts/helpers/stellar_inject.js +9 -0
  137. package/scripts/helpers/ui_classes.js +12 -0
  138. package/scripts/lib/ai_label.js +14 -11
  139. package/scripts/lib/brand.js +41 -0
  140. package/scripts/lib/browser-runtime.js +115 -0
  141. package/scripts/lib/caption.js +21 -0
  142. package/scripts/lib/collection-pipeline/adapters/notebook.js +62 -0
  143. package/scripts/lib/collection-pipeline/adapters/post.js +20 -0
  144. package/scripts/lib/collection-pipeline/adapters/topic.js +82 -0
  145. package/scripts/lib/collection-pipeline/adapters/wiki.js +20 -0
  146. package/scripts/lib/collection-pipeline/index.js +169 -0
  147. package/scripts/lib/collection-pipeline/registry.js +27 -0
  148. package/scripts/lib/collection-pipeline/shared.js +164 -0
  149. package/scripts/lib/comments.js +60 -0
  150. package/scripts/lib/config-inject.js +20 -0
  151. package/scripts/lib/config-schema.js +1095 -0
  152. package/scripts/lib/content-config.js +157 -0
  153. package/scripts/lib/content-defaults.js +56 -0
  154. package/scripts/lib/content-membership.js +233 -0
  155. package/scripts/lib/contribution-contract.js +165 -0
  156. package/scripts/lib/contribution-registry.js +429 -0
  157. package/scripts/lib/doc_tree.js +46 -44
  158. package/scripts/lib/doctor.js +296 -0
  159. package/scripts/lib/front-matter.js +29 -0
  160. package/scripts/lib/hero-effect-registry.js +262 -0
  161. package/scripts/lib/html-images.js +128 -0
  162. package/scripts/lib/internal-constants.js +152 -0
  163. package/scripts/lib/layout-config.js +62 -0
  164. package/scripts/lib/mdrender_html.js +36 -23
  165. package/scripts/lib/menu.js +36 -0
  166. package/scripts/lib/model-schema.js +90 -0
  167. package/scripts/lib/models/index.js +1542 -0
  168. package/scripts/lib/new-note.js +172 -0
  169. package/scripts/lib/page-view-model-registry.js +103 -0
  170. package/scripts/lib/regions.js +132 -0
  171. package/scripts/lib/runtime-data.js +23 -0
  172. package/scripts/lib/safe-path.js +44 -0
  173. package/scripts/lib/search-domain.js +59 -0
  174. package/scripts/lib/seo.js +10 -10
  175. package/scripts/lib/service-provider.js +12 -0
  176. package/scripts/lib/settings.js +16 -0
  177. package/scripts/lib/share-services.js +96 -0
  178. package/scripts/lib/source-config.js +27 -0
  179. package/scripts/lib/theme-metadata.js +22 -0
  180. package/scripts/lib/ui-capabilities.js +32 -0
  181. package/scripts/lib/widget-registry.js +150 -0
  182. package/scripts/lib/wiki_readme.js +15 -11
  183. package/scripts/schema/config-rules.js +290 -0
  184. package/scripts/schema/config-schema.js +163 -0
  185. package/scripts/schema/content-config-rules.js +264 -0
  186. package/scripts/schema/content-config-schema.js +321 -0
  187. package/scripts/schema/model-schema.js +971 -0
  188. package/scripts/schema/schema-utils.js +48 -0
  189. package/scripts/tags/index.js +2 -3
  190. package/scripts/tags/lib/albums.js +6 -6
  191. package/scripts/tags/lib/banner.js +10 -4
  192. package/scripts/tags/lib/box.js +1 -1
  193. package/scripts/tags/lib/button.js +1 -1
  194. package/scripts/tags/lib/chat.js +9 -31
  195. package/scripts/tags/lib/checkbox.js +6 -1
  196. package/scripts/tags/lib/copy.js +4 -1
  197. package/scripts/tags/lib/dropdown.js +6 -4
  198. package/scripts/tags/lib/emoji.js +5 -10
  199. package/scripts/tags/lib/friends.js +4 -4
  200. package/scripts/tags/lib/gallery.js +7 -7
  201. package/scripts/tags/lib/ghcard.js +5 -3
  202. package/scripts/tags/lib/gist.js +16 -0
  203. package/scripts/tags/lib/grid.js +4 -2
  204. package/scripts/tags/lib/hashtag.js +1 -1
  205. package/scripts/tags/lib/icon.js +1 -1
  206. package/scripts/tags/lib/image.js +1 -1
  207. package/scripts/tags/lib/link.js +6 -3
  208. package/scripts/tags/lib/mark.js +8 -3
  209. package/scripts/tags/lib/md.js +1 -1
  210. package/scripts/tags/lib/note.js +1 -1
  211. package/scripts/tags/lib/okr.js +18 -1
  212. package/scripts/tags/lib/posters.js +6 -6
  213. package/scripts/tags/lib/quot.js +15 -5
  214. package/scripts/tags/lib/rating.js +7 -4
  215. package/scripts/tags/lib/sites.js +8 -6
  216. package/scripts/tags/lib/tip.js +6 -6
  217. package/scripts/tags/lib/toc.js +2 -2
  218. package/scripts/tags/lib/vote.js +8 -5
  219. package/source/css/_appearances/_mixins.styl +258 -0
  220. package/source/css/_appearances/card.styl +30 -0
  221. package/source/css/_appearances/flat.styl +44 -0
  222. package/source/css/_appearances/glass.styl +138 -0
  223. package/source/css/_appearances/minimal.styl +325 -0
  224. package/source/css/_common/base.styl +5 -9
  225. package/source/css/_common/blockquote.styl +0 -1
  226. package/source/css/_common/button.styl +1 -1
  227. package/source/css/_common/device.styl +24 -42
  228. package/source/css/_common/dropdown.styl +20 -14
  229. package/source/css/_common/highlight.styl +5 -12
  230. package/source/css/_common/icon.styl +38 -0
  231. package/source/css/_common/input.styl +33 -0
  232. package/source/css/_common/loading.styl +2 -2
  233. package/source/css/_common/svg.styl +0 -8
  234. package/source/css/_components/collection.styl +21 -64
  235. package/source/css/_components/layout.styl +524 -84
  236. package/source/css/_components/list.styl +36 -22
  237. package/source/css/_components/main.styl +16 -19
  238. package/source/css/_components/md.styl +8 -13
  239. package/source/css/_components/pages/article-indent.styl +1 -1
  240. package/source/css/_components/pages/article-story.styl +7 -6
  241. package/source/css/_components/pages/article-tech.styl +5 -5
  242. package/source/css/_components/pages/collection-preview.styl +1 -5
  243. package/source/css/_components/pages/settings.styl +184 -0
  244. package/source/css/_components/partial/article-banner.styl +2 -2
  245. package/source/css/_components/partial/article-footer.styl +0 -32
  246. package/source/css/_components/partial/article-share.styl +48 -0
  247. package/source/css/_components/partial/article-tags.styl +1 -1
  248. package/source/css/_components/partial/cover.styl +13 -13
  249. package/source/css/_components/partial/listing-nav.styl +68 -0
  250. package/source/css/_components/partial/paginator.styl +1 -1
  251. package/source/css/_components/pin-slider.styl +3 -3
  252. package/source/css/_components/sidebar/brand.styl +135 -0
  253. package/source/css/_components/sidebar/footer.styl +14 -31
  254. package/source/css/_components/sidebar/nav-area.styl +4 -0
  255. package/source/css/_components/sidebar/search.styl +176 -26
  256. package/source/css/_components/sidebar/sidebar.styl +76 -110
  257. package/source/css/_components/tag-plugins/banner.styl +16 -28
  258. package/source/css/_components/tag-plugins/checkbox.styl +7 -22
  259. package/source/css/_components/tag-plugins/copy.styl +3 -5
  260. package/source/css/_components/tag-plugins/gallery.styl +2 -2
  261. package/source/css/_components/tag-plugins/grid.styl +3 -0
  262. package/source/css/_components/tag-plugins/image.styl +2 -1
  263. package/source/css/_components/tag-plugins/link.styl +0 -1
  264. package/source/css/_components/tag-plugins/mark.styl +19 -4
  265. package/source/css/_components/tag-plugins/mdrender.styl +2 -2
  266. package/source/css/_components/tag-plugins/navbar.styl +23 -17
  267. package/source/css/_components/tag-plugins/note.styl +2 -2
  268. package/source/css/_components/tag-plugins/okr.styl +1 -2
  269. package/source/css/_components/tag-plugins/quot.styl +5 -0
  270. package/source/css/_components/tag-plugins/rating.styl +3 -2
  271. package/source/css/_components/tag-plugins/timeline.styl +1 -1
  272. package/source/css/_components/tag-plugins/tip.styl +1 -1
  273. package/source/css/_components/tag-plugins/vote.styl +3 -2
  274. package/source/css/_components/widgets/ghrepo.styl +2 -1
  275. package/source/css/_components/widgets/ghuser.styl +4 -6
  276. package/source/css/_components/widgets/settings.styl +49 -0
  277. package/source/css/_components/widgets/timeline.styl +2 -2
  278. package/source/css/_components/widgets/toc.styl +12 -33
  279. package/source/css/_components/widgets/widgets.styl +14 -19
  280. package/source/css/_components/wiki-card.styl +2 -2
  281. package/source/css/_custom.styl +26 -32
  282. package/source/css/_defines/func.styl +47 -37
  283. package/source/css/_defines/theme_base.styl +8 -10
  284. package/source/css/_plugins/card-hover.styl +1 -1
  285. package/source/css/_plugins/copycode.styl +16 -19
  286. package/source/css/_plugins/index.styl +3 -8
  287. package/source/css/_plugins/lazyload.styl +1 -1
  288. package/source/css/main.styl +12 -0
  289. package/source/js/main.js +302 -59
  290. package/source/js/plugins/adaptive-text.js +33 -16
  291. package/source/js/plugins/card-hover.js +2 -24
  292. package/source/js/plugins/copycode.js +10 -16
  293. package/source/js/plugins/voice.js +51 -48
  294. package/source/js/profile.js +316 -0
  295. package/source/js/runtime/asset-loader.js +61 -0
  296. package/source/js/runtime/extension-registry.js +149 -0
  297. package/source/js/runtime/extensions/card-hover.js +5 -0
  298. package/source/js/runtime/extensions/color-scheme-switch.js +101 -0
  299. package/source/js/runtime/extensions/comments.js +200 -0
  300. package/source/js/runtime/extensions/deferred-icons.js +53 -0
  301. package/source/js/{plugins → runtime/extensions}/dropdown.js +69 -30
  302. package/source/js/runtime/extensions/feature.js +200 -0
  303. package/source/js/runtime/extensions/hero-effect.js +179 -0
  304. package/source/js/runtime/extensions/reveal.js +80 -0
  305. package/source/js/runtime/extensions/search.js +23 -0
  306. package/source/js/{services.js → runtime/extensions/services.js} +67 -54
  307. package/source/js/runtime/extensions/settings.js +235 -0
  308. package/source/js/runtime/hero-effects/ferrofluid.js +385 -0
  309. package/source/js/{plugins → runtime/hero-effects}/galaxy.js +53 -177
  310. package/source/js/runtime/hero-effects/light-rays.js +293 -0
  311. package/source/js/runtime/index.js +75 -0
  312. package/source/js/runtime/legacy-request-adapter.js +47 -0
  313. package/source/js/runtime/request-cache.js +219 -0
  314. package/source/js/search/algolia-search.js +76 -51
  315. package/source/js/search/highlight.js +1 -1
  316. package/source/js/search/local-search.js +96 -57
  317. package/source/js/search/shortcut.js +31 -20
  318. package/source/js/services/friends_and_posts.js +6 -1
  319. package/source/js/services/rating.js +14 -6
  320. package/source/js/services/siteinfo.js +3 -7
  321. package/source/js/services/timeline.js +1 -1
  322. package/source/js/services/vote.js +7 -5
  323. package/source/js/services/weibo.js +1 -1
  324. package/source/js/utils.js +19 -444
  325. package/.claude/skills/stellar-theme-dev/SKILL.md +0 -51
  326. package/_data/chat_users.yml +0 -0
  327. package/layout/_partial/comments/artalk/script.ejs +0 -76
  328. package/layout/_partial/comments/beaudar/script.ejs +0 -33
  329. package/layout/_partial/comments/giscus/script.ejs +0 -31
  330. package/layout/_partial/comments/script.ejs +0 -3
  331. package/layout/_partial/comments/twikoo/script.ejs +0 -25
  332. package/layout/_partial/comments/utterances/script.ejs +0 -33
  333. package/layout/_partial/comments/waline/script.ejs +0 -43
  334. package/layout/_partial/main/article/article_footer.ejs +0 -164
  335. package/layout/_partial/main/article/article_tags.ejs +0 -16
  336. package/layout/_partial/main/article/read_next.ejs +0 -63
  337. package/layout/_partial/main/article/related_posts.ejs +0 -16
  338. package/layout/_partial/main/navbar/nav_tabs_wiki.ejs +0 -52
  339. package/layout/_partial/scripts/bootstrap.ejs +0 -37
  340. package/layout/_partial/scripts/lazyload.ejs +0 -89
  341. package/layout/_partial/sidebar/grad-def.ejs +0 -26
  342. package/layout/_partial/sidebar/index_leftbar.ejs +0 -191
  343. package/layout/_partial/sidebar/index_rightbar.ejs +0 -94
  344. package/layout/_partial/sidebar/logo.ejs +0 -99
  345. package/layout/_plugins/adaptive_text.ejs +0 -11
  346. package/layout/_plugins/card_hover.ejs +0 -32
  347. package/layout/_plugins/copycode.ejs +0 -17
  348. package/layout/_plugins/fancybox.ejs +0 -53
  349. package/layout/_plugins/heti.ejs +0 -21
  350. package/layout/_plugins/index.ejs +0 -50
  351. package/layout/_plugins/mathjax.ejs +0 -49
  352. package/layout/_plugins/mermaid.ejs +0 -33
  353. package/layout/_plugins/preload.ejs +0 -9
  354. package/layout/_plugins/scrollreveal.ejs +0 -102
  355. package/layout/_plugins/search/algolia_search.ejs +0 -12
  356. package/layout/_plugins/search/local_search.ejs +0 -9
  357. package/layout/_plugins/swiper.ejs +0 -27
  358. package/layout/_plugins/tianli_gpt.ejs +0 -14
  359. package/scripts/commands/new-note.js +0 -49
  360. package/scripts/events/lib/merge_posts.js +0 -48
  361. package/scripts/events/lib/topic_tree.js +0 -48
  362. package/scripts/helpers/related_posts.js +0 -51
  363. package/scripts/helpers/subtitle.js +0 -8
  364. package/scripts/lib/notebooks.js +0 -181
  365. package/scripts/lib/subtitle.js +0 -28
  366. package/scripts/tags/lib/about.js +0 -48
  367. package/source/css/_components/page-transition.styl +0 -22
  368. package/source/css/_components/partial/navbar.styl +0 -51
  369. package/source/css/_components/sidebar/logo.styl +0 -111
  370. package/source/css/_components/tag-plugins/about.styl +0 -56
  371. package/source/css/_components/widgets/tree.styl +0 -0
  372. package/source/css/_plugins/scrollreveal.styl +0 -6
  373. package/source/css/_plugins/tianli_gpt.styl +0 -213
  374. package/source/css/plugins/mermaid.styl +0 -137
  375. package/source/js/icons.js +0 -60
  376. package/source/js/services/fcircle.js +0 -35
  377. package/source/js/theme.js +0 -61
@@ -0,0 +1,296 @@
1
+ /* global hexo */
2
+ "use strict";
3
+
4
+ const fs = require("node:fs");
5
+ const path = require("node:path");
6
+ const yaml = require("js-yaml");
7
+
8
+ const { ConfigSchemaError, deepFreeze, parseStellarConfig } = require("./config-schema");
9
+ const {
10
+ ContentConfigError,
11
+ parseCollectionConfig,
12
+ parsePageConfig,
13
+ validateCollectionProfileConfig,
14
+ validatePageProfileConfig
15
+ } = require("./content-config");
16
+ const { getProfileAdapter } = require("./collection-pipeline/registry");
17
+ const {
18
+ createCollectionRegistry,
19
+ resolveContentMembership,
20
+ sourcePagePath
21
+ } = require("./content-membership");
22
+ const { FrontMatterParseError, parseFrontMatterYaml } = require("./front-matter");
23
+ const { resolveRegions } = require("./regions");
24
+
25
+ function issue(code, source, fieldPath, actualType, expected, migration) {
26
+ return Object.freeze({ code, source, path: fieldPath, actualType, expected, migration });
27
+ }
28
+
29
+ function relative(baseDir, file) {
30
+ return path.relative(baseDir, file).replace(/\\/g, "/") || ".";
31
+ }
32
+
33
+ function major(version) {
34
+ const match = String(version || "").match(/^(?:v)?(\d+)/);
35
+ return match ? Number(match[1]) : null;
36
+ }
37
+
38
+ function yamlValue(file, source, issues) {
39
+ try {
40
+ return yaml.load(fs.readFileSync(file, "utf8"), { filename: source }) || {};
41
+ } catch (error) {
42
+ issues.push(issue("invalid_yaml", source, "root", "invalid YAML", "valid YAML document", "configuration/v2"));
43
+ return null;
44
+ }
45
+ }
46
+
47
+ function frontMatterValue(file, source, issues) {
48
+ const content = fs.readFileSync(file, "utf8");
49
+ try {
50
+ return parseFrontMatterYaml(content, source);
51
+ } catch (error) {
52
+ if (!(error instanceof FrontMatterParseError)) throw error;
53
+ const actualType = error.kind === "unterminated" ? "unterminated front matter" : "invalid YAML";
54
+ issues.push(issue("invalid_yaml", source, "root", actualType, "valid YAML front matter", "content-schema/front-matter"));
55
+ return null;
56
+ }
57
+ }
58
+
59
+ function filesBelow(root, predicate) {
60
+ if (!fs.existsSync(root)) return [];
61
+ const result = [];
62
+ const visit = directory => {
63
+ for (const entry of fs.readdirSync(directory, { withFileTypes: true }).sort((left, right) => left.name.localeCompare(right.name))) {
64
+ const file = path.join(directory, entry.name);
65
+ if (entry.isDirectory()) visit(file);
66
+ else if (entry.isFile() && predicate(file)) result.push(file);
67
+ }
68
+ };
69
+ visit(root);
70
+ return result;
71
+ }
72
+
73
+ function collectSchemaIssues(callback, issues) {
74
+ try {
75
+ return callback();
76
+ } catch (error) {
77
+ if (!(error instanceof ConfigSchemaError) && !(error instanceof ContentConfigError)) throw error;
78
+ issues.push(...error.issues);
79
+ return null;
80
+ }
81
+ }
82
+
83
+ function widgetCatalog(baseDir) {
84
+ const themeFile = path.resolve(__dirname, "../../_data/widgets.yml");
85
+ const siteFile = path.join(baseDir, "source/_data/widgets.yml");
86
+ const theme = yaml.load(fs.readFileSync(themeFile, "utf8"), { filename: themeFile }) || {};
87
+ if (!fs.existsSync(siteFile)) return theme;
88
+ const site = yaml.load(fs.readFileSync(siteFile, "utf8"), { filename: siteFile }) || {};
89
+ const result = { ...theme };
90
+ for (const [id, descriptor] of Object.entries(site)) {
91
+ if (descriptor == null || descriptor.length === 0) delete result[id];
92
+ else result[id] = { ...(result[id] || {}), ...descriptor };
93
+ }
94
+ return result;
95
+ }
96
+
97
+ function placementWarnings(options) {
98
+ const resolved = resolveRegions({
99
+ profile: options.profile,
100
+ defaultState: options.defaultState,
101
+ catalog: options.catalog,
102
+ layers: options.layers
103
+ });
104
+ return resolved.warnings.map(warning => Object.freeze({
105
+ code: warning.code,
106
+ severity: "warning",
107
+ source: options.source,
108
+ path: `layout=${options.profile}; region=${warning.region}`,
109
+ widget: warning.widget,
110
+ layout: warning.layout,
111
+ region: warning.region,
112
+ supported: warning.supported
113
+ }));
114
+ }
115
+
116
+ function runDoctor(options = {}) {
117
+ const baseDir = path.resolve(options.baseDir || process.cwd());
118
+ const nodeVersion = String(options.nodeVersion || process.versions.node);
119
+ const hexoVersion = String(options.hexoVersion || "");
120
+ const issues = [];
121
+ const warnings = [];
122
+ const catalog = widgetCatalog(baseDir);
123
+
124
+ if (major(nodeVersion) == null || major(nodeVersion) < 22) {
125
+ issues.push(issue("unsupported_version", "environment", "node", `string:${nodeVersion || "unknown"}`, "Node.js >= 22", "start/requirements"));
126
+ }
127
+ if (major(hexoVersion) == null || major(hexoVersion) < 8) {
128
+ issues.push(issue("unsupported_version", "environment", "hexo", `string:${hexoVersion || "unknown"}`, "Hexo >= 8", "start/requirements"));
129
+ }
130
+
131
+ const siteConfigPath = path.join(baseDir, "_config.yml");
132
+ let siteConfig = {};
133
+ if (!fs.existsSync(siteConfigPath)) {
134
+ issues.push(issue("missing_file", "_config.yml", "root", "missing", "Hexo site config", "start/install"));
135
+ } else {
136
+ siteConfig = yamlValue(siteConfigPath, "_config.yml", issues) || {};
137
+ if (siteConfig.theme !== "stellar") {
138
+ issues.push(issue("invalid_value", "_config.yml", "theme", typeof siteConfig.theme, "stellar", "start/install"));
139
+ }
140
+ }
141
+
142
+ const stellarConfigPath = path.join(baseDir, "_config.stellar.yml");
143
+ let stellarConfig = null;
144
+ if (fs.existsSync(stellarConfigPath)) {
145
+ const value = yamlValue(stellarConfigPath, "_config.stellar.yml", issues);
146
+ if (value != null) stellarConfig = collectSchemaIssues(() => parseStellarConfig({
147
+ source: "_config.stellar.yml",
148
+ themeConfig: value,
149
+ siteConfig
150
+ }), issues);
151
+ } else {
152
+ stellarConfig = collectSchemaIssues(() => parseStellarConfig({
153
+ source: "Stellar Schema defaults",
154
+ themeConfig: {},
155
+ siteConfig
156
+ }), issues);
157
+ }
158
+
159
+ if (stellarConfig) {
160
+ for (const [profile, profileConfig] of Object.entries(stellarConfig.profiles)) {
161
+ warnings.push(...placementWarnings({
162
+ profile,
163
+ source: fs.existsSync(stellarConfigPath) ? "_config.stellar.yml" : "Stellar Schema defaults",
164
+ catalog,
165
+ defaultState: stellarConfig.leftbar.defaultState,
166
+ layers: [stellarConfig, profileConfig]
167
+ }));
168
+ }
169
+ }
170
+
171
+ const collectionConfigs = new Map();
172
+ for (const collectionRoot of ["wiki", "topic", "notebooks"]) {
173
+ const directory = path.join(baseDir, "source", "_data", collectionRoot);
174
+ for (const file of filesBelow(directory, item => /\.ya?ml$/i.test(item))) {
175
+ const source = relative(baseDir, file);
176
+ const value = yamlValue(file, source, issues);
177
+ if (value != null) {
178
+ const contentProfile = collectionRoot === "notebooks" ? "notebook" : collectionRoot;
179
+ const parsed = collectSchemaIssues(() => {
180
+ const config = parseCollectionConfig(value, source);
181
+ return validateCollectionProfileConfig(config, source, contentProfile, getProfileAdapter(contentProfile).config);
182
+ }, issues);
183
+ if (parsed != null) {
184
+ const key = relative(path.join(baseDir, "source", "_data"), file).replace(/\.ya?ml$/i, "");
185
+ collectionConfigs.set(key, parsed);
186
+ const profile = collectionRoot === "notebooks" ? "note" : collectionRoot;
187
+ if (stellarConfig) warnings.push(...placementWarnings({
188
+ profile,
189
+ source,
190
+ catalog,
191
+ defaultState: stellarConfig.leftbar.defaultState,
192
+ layers: [
193
+ stellarConfig,
194
+ stellarConfig.profiles[profile],
195
+ parsed
196
+ ]
197
+ }));
198
+ }
199
+ }
200
+ }
201
+ }
202
+
203
+ const membershipRegistry = createCollectionRegistry(collectionConfigs);
204
+ const sourceRoot = path.join(baseDir, "source");
205
+ for (const file of filesBelow(sourceRoot, item => item.endsWith(".md"))) {
206
+ const source = relative(baseDir, file);
207
+ const value = frontMatterValue(file, source, issues);
208
+ if (value != null) {
209
+ const parsed = collectSchemaIssues(() => parsePageConfig(value, source), issues);
210
+ if (parsed == null) continue;
211
+ const resolved = resolveContentMembership({
212
+ kind: source.startsWith("source/_posts/") ? "posts" : "pages",
213
+ source,
214
+ pagePath: parsed.permalink || sourcePagePath(source),
215
+ config: parsed,
216
+ registry: membershipRegistry
217
+ });
218
+ issues.push(...resolved.issues);
219
+ const finalConfig = resolved.config || parsed;
220
+ const profile = finalConfig.collection?.profile
221
+ || (source.startsWith("source/_posts/") ? "post" : (parsed.layout || "page"));
222
+ const contentProfile = finalConfig.collection?.profile
223
+ || (source.startsWith("source/_posts/") ? "post" : "page");
224
+ collectSchemaIssues(() => validatePageProfileConfig(
225
+ finalConfig,
226
+ source,
227
+ contentProfile,
228
+ contentProfile === "page" ? null : getProfileAdapter(contentProfile).config
229
+ ), issues);
230
+ const collectionKey = finalConfig.collection
231
+ ? `${finalConfig.collection.profile === "notebook" ? "notebooks" : finalConfig.collection.profile}/${finalConfig.collection.id}`
232
+ : null;
233
+ const collection = collectionKey ? collectionConfigs.get(collectionKey) : null;
234
+ if (stellarConfig) warnings.push(...placementWarnings({
235
+ profile,
236
+ source,
237
+ catalog,
238
+ defaultState: stellarConfig.leftbar.defaultState,
239
+ layers: [
240
+ stellarConfig,
241
+ stellarConfig.profiles[profile],
242
+ collection,
243
+ finalConfig
244
+ ]
245
+ }));
246
+ }
247
+ }
248
+
249
+ return deepFreeze({
250
+ ok: issues.length === 0,
251
+ environment: {
252
+ node: nodeVersion,
253
+ hexo: hexoVersion,
254
+ baseDir
255
+ },
256
+ checked: {
257
+ themeConfig: fs.existsSync(stellarConfigPath),
258
+ collections: filesBelow(path.join(baseDir, "source", "_data"), item => /\/(wiki|topic|notebooks)\/.*\.ya?ml$/i.test(item)).length,
259
+ pages: filesBelow(sourceRoot, item => item.endsWith(".md")).length
260
+ },
261
+ issues: issues.map(item => Object.freeze({ ...item })),
262
+ warnings
263
+ });
264
+ }
265
+
266
+ function formatDoctorText(result) {
267
+ const lines = [
268
+ `Stellar doctor: ${result.ok ? "PASS" : "FAIL"}`,
269
+ `Node.js: ${result.environment.node}`,
270
+ `Hexo: ${result.environment.hexo}`,
271
+ `Checked: ${result.checked.themeConfig ? "theme config" : "Schema defaults"}, ${result.checked.collections} collection file(s), ${result.checked.pages} Markdown file(s)`
272
+ ];
273
+ if (result.issues.length > 0) {
274
+ lines.push(`Issues (${result.issues.length}):`);
275
+ for (const item of result.issues) {
276
+ lines.push(`- ${item.source}: ${item.path}; actual=${item.actualType}; expected=${item.expected}; migration=${item.migration}`);
277
+ }
278
+ }
279
+ if (result.warnings.length > 0) {
280
+ lines.push(`Warnings (${result.warnings.length}):`);
281
+ for (const item of result.warnings) {
282
+ lines.push(`- ${item.source}: Widget ${item.widget} (layout=${item.layout}) does not support ${item.region}; supported=${item.supported.join(",") || "none"}; skipped`);
283
+ }
284
+ }
285
+ return lines.join("\n");
286
+ }
287
+
288
+ function formatDoctorJson(result) {
289
+ return JSON.stringify(result, null, 2);
290
+ }
291
+
292
+ module.exports = {
293
+ formatDoctorJson,
294
+ formatDoctorText,
295
+ runDoctor
296
+ };
@@ -0,0 +1,29 @@
1
+ /* global hexo */
2
+ "use strict";
3
+
4
+ const yaml = require("js-yaml");
5
+
6
+ class FrontMatterParseError extends Error {
7
+ constructor(kind, source, message) {
8
+ super(`${source}: ${message}`);
9
+ this.name = "FrontMatterParseError";
10
+ this.kind = kind;
11
+ this.source = source;
12
+ }
13
+ }
14
+
15
+ function parseFrontMatterYaml(content, source) {
16
+ if (!/^\uFEFF?---\r?\n/.test(content)) return null;
17
+ const match = content.match(/^\uFEFF?---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/);
18
+ if (!match) throw new FrontMatterParseError("unterminated", source, "Front Matter 缺少结束分隔符");
19
+ try {
20
+ return yaml.load(match[1], { filename: source }) || {};
21
+ } catch (error) {
22
+ throw new FrontMatterParseError("invalid_yaml", source, `Front Matter YAML 无效(${error.message})`);
23
+ }
24
+ }
25
+
26
+ module.exports = {
27
+ FrontMatterParseError,
28
+ parseFrontMatterYaml
29
+ };
@@ -0,0 +1,262 @@
1
+ "use strict";
2
+
3
+ const INTERNAL = require("./internal-constants");
4
+ const OPTION_TYPES = new Set([
5
+ "boolean",
6
+ "enum",
7
+ "hex_color",
8
+ "hex_color_array",
9
+ "nullable_positive_number",
10
+ "nullable_string",
11
+ "number",
12
+ "number_array"
13
+ ]);
14
+
15
+ function deepFreeze(value) {
16
+ if (value == null || typeof value !== "object" || Object.isFrozen(value)) return value;
17
+ Object.values(value).forEach(deepFreeze);
18
+ return Object.freeze(value);
19
+ }
20
+
21
+ function optionMatches(rule, value) {
22
+ if (rule.type === "boolean") return typeof value === "boolean";
23
+ if (rule.type === "number") return typeof value === "number" && Number.isFinite(value);
24
+ if (rule.type === "nullable_positive_number") {
25
+ return value === null || (typeof value === "number" && Number.isFinite(value) && value > 0);
26
+ }
27
+ if (rule.type === "nullable_string") return value === null || (typeof value === "string" && value.trim().length > 0);
28
+ if (rule.type === "number_array") {
29
+ return Array.isArray(value) && value.every(item => typeof item === "number" && Number.isFinite(item));
30
+ }
31
+ if (rule.type === "enum") return typeof value === "string" && rule.values.includes(value);
32
+ if (rule.type === "hex_color") return typeof value === "string" && /^#?[a-f\d]{6}$/i.test(value);
33
+ if (rule.type === "hex_color_array") {
34
+ return Array.isArray(value)
35
+ && value.length >= 1
36
+ && value.length <= 8
37
+ && value.every(item => typeof item === "string" && /^#?[a-f\d]{6}$/i.test(item));
38
+ }
39
+ return false;
40
+ }
41
+
42
+ function defineHeroEffects(definitions) {
43
+ const ids = new Set();
44
+ for (const definition of definitions) {
45
+ if (typeof definition.id !== "string" || !/^[a-z][a-z0-9-]*$/.test(definition.id)) {
46
+ throw new TypeError("[stellar hero effects] id is invalid");
47
+ }
48
+ if (ids.has(definition.id)) throw new TypeError(`[stellar hero effects] duplicate id ${definition.id}`);
49
+ ids.add(definition.id);
50
+ if (typeof definition.label !== "string" || definition.label.length === 0) {
51
+ throw new TypeError(`[stellar hero effects] ${definition.id} label is invalid`);
52
+ }
53
+ if (typeof definition.module !== "string" || !definition.module.startsWith("/js/runtime/hero-effects/") || !definition.module.endsWith(".js")) {
54
+ throw new TypeError(`[stellar hero effects] ${definition.id} module is invalid`);
55
+ }
56
+ if (definition.options == null || typeof definition.options !== "object" || Array.isArray(definition.options)) {
57
+ throw new TypeError(`[stellar hero effects] ${definition.id} options are invalid`);
58
+ }
59
+ if (definition.defaults == null || typeof definition.defaults !== "object" || Array.isArray(definition.defaults)) {
60
+ throw new TypeError(`[stellar hero effects] ${definition.id} defaults are invalid`);
61
+ }
62
+ for (const [key, rule] of Object.entries(definition.options)) {
63
+ if (!rule || !OPTION_TYPES.has(rule.type)) {
64
+ throw new TypeError(`[stellar hero effects] ${definition.id}.${key} option rule is invalid`);
65
+ }
66
+ if (rule.type === "enum" && (!Array.isArray(rule.values) || rule.values.length === 0)) {
67
+ throw new TypeError(`[stellar hero effects] ${definition.id}.${key} enum is empty`);
68
+ }
69
+ if (!Object.prototype.hasOwnProperty.call(definition.defaults, key) || !optionMatches(rule, definition.defaults[key])) {
70
+ throw new TypeError(`[stellar hero effects] ${definition.id}.${key} default is invalid`);
71
+ }
72
+ }
73
+ const unknownDefault = Object.keys(definition.defaults).find(key => !definition.options[key]);
74
+ if (unknownDefault) throw new TypeError(`[stellar hero effects] ${definition.id}.${unknownDefault} default is not declared`);
75
+ if (typeof definition.presentation !== "function") {
76
+ throw new TypeError(`[stellar hero effects] ${definition.id} presentation is invalid`);
77
+ }
78
+ }
79
+ return deepFreeze(definitions.slice());
80
+ }
81
+
82
+ const LIGHT_RAYS_ORIGINS = Object.freeze([
83
+ "top-left",
84
+ "top-center",
85
+ "top-right",
86
+ "left",
87
+ "right",
88
+ "bottom-left",
89
+ "bottom-center",
90
+ "bottom-right"
91
+ ]);
92
+
93
+ const DEFINITIONS = defineHeroEffects([
94
+ {
95
+ id: "galaxy",
96
+ label: "Galaxy",
97
+ module: INTERNAL.assets.heroEffects.galaxy,
98
+ options: {
99
+ focal: { type: "number_array" },
100
+ rotation: { type: "number_array" },
101
+ starSpeed: { type: "number" },
102
+ density: { type: "number" },
103
+ hueShift: { type: "number" },
104
+ disableAnimation: { type: "boolean" },
105
+ speed: { type: "number" },
106
+ mouseInteraction: { type: "boolean" },
107
+ glowIntensity: { type: "number" },
108
+ saturation: { type: "number" },
109
+ mouseRepulsion: { type: "boolean" },
110
+ repulsionStrength: { type: "number" },
111
+ twinkleIntensity: { type: "number" },
112
+ rotationSpeed: { type: "number" },
113
+ autoCenterRepulsion: { type: "number" },
114
+ transparent: { type: "boolean" }
115
+ },
116
+ defaults: {
117
+ focal: [0.5, 0.5],
118
+ rotation: [1, 0],
119
+ starSpeed: 2,
120
+ density: 2,
121
+ hueShift: 140,
122
+ disableAnimation: false,
123
+ speed: 0.5,
124
+ mouseInteraction: true,
125
+ glowIntensity: 0.2,
126
+ saturation: 0.1,
127
+ mouseRepulsion: true,
128
+ twinkleIntensity: 0.1,
129
+ rotationSpeed: 0.1,
130
+ repulsionStrength: 0.1,
131
+ autoCenterRepulsion: 0,
132
+ transparent: true
133
+ },
134
+ presentation() {
135
+ return { background: "#000000" };
136
+ }
137
+ },
138
+ {
139
+ id: "light-rays",
140
+ label: "Light Rays",
141
+ module: INTERNAL.assets.heroEffects.lightRays,
142
+ options: {
143
+ raysOrigin: { type: "enum", values: LIGHT_RAYS_ORIGINS },
144
+ raysColor: { type: "hex_color" },
145
+ raysSpeed: { type: "number" },
146
+ lightSpread: { type: "number" },
147
+ rayLength: { type: "number" },
148
+ pulsating: { type: "boolean" },
149
+ fadeDistance: { type: "number" },
150
+ saturation: { type: "number" },
151
+ followMouse: { type: "boolean" },
152
+ mouseInfluence: { type: "number" },
153
+ noiseAmount: { type: "number" },
154
+ distortion: { type: "number" },
155
+ lightMode: { type: "boolean" }
156
+ },
157
+ defaults: {
158
+ raysOrigin: "top-center",
159
+ raysColor: "#ffffff",
160
+ raysSpeed: 1,
161
+ lightSpread: 0.5,
162
+ rayLength: 3,
163
+ pulsating: false,
164
+ fadeDistance: 1,
165
+ saturation: 1,
166
+ followMouse: true,
167
+ mouseInfluence: 0.1,
168
+ noiseAmount: 0,
169
+ distortion: 0,
170
+ lightMode: false
171
+ },
172
+ presentation(options) {
173
+ return { background: options?.lightMode === true ? "#ffffff" : "#000000" };
174
+ }
175
+ },
176
+ {
177
+ id: "ferrofluid",
178
+ label: "Ferrofluid",
179
+ module: INTERNAL.assets.heroEffects.ferrofluid,
180
+ options: {
181
+ colors: { type: "hex_color_array" },
182
+ backgroundColor: { type: "hex_color" },
183
+ speed: { type: "number" },
184
+ scale: { type: "number" },
185
+ turbulence: { type: "number" },
186
+ fluidity: { type: "number" },
187
+ rimWidth: { type: "number" },
188
+ sharpness: { type: "number" },
189
+ shimmer: { type: "number" },
190
+ glow: { type: "number" },
191
+ flowDirection: { type: "enum", values: ["up", "down", "left", "right"] },
192
+ opacity: { type: "number" },
193
+ mouseInteraction: { type: "boolean" },
194
+ mouseStrength: { type: "number" },
195
+ mouseRadius: { type: "number" },
196
+ mouseDampening: { type: "number" },
197
+ paused: { type: "boolean" },
198
+ dpr: { type: "nullable_positive_number" },
199
+ mixBlendMode: { type: "nullable_string" }
200
+ },
201
+ defaults: {
202
+ colors: ["#ffffff", "#ffffff", "#ffffff"],
203
+ backgroundColor: "#03010A",
204
+ speed: 0.5,
205
+ scale: 1.6,
206
+ turbulence: 1,
207
+ fluidity: 0.1,
208
+ rimWidth: 0.2,
209
+ sharpness: 2.5,
210
+ shimmer: 1.5,
211
+ glow: 2,
212
+ flowDirection: "down",
213
+ opacity: 1,
214
+ mouseInteraction: true,
215
+ mouseStrength: 1,
216
+ mouseRadius: 0.35,
217
+ mouseDampening: 0.15,
218
+ paused: false,
219
+ dpr: null,
220
+ mixBlendMode: null
221
+ },
222
+ presentation(options) {
223
+ const color = typeof options?.backgroundColor === "string" ? options.backgroundColor : "#03010A";
224
+ return { background: color.startsWith("#") ? color : `#${color}` };
225
+ }
226
+ }
227
+ ]);
228
+
229
+ const BY_ID = new Map(DEFINITIONS.map(definition => [definition.id, definition]));
230
+ const HERO_EFFECT_IDS = Object.freeze(DEFINITIONS.map(definition => definition.id));
231
+
232
+ function getHeroEffectDefinition(id) {
233
+ return BY_ID.get(id) || null;
234
+ }
235
+
236
+ function heroEffectDefinitions() {
237
+ return DEFINITIONS.slice();
238
+ }
239
+
240
+ function heroEffectRuntimeConfig() {
241
+ return Object.fromEntries(DEFINITIONS.map(definition => [definition.id, {
242
+ module: definition.module,
243
+ defaults: definition.defaults
244
+ }]));
245
+ }
246
+
247
+ function projectHeroEffect(effect) {
248
+ const definition = getHeroEffectDefinition(effect?.type);
249
+ if (!definition) return effect;
250
+ return {
251
+ ...effect,
252
+ presentation: definition.presentation(effect.options || {})
253
+ };
254
+ }
255
+
256
+ module.exports = {
257
+ HERO_EFFECT_IDS,
258
+ getHeroEffectDefinition,
259
+ heroEffectDefinitions,
260
+ heroEffectRuntimeConfig,
261
+ projectHeroEffect
262
+ };