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.
- package/CHANGELOG.md +63 -5
- package/CONTRIBUTING.md +29 -120
- package/README.md +66 -73
- package/README_EN.md +66 -73
- package/_config.yml +890 -743
- package/_data/icons.yml +43 -171
- package/_data/widgets.yml +1 -1
- package/assets/icon-v2-x512.webp +0 -0
- package/languages/en.yml +59 -2
- package/languages/zh-CN.yml +59 -2
- package/languages/zh-TW.yml +59 -2
- package/layout/404.ejs +7 -4
- package/layout/_partial/comments/artalk/layout.ejs +3 -2
- package/layout/_partial/comments/beaudar/layout.ejs +2 -2
- package/layout/_partial/comments/giscus/layout.ejs +2 -5
- package/layout/_partial/comments/layout.ejs +11 -40
- package/layout/_partial/comments/twikoo/layout.ejs +3 -2
- package/layout/_partial/comments/utterances/layout.ejs +2 -2
- package/layout/_partial/comments/waline/layout.ejs +3 -2
- package/layout/_partial/components/collection-item.ejs +30 -13
- package/layout/_partial/components/collection.ejs +2 -2
- package/layout/_partial/cover/index.ejs +5 -2
- package/layout/_partial/cover/wiki_cover.ejs +39 -28
- package/layout/_partial/dropdown.ejs +26 -14
- package/layout/_partial/head.ejs +96 -69
- package/layout/_partial/main/article/contributors.ejs +12 -9
- package/layout/_partial/main/article/post_footer.ejs +47 -0
- package/layout/_partial/main/article/post_read_next.ejs +22 -0
- package/layout/_partial/main/article/post_related.ejs +14 -0
- package/layout/_partial/main/article/post_tags.ejs +12 -0
- package/layout/_partial/main/article/share.ejs +55 -0
- package/layout/_partial/main/footer.ejs +11 -10
- package/layout/_partial/main/{navbar/nav_tabs_blog.ejs → listing_nav/blog.ejs} +21 -18
- package/layout/_partial/main/listing_nav/wiki.ejs +56 -0
- package/layout/_partial/main/navbar/article_banner.ejs +39 -35
- package/layout/_partial/main/navbar/breadcrumb/blog.ejs +15 -28
- package/layout/_partial/main/navbar/breadcrumb/note.ejs +12 -5
- package/layout/_partial/main/navbar/breadcrumb/wiki.ejs +15 -11
- package/layout/_partial/main/navbar/dateinfo.ejs +28 -12
- package/layout/_partial/main/navbar/ghinfo.ejs +5 -3
- package/layout/_partial/main/notebook/note_card.ejs +12 -17
- package/layout/_partial/main/notebook/note_tags.ejs +3 -4
- package/layout/_partial/main/notebook/notebook_card.ejs +11 -4
- package/layout/_partial/main/pin_slider.ejs +48 -43
- package/layout/_partial/main/post_list/archive_item.ejs +8 -4
- package/layout/_partial/main/post_list/latest_post_card.ejs +10 -4
- package/layout/_partial/main/post_list/post_card.ejs +39 -90
- package/layout/_partial/main/post_list/topic_card.ejs +7 -5
- package/layout/_partial/main/post_list/wiki_card.ejs +16 -13
- package/layout/_partial/menubtn.ejs +3 -3
- package/layout/_partial/primitives/item.ejs +8 -0
- package/layout/_partial/primitives/navigation.ejs +17 -0
- package/layout/_partial/primitives/region.ejs +16 -0
- package/layout/_partial/primitives/section.ejs +8 -0
- package/layout/_partial/primitives/shell.ejs +35 -0
- package/layout/_partial/regions/widgets.ejs +84 -0
- package/layout/_partial/scripts/defines.ejs +46 -76
- package/layout/_partial/scripts/runtime.ejs +55 -0
- package/layout/_partial/scripts.ejs +18 -42
- package/layout/_partial/search/dialog.ejs +33 -0
- package/layout/_partial/search/shortcut.ejs +1 -0
- package/layout/_partial/sidebar/brand.ejs +127 -0
- package/layout/_partial/sidebar/menu.ejs +59 -14
- package/layout/_partial/sidebar/search.ejs +58 -41
- package/layout/_partial/widgets/actions.ejs +25 -0
- package/layout/_partial/widgets/author.ejs +9 -5
- package/layout/_partial/widgets/components/linklist.ejs +1 -2
- package/layout/_partial/widgets/ghissues.ejs +7 -10
- package/layout/_partial/widgets/ghrepo.ejs +23 -16
- package/layout/_partial/widgets/ghuser.ejs +3 -3
- package/layout/_partial/widgets/recent.ejs +25 -21
- package/layout/_partial/widgets/related.ejs +25 -34
- package/layout/_partial/widgets/settings.ejs +17 -0
- package/layout/_partial/widgets/tagtree.ejs +18 -10
- package/layout/_partial/widgets/toc.ejs +17 -9
- package/layout/_partial/widgets/tree.ejs +12 -13
- package/layout/archive.ejs +20 -13
- package/layout/categories.ejs +4 -3
- package/layout/collection-preview.ejs +8 -9
- package/layout/index.ejs +32 -43
- package/layout/index_topic.ejs +6 -13
- package/layout/index_wiki.ejs +17 -34
- package/layout/layout.ejs +195 -65
- package/layout/notebooks.ejs +3 -3
- package/layout/notes.ejs +4 -4
- package/layout/page.ejs +95 -50
- package/layout/settings.ejs +109 -0
- package/layout/tags.ejs +4 -3
- package/{THIRD-PARTY-NOTICES.md → legal/THIRD-PARTY-NOTICES.md} +8 -4
- package/package.json +28 -6
- package/scripts/commands/stellar.js +55 -0
- package/scripts/events/index.js +15 -9
- package/scripts/events/lib/authors.js +9 -7
- package/scripts/events/lib/config-hot-reload.js +65 -0
- package/scripts/events/lib/config-schema.js +20 -0
- package/scripts/events/lib/config.js +22 -63
- package/scripts/events/lib/content-config.js +5 -0
- package/scripts/events/lib/doc_tree.js +99 -9
- package/scripts/events/lib/links.js +6 -3
- package/scripts/events/lib/notebooks.js +200 -8
- package/scripts/events/lib/utils.js +4 -4
- package/scripts/events/lib/version-check.js +57 -3
- package/scripts/filters/index.js +2 -27
- package/scripts/filters/lib/img_lazyload.js +4 -126
- package/scripts/filters/lib/img_onerror.js +14 -17
- package/scripts/filters/lib/page-view-model.js +152 -0
- package/scripts/generators/404.js +13 -8
- package/scripts/generators/author.js +16 -11
- package/scripts/generators/notebooks.js +68 -39
- package/scripts/generators/search.js +62 -67
- package/scripts/generators/settings.js +43 -0
- package/scripts/generators/stellar-icons.js +13 -5
- package/scripts/generators/topic.js +24 -13
- package/scripts/generators/wiki.js +49 -21
- package/scripts/helpers/ai_label.js +6 -12
- package/scripts/helpers/brand.js +17 -0
- package/scripts/helpers/browser_runtime_manifest.js +12 -0
- package/scripts/helpers/caption.js +8 -0
- package/scripts/helpers/category_color.js +13 -13
- package/scripts/helpers/collection.js +18 -0
- package/scripts/helpers/comments_model.js +14 -0
- package/scripts/helpers/extension_assets.js +8 -0
- package/scripts/helpers/json_ld.js +16 -7
- package/scripts/helpers/mdrender.js +3 -9
- package/scripts/helpers/menu.js +9 -0
- package/scripts/helpers/post_view_model.js +23 -0
- package/scripts/helpers/regions.js +37 -0
- package/scripts/helpers/scrollreveal.js +7 -7
- package/scripts/helpers/search_domain.js +34 -0
- package/scripts/helpers/service_provider.js +9 -0
- package/scripts/helpers/settings.js +16 -0
- package/scripts/helpers/share_action.js +8 -0
- package/scripts/helpers/stellar_config.js +12 -0
- package/scripts/helpers/stellar_data.js +8 -0
- package/scripts/helpers/stellar_info.js +21 -16
- package/scripts/helpers/stellar_inject.js +9 -0
- package/scripts/helpers/ui_classes.js +12 -0
- package/scripts/lib/ai_label.js +14 -11
- package/scripts/lib/brand.js +41 -0
- package/scripts/lib/browser-runtime.js +115 -0
- package/scripts/lib/caption.js +21 -0
- package/scripts/lib/collection-pipeline/adapters/notebook.js +62 -0
- package/scripts/lib/collection-pipeline/adapters/post.js +20 -0
- package/scripts/lib/collection-pipeline/adapters/topic.js +82 -0
- package/scripts/lib/collection-pipeline/adapters/wiki.js +20 -0
- package/scripts/lib/collection-pipeline/index.js +169 -0
- package/scripts/lib/collection-pipeline/registry.js +27 -0
- package/scripts/lib/collection-pipeline/shared.js +164 -0
- package/scripts/lib/comments.js +60 -0
- package/scripts/lib/config-inject.js +20 -0
- package/scripts/lib/config-schema.js +1095 -0
- package/scripts/lib/content-config.js +157 -0
- package/scripts/lib/content-defaults.js +56 -0
- package/scripts/lib/content-membership.js +233 -0
- package/scripts/lib/contribution-contract.js +165 -0
- package/scripts/lib/contribution-registry.js +429 -0
- package/scripts/lib/doc_tree.js +46 -44
- package/scripts/lib/doctor.js +296 -0
- package/scripts/lib/front-matter.js +29 -0
- package/scripts/lib/hero-effect-registry.js +262 -0
- package/scripts/lib/html-images.js +128 -0
- package/scripts/lib/internal-constants.js +152 -0
- package/scripts/lib/layout-config.js +62 -0
- package/scripts/lib/mdrender_html.js +36 -23
- package/scripts/lib/menu.js +36 -0
- package/scripts/lib/model-schema.js +90 -0
- package/scripts/lib/models/index.js +1542 -0
- package/scripts/lib/new-note.js +172 -0
- package/scripts/lib/page-view-model-registry.js +103 -0
- package/scripts/lib/regions.js +132 -0
- package/scripts/lib/runtime-data.js +23 -0
- package/scripts/lib/safe-path.js +44 -0
- package/scripts/lib/search-domain.js +59 -0
- package/scripts/lib/seo.js +10 -10
- package/scripts/lib/service-provider.js +12 -0
- package/scripts/lib/settings.js +16 -0
- package/scripts/lib/share-services.js +96 -0
- package/scripts/lib/source-config.js +27 -0
- package/scripts/lib/theme-metadata.js +22 -0
- package/scripts/lib/ui-capabilities.js +32 -0
- package/scripts/lib/widget-registry.js +150 -0
- package/scripts/lib/wiki_readme.js +15 -11
- package/scripts/schema/config-rules.js +290 -0
- package/scripts/schema/config-schema.js +163 -0
- package/scripts/schema/content-config-rules.js +264 -0
- package/scripts/schema/content-config-schema.js +321 -0
- package/scripts/schema/model-schema.js +971 -0
- package/scripts/schema/schema-utils.js +48 -0
- package/scripts/tags/index.js +2 -3
- package/scripts/tags/lib/albums.js +6 -6
- package/scripts/tags/lib/banner.js +10 -4
- package/scripts/tags/lib/box.js +1 -1
- package/scripts/tags/lib/button.js +1 -1
- package/scripts/tags/lib/chat.js +9 -31
- package/scripts/tags/lib/checkbox.js +6 -1
- package/scripts/tags/lib/copy.js +4 -1
- package/scripts/tags/lib/dropdown.js +6 -4
- package/scripts/tags/lib/emoji.js +5 -10
- package/scripts/tags/lib/friends.js +4 -4
- package/scripts/tags/lib/gallery.js +7 -7
- package/scripts/tags/lib/ghcard.js +5 -3
- package/scripts/tags/lib/gist.js +16 -0
- package/scripts/tags/lib/grid.js +4 -2
- package/scripts/tags/lib/hashtag.js +1 -1
- package/scripts/tags/lib/icon.js +1 -1
- package/scripts/tags/lib/image.js +1 -1
- package/scripts/tags/lib/link.js +6 -3
- package/scripts/tags/lib/mark.js +8 -3
- package/scripts/tags/lib/md.js +1 -1
- package/scripts/tags/lib/note.js +1 -1
- package/scripts/tags/lib/okr.js +18 -1
- package/scripts/tags/lib/posters.js +6 -6
- package/scripts/tags/lib/quot.js +15 -5
- package/scripts/tags/lib/rating.js +7 -4
- package/scripts/tags/lib/sites.js +8 -6
- package/scripts/tags/lib/tip.js +6 -6
- package/scripts/tags/lib/toc.js +2 -2
- package/scripts/tags/lib/vote.js +8 -5
- package/source/css/_appearances/_mixins.styl +258 -0
- package/source/css/_appearances/card.styl +30 -0
- package/source/css/_appearances/flat.styl +44 -0
- package/source/css/_appearances/glass.styl +138 -0
- package/source/css/_appearances/minimal.styl +325 -0
- package/source/css/_common/base.styl +5 -9
- package/source/css/_common/blockquote.styl +0 -1
- package/source/css/_common/button.styl +1 -1
- package/source/css/_common/device.styl +24 -42
- package/source/css/_common/dropdown.styl +20 -14
- package/source/css/_common/highlight.styl +5 -12
- package/source/css/_common/icon.styl +38 -0
- package/source/css/_common/input.styl +33 -0
- package/source/css/_common/loading.styl +2 -2
- package/source/css/_common/svg.styl +0 -8
- package/source/css/_components/collection.styl +21 -64
- package/source/css/_components/layout.styl +524 -84
- package/source/css/_components/list.styl +36 -22
- package/source/css/_components/main.styl +16 -19
- package/source/css/_components/md.styl +8 -13
- package/source/css/_components/pages/article-indent.styl +1 -1
- package/source/css/_components/pages/article-story.styl +7 -6
- package/source/css/_components/pages/article-tech.styl +5 -5
- package/source/css/_components/pages/collection-preview.styl +1 -5
- package/source/css/_components/pages/settings.styl +184 -0
- package/source/css/_components/partial/article-banner.styl +2 -2
- package/source/css/_components/partial/article-footer.styl +0 -32
- package/source/css/_components/partial/article-share.styl +48 -0
- package/source/css/_components/partial/article-tags.styl +1 -1
- package/source/css/_components/partial/cover.styl +13 -13
- package/source/css/_components/partial/listing-nav.styl +68 -0
- package/source/css/_components/partial/paginator.styl +1 -1
- package/source/css/_components/pin-slider.styl +3 -3
- package/source/css/_components/sidebar/brand.styl +135 -0
- package/source/css/_components/sidebar/footer.styl +14 -31
- package/source/css/_components/sidebar/nav-area.styl +4 -0
- package/source/css/_components/sidebar/search.styl +176 -26
- package/source/css/_components/sidebar/sidebar.styl +76 -110
- package/source/css/_components/tag-plugins/banner.styl +16 -28
- package/source/css/_components/tag-plugins/checkbox.styl +7 -22
- package/source/css/_components/tag-plugins/copy.styl +3 -5
- package/source/css/_components/tag-plugins/gallery.styl +2 -2
- package/source/css/_components/tag-plugins/grid.styl +3 -0
- package/source/css/_components/tag-plugins/image.styl +2 -1
- package/source/css/_components/tag-plugins/link.styl +0 -1
- package/source/css/_components/tag-plugins/mark.styl +19 -4
- package/source/css/_components/tag-plugins/mdrender.styl +2 -2
- package/source/css/_components/tag-plugins/navbar.styl +23 -17
- package/source/css/_components/tag-plugins/note.styl +2 -2
- package/source/css/_components/tag-plugins/okr.styl +1 -2
- package/source/css/_components/tag-plugins/quot.styl +5 -0
- package/source/css/_components/tag-plugins/rating.styl +3 -2
- package/source/css/_components/tag-plugins/timeline.styl +1 -1
- package/source/css/_components/tag-plugins/tip.styl +1 -1
- package/source/css/_components/tag-plugins/vote.styl +3 -2
- package/source/css/_components/widgets/ghrepo.styl +2 -1
- package/source/css/_components/widgets/ghuser.styl +4 -6
- package/source/css/_components/widgets/settings.styl +49 -0
- package/source/css/_components/widgets/timeline.styl +2 -2
- package/source/css/_components/widgets/toc.styl +12 -33
- package/source/css/_components/widgets/widgets.styl +14 -19
- package/source/css/_components/wiki-card.styl +2 -2
- package/source/css/_custom.styl +26 -32
- package/source/css/_defines/func.styl +47 -37
- package/source/css/_defines/theme_base.styl +8 -10
- package/source/css/_plugins/card-hover.styl +1 -1
- package/source/css/_plugins/copycode.styl +16 -19
- package/source/css/_plugins/index.styl +3 -8
- package/source/css/_plugins/lazyload.styl +1 -1
- package/source/css/main.styl +12 -0
- package/source/js/main.js +302 -59
- package/source/js/plugins/adaptive-text.js +33 -16
- package/source/js/plugins/card-hover.js +2 -24
- package/source/js/plugins/copycode.js +10 -16
- package/source/js/plugins/voice.js +51 -48
- package/source/js/profile.js +316 -0
- package/source/js/runtime/asset-loader.js +61 -0
- package/source/js/runtime/extension-registry.js +149 -0
- package/source/js/runtime/extensions/card-hover.js +5 -0
- package/source/js/runtime/extensions/color-scheme-switch.js +101 -0
- package/source/js/runtime/extensions/comments.js +200 -0
- package/source/js/runtime/extensions/deferred-icons.js +53 -0
- package/source/js/{plugins → runtime/extensions}/dropdown.js +69 -30
- package/source/js/runtime/extensions/feature.js +200 -0
- package/source/js/runtime/extensions/hero-effect.js +179 -0
- package/source/js/runtime/extensions/reveal.js +80 -0
- package/source/js/runtime/extensions/search.js +23 -0
- package/source/js/{services.js → runtime/extensions/services.js} +67 -54
- package/source/js/runtime/extensions/settings.js +235 -0
- package/source/js/runtime/hero-effects/ferrofluid.js +385 -0
- package/source/js/{plugins → runtime/hero-effects}/galaxy.js +53 -177
- package/source/js/runtime/hero-effects/light-rays.js +293 -0
- package/source/js/runtime/index.js +75 -0
- package/source/js/runtime/legacy-request-adapter.js +47 -0
- package/source/js/runtime/request-cache.js +219 -0
- package/source/js/search/algolia-search.js +76 -51
- package/source/js/search/highlight.js +1 -1
- package/source/js/search/local-search.js +96 -57
- package/source/js/search/shortcut.js +31 -20
- package/source/js/services/friends_and_posts.js +6 -1
- package/source/js/services/rating.js +14 -6
- package/source/js/services/siteinfo.js +3 -7
- package/source/js/services/timeline.js +1 -1
- package/source/js/services/vote.js +7 -5
- package/source/js/services/weibo.js +1 -1
- package/source/js/utils.js +19 -444
- package/.claude/skills/stellar-theme-dev/SKILL.md +0 -51
- package/_data/chat_users.yml +0 -0
- package/layout/_partial/comments/artalk/script.ejs +0 -76
- package/layout/_partial/comments/beaudar/script.ejs +0 -33
- package/layout/_partial/comments/giscus/script.ejs +0 -31
- package/layout/_partial/comments/script.ejs +0 -3
- package/layout/_partial/comments/twikoo/script.ejs +0 -25
- package/layout/_partial/comments/utterances/script.ejs +0 -33
- package/layout/_partial/comments/waline/script.ejs +0 -43
- package/layout/_partial/main/article/article_footer.ejs +0 -164
- package/layout/_partial/main/article/article_tags.ejs +0 -16
- package/layout/_partial/main/article/read_next.ejs +0 -63
- package/layout/_partial/main/article/related_posts.ejs +0 -16
- package/layout/_partial/main/navbar/nav_tabs_wiki.ejs +0 -52
- package/layout/_partial/scripts/bootstrap.ejs +0 -37
- package/layout/_partial/scripts/lazyload.ejs +0 -89
- package/layout/_partial/sidebar/grad-def.ejs +0 -26
- package/layout/_partial/sidebar/index_leftbar.ejs +0 -191
- package/layout/_partial/sidebar/index_rightbar.ejs +0 -94
- package/layout/_partial/sidebar/logo.ejs +0 -99
- package/layout/_plugins/adaptive_text.ejs +0 -11
- package/layout/_plugins/card_hover.ejs +0 -32
- package/layout/_plugins/copycode.ejs +0 -17
- package/layout/_plugins/fancybox.ejs +0 -53
- package/layout/_plugins/heti.ejs +0 -21
- package/layout/_plugins/index.ejs +0 -50
- package/layout/_plugins/mathjax.ejs +0 -49
- package/layout/_plugins/mermaid.ejs +0 -33
- package/layout/_plugins/preload.ejs +0 -9
- package/layout/_plugins/scrollreveal.ejs +0 -102
- package/layout/_plugins/search/algolia_search.ejs +0 -12
- package/layout/_plugins/search/local_search.ejs +0 -9
- package/layout/_plugins/swiper.ejs +0 -27
- package/layout/_plugins/tianli_gpt.ejs +0 -14
- package/scripts/commands/new-note.js +0 -49
- package/scripts/events/lib/merge_posts.js +0 -48
- package/scripts/events/lib/topic_tree.js +0 -48
- package/scripts/helpers/related_posts.js +0 -51
- package/scripts/helpers/subtitle.js +0 -8
- package/scripts/lib/notebooks.js +0 -181
- package/scripts/lib/subtitle.js +0 -28
- package/scripts/tags/lib/about.js +0 -48
- package/source/css/_components/page-transition.styl +0 -22
- package/source/css/_components/partial/navbar.styl +0 -51
- package/source/css/_components/sidebar/logo.styl +0 -111
- package/source/css/_components/tag-plugins/about.styl +0 -56
- package/source/css/_components/widgets/tree.styl +0 -0
- package/source/css/_plugins/scrollreveal.styl +0 -6
- package/source/css/_plugins/tianli_gpt.styl +0 -213
- package/source/css/plugins/mermaid.styl +0 -137
- package/source/js/icons.js +0 -60
- package/source/js/services/fcircle.js +0 -35
- package/source/js/theme.js +0 -61
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
/* global hexo */
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
const { deepFreeze } = require("./schema-utils");
|
|
5
|
+
const { SHARE_SERVICE_IDS } = require("../lib/share-services");
|
|
6
|
+
|
|
7
|
+
const COLLECTION_SCOPE = Object.freeze(["collection"]);
|
|
8
|
+
const FRONT_MATTER_SCOPE = Object.freeze(["front_matter"]);
|
|
9
|
+
const COLLECTION_CASCADE = Object.freeze(["schema default", "theme profile", "collection"]);
|
|
10
|
+
const FRONT_MATTER_CASCADE = Object.freeze(["schema default", "theme profile", "collection", "front matter"]);
|
|
11
|
+
|
|
12
|
+
function literal(value) {
|
|
13
|
+
return { kind: "literal", value };
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function derived(...sources) {
|
|
17
|
+
return { kind: "derived", sources };
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function runtimePath(path) {
|
|
21
|
+
const segments = path.split(".");
|
|
22
|
+
return segments.map((segment, index) => {
|
|
23
|
+
if (segment.startsWith("<")) return segment;
|
|
24
|
+
if (segments[index - 1] === "providers") return segment;
|
|
25
|
+
return segment.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
26
|
+
}).join(".");
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function targetField(path, options) {
|
|
30
|
+
const scopes = options.scopes;
|
|
31
|
+
const types = Array.isArray(options.type) ? options.type : [options.type];
|
|
32
|
+
const boundary = options.boundary || "sealed";
|
|
33
|
+
const hasMergeableUnion = types.length > 1 && (types.includes("array") || types.includes("object"));
|
|
34
|
+
return {
|
|
35
|
+
path,
|
|
36
|
+
type: types,
|
|
37
|
+
default: options.default,
|
|
38
|
+
scopes,
|
|
39
|
+
cascade: options.cascade,
|
|
40
|
+
normalization: options.normalization || "validate the declared type; preserve the value; deep-freeze the result",
|
|
41
|
+
mergeStrategy: options.mergeStrategy || (hasMergeableUnion ? "by_value_type" : (types.includes("array") ? "replace" : (types.includes("object") ? (boundary === "parameter_bag" ? "merge_keys" : "merge_declared_keys") : "replace"))),
|
|
42
|
+
runtimePath: options.runtimePath || runtimePath(path),
|
|
43
|
+
consumers: options.consumers,
|
|
44
|
+
migration: options.migration || `configuration/${path.split(".")[0]}`,
|
|
45
|
+
status: options.status || "planned",
|
|
46
|
+
boundary,
|
|
47
|
+
...(options.items ? { items: options.items } : {}),
|
|
48
|
+
...(options.values ? { values: options.values } : {}),
|
|
49
|
+
...(options.minimum !== undefined ? { minimum: options.minimum } : {}),
|
|
50
|
+
...(options.maximum !== undefined ? { maximum: options.maximum } : {}),
|
|
51
|
+
...(options.exclusiveMinimum !== undefined ? { exclusiveMinimum: options.exclusiveMinimum } : {})
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function fields(consumers, definitions, options = {}) {
|
|
56
|
+
return definitions.map(definition => {
|
|
57
|
+
const resolvedOptions = {
|
|
58
|
+
...options,
|
|
59
|
+
cascade: typeof options.cascade === "function" ? options.cascade(definition[0]) : options.cascade
|
|
60
|
+
};
|
|
61
|
+
return targetField(definition[0], {
|
|
62
|
+
type: definition[1],
|
|
63
|
+
default: definition[2],
|
|
64
|
+
consumers,
|
|
65
|
+
...resolvedOptions,
|
|
66
|
+
...(definition[3] || {})
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
const CONTENT_CONSUMERS = Object.freeze(["CollectionModel", "PageViewModel", "article renderer", "listing renderer"]);
|
|
73
|
+
const REGION_NORMALIZATION = "accept a Region object; validate children and deep-freeze the normalized object";
|
|
74
|
+
const MENU_ITEMS = { type: ["object"], boundary: "parameter_bag" };
|
|
75
|
+
const ACTION_ITEMS = { type: ["object"], boundary: "parameter_bag" };
|
|
76
|
+
|
|
77
|
+
function contentOverrideCascade(scope, path) {
|
|
78
|
+
const page = scope === "front_matter";
|
|
79
|
+
if (/^(?:topbar|leftbar|rightbar)(?:\.|$)/.test(path)) {
|
|
80
|
+
return page
|
|
81
|
+
? ["theme global", "theme profile", "collection", "front matter"]
|
|
82
|
+
: ["theme global", "theme profile", "collection"];
|
|
83
|
+
}
|
|
84
|
+
if (path === "active_menu") {
|
|
85
|
+
return page ? ["theme profile", "collection", "front matter"] : ["theme profile", "collection"];
|
|
86
|
+
}
|
|
87
|
+
if (path === "breadcrumb") {
|
|
88
|
+
return page ? ["collection", "front matter"] : ["collection"];
|
|
89
|
+
}
|
|
90
|
+
if (/^article(?:\.|$)/.test(path)) {
|
|
91
|
+
return page ? ["theme article defaults", "collection", "front matter"] : ["theme article defaults", "collection"];
|
|
92
|
+
}
|
|
93
|
+
if (/^footer(?:\.|$)/.test(path)) {
|
|
94
|
+
return page ? ["theme article footer defaults", "collection", "front matter"] : ["theme article footer defaults", "collection"];
|
|
95
|
+
}
|
|
96
|
+
if (/^comments(?:\.|$)/.test(path)) {
|
|
97
|
+
return page ? ["theme comments defaults", "collection", "front matter"] : ["theme comments defaults", "collection"];
|
|
98
|
+
}
|
|
99
|
+
if (/^source(?:\.|$)/.test(path)) {
|
|
100
|
+
return page ? ["collection", "front matter"] : ["collection"];
|
|
101
|
+
}
|
|
102
|
+
return page ? FRONT_MATTER_CASCADE : COLLECTION_CASCADE;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const CONTENT_OVERRIDE_DEFINITIONS = [
|
|
106
|
+
["topbar", "object", derived("theme or collection topbar"), { boundary: "sealed", normalization: REGION_NORMALIZATION }],
|
|
107
|
+
["topbar.enabled", ["boolean", "null"], literal(null)],
|
|
108
|
+
["topbar.brand", ["object", "boolean", "null"], literal(null), { boundary: "sealed" }],
|
|
109
|
+
["topbar.brand.image", "object", literal({}), { boundary: "sealed" }],
|
|
110
|
+
["topbar.brand.image.src", ["string", "null"], literal(null)],
|
|
111
|
+
["topbar.brand.image.variant", ["string", "null"], literal(null), { values: ["avatar", "icon", "plain", null] }],
|
|
112
|
+
["topbar.brand.name", ["string", "null"], literal(null)],
|
|
113
|
+
["topbar.brand.tagline", ["string", "null"], literal(null)],
|
|
114
|
+
["topbar.brand.href", ["string", "null"], literal(null)],
|
|
115
|
+
["topbar.menu", ["array", "null"], literal(null), { items: MENU_ITEMS }],
|
|
116
|
+
["topbar.widgets", "array", literal([]), { items: { type: ["string", "object"], boundary: "parameter_bag" } }],
|
|
117
|
+
["leftbar", "object", derived("theme or collection leftbar"), { boundary: "sealed", normalization: REGION_NORMALIZATION }],
|
|
118
|
+
["leftbar.enabled", ["boolean", "null"], literal(null)],
|
|
119
|
+
["leftbar.brand", ["object", "boolean", "null"], literal(null), { boundary: "sealed" }],
|
|
120
|
+
["leftbar.brand.style", ["string", "null"], literal(null), { values: ["regular", "compact", null] }],
|
|
121
|
+
["leftbar.brand.image", "object", literal({}), { boundary: "sealed" }],
|
|
122
|
+
["leftbar.brand.image.src", ["string", "null"], literal(null)],
|
|
123
|
+
["leftbar.brand.image.variant", ["string", "null"], literal(null), { values: ["avatar", "icon", "plain", null] }],
|
|
124
|
+
["leftbar.brand.name", ["string", "null"], literal(null)],
|
|
125
|
+
["leftbar.brand.tagline", ["string", "null"], literal(null)],
|
|
126
|
+
["leftbar.brand.href", ["string", "null"], literal(null)],
|
|
127
|
+
["leftbar.menu", ["array", "null"], literal(null), { items: MENU_ITEMS }],
|
|
128
|
+
["leftbar.footer", "object", literal({}), { boundary: "sealed" }],
|
|
129
|
+
["leftbar.footer.actions", ["array", "null"], literal(null), { items: ACTION_ITEMS }],
|
|
130
|
+
["leftbar.widgets", "array", literal([]), { items: { type: ["string", "object"], boundary: "parameter_bag" } }],
|
|
131
|
+
["rightbar", "object", derived("theme or collection rightbar"), { boundary: "sealed", normalization: REGION_NORMALIZATION }],
|
|
132
|
+
["rightbar.enabled", ["boolean", "null"], literal(null)],
|
|
133
|
+
["rightbar.widgets", "array", literal([]), { items: { type: ["string", "object"], boundary: "parameter_bag" } }],
|
|
134
|
+
["active_menu", ["string", "null"], literal(null)],
|
|
135
|
+
["breadcrumb", ["boolean", "null"], literal(null)],
|
|
136
|
+
["article", "object", derived("theme article defaults"), { boundary: "sealed" }],
|
|
137
|
+
["article.style", ["string", "null"], literal(null), { values: ["tech", "story"] }],
|
|
138
|
+
["article.paragraph_indent", ["string", "null"], literal(null), { values: ["auto", "always", "never"] }],
|
|
139
|
+
["article.author", ["string", "null"], literal(null)],
|
|
140
|
+
["article.ai_label", ["string", "null"], literal(null), { values: ["manual", "reviewed", "polished", "generated"] }],
|
|
141
|
+
["footer", "object", derived("content defaults footer"), { boundary: "sealed" }],
|
|
142
|
+
["footer.references", "array", literal([]), { items: { type: ["object", "string"] } }],
|
|
143
|
+
["footer.license", ["boolean", "string", "null"], literal(null)],
|
|
144
|
+
["footer.share", ["boolean", "array", "null"], literal(null), { items: { type: ["string"], values: SHARE_SERVICE_IDS } }],
|
|
145
|
+
["footer.show_tags", ["boolean", "null"], literal(null)],
|
|
146
|
+
["comments", "object", derived("theme comments and broader content scope"), { boundary: "sealed" }],
|
|
147
|
+
["comments.enabled", ["boolean", "null"], literal(null)],
|
|
148
|
+
["comments.title", ["string", "null"], literal(null)],
|
|
149
|
+
["comments.id", ["string", "null"], literal(null)],
|
|
150
|
+
["comments.provider", ["string", "null"], literal(null)],
|
|
151
|
+
["comments.options", "object", literal({}), { boundary: "parameter_bag" }],
|
|
152
|
+
["source", "object", literal({}), { boundary: "sealed" }],
|
|
153
|
+
["source.repository", ["string", "null"], literal(null)],
|
|
154
|
+
["source.branch", ["string", "null"], literal(null)]
|
|
155
|
+
];
|
|
156
|
+
|
|
157
|
+
const COLLECTION_TARGET_DEFINITIONS = [
|
|
158
|
+
["leftbar.brand.source", ["string", "null"], literal(null), { values: ["site", "collection", null] }],
|
|
159
|
+
["leftbar.brand.back_button", ["boolean", "null"], literal(null)],
|
|
160
|
+
["leftbar.brand.search", ["boolean", "null"], literal(null)],
|
|
161
|
+
["name", "string", derived("required collection identity")],
|
|
162
|
+
["headline", ["string", "null"], literal(null)],
|
|
163
|
+
["tagline", ["string", "null"], literal(null)],
|
|
164
|
+
["description", ["string", "null"], literal(null)],
|
|
165
|
+
["tags", "array", literal([]), { items: { type: ["string"] } }],
|
|
166
|
+
["audience", ["string", "null"], literal(null)],
|
|
167
|
+
["icon", ["string", "null"], literal(null)],
|
|
168
|
+
["cover", ["string", "null"], literal(null)],
|
|
169
|
+
["banner", "object", derived("collection banner"), { boundary: "sealed" }],
|
|
170
|
+
["banner.enabled", ["boolean", "null"], literal(null)],
|
|
171
|
+
["banner.image", ["string", "null"], literal(null)],
|
|
172
|
+
["banner.avatar", ["string", "null"], literal(null)],
|
|
173
|
+
["banner.headline", ["string", "null"], literal(null)],
|
|
174
|
+
["banner.tagline", ["string", "null"], literal(null)],
|
|
175
|
+
["hero", "object", literal({}), { boundary: "sealed" }],
|
|
176
|
+
["hero.enabled", ["boolean", "null"], literal(null)],
|
|
177
|
+
["hero.background", "object", literal({}), { boundary: "sealed" }],
|
|
178
|
+
["hero.background.image", ["string", "null"], literal(null)],
|
|
179
|
+
["hero.background.effect", ["object", "null"], literal(null), { boundary: "registered_schema" }],
|
|
180
|
+
["hero.preview", ["object", "null"], literal(null), { boundary: "sealed" }],
|
|
181
|
+
["hero.preview.type", ["string", "null"], literal(null), { values: ["terminal", "image"] }],
|
|
182
|
+
["hero.preview.src", ["string", "null"], literal(null)],
|
|
183
|
+
["hero.preview.alt", ["string", "null"], literal(null)],
|
|
184
|
+
["hero.preview.commands", "array", literal([]), { items: { type: ["object"] } }],
|
|
185
|
+
["hero.preview.commands[].label", ["string", "null"], literal(null)],
|
|
186
|
+
["hero.preview.commands[].codes", ["string", "null"], literal(null)],
|
|
187
|
+
["hero.actions", "array", literal([]), { items: { type: ["object"] } }],
|
|
188
|
+
["hero.actions[].title", ["string", "null"], literal(null)],
|
|
189
|
+
["hero.actions[].url", ["string", "null"], literal(null)],
|
|
190
|
+
["hero.actions[].icon", ["string", "null"], literal(null)],
|
|
191
|
+
["route", "object", literal({}), { boundary: "sealed" }],
|
|
192
|
+
["route.path", "string", derived("collection route"), { normalization: "normalize to a collection-relative path" }],
|
|
193
|
+
["route.start", ["string", "null"], literal(null)],
|
|
194
|
+
["listing", "object", literal({}), { boundary: "sealed" }],
|
|
195
|
+
["listing.priority", ["number", "null"], literal(null), { minimum: 0 }],
|
|
196
|
+
["listing.order", ["number", "null"], literal(null), { minimum: 0 }],
|
|
197
|
+
["listing.excerpt_length", ["number", "null"], literal(null), { minimum: 0 }],
|
|
198
|
+
["listing.per_page", ["number", "null"], literal(null), { minimum: 0 }],
|
|
199
|
+
["listing.sort", ["object", "null"], literal(null), { boundary: "sealed" }],
|
|
200
|
+
["listing.sort.field", ["string", "null"], literal(null), { values: ["date", "updated", "title"] }],
|
|
201
|
+
["listing.sort.direction", ["string", "null"], literal(null), { values: ["asc", "desc"] }],
|
|
202
|
+
["visibility", "object", literal({}), { boundary: "sealed" }],
|
|
203
|
+
["visibility.listed", "boolean", literal(true)],
|
|
204
|
+
["visibility.searchable", "boolean", literal(true)],
|
|
205
|
+
["navigation.tree", ["array", "object"], literal([]), { boundary: "record" }]
|
|
206
|
+
];
|
|
207
|
+
|
|
208
|
+
const FRONT_MATTER_TARGET_DEFINITIONS = [
|
|
209
|
+
["collection", "object", literal({}), { boundary: "sealed" }],
|
|
210
|
+
["collection.profile", "string", derived("required collection profile"), { values: ["wiki", "topic", "notebook"] }],
|
|
211
|
+
["collection.id", "string", derived("required collection ID")],
|
|
212
|
+
["cover", ["string", "null"], literal(null)],
|
|
213
|
+
["tagline", ["string", "null"], literal(null)],
|
|
214
|
+
["banner", "object", derived("collection or theme banner"), { boundary: "sealed" }],
|
|
215
|
+
["banner.enabled", ["boolean", "null"], literal(null)],
|
|
216
|
+
["banner.image", ["string", "null"], literal(null)],
|
|
217
|
+
["banner.avatar", ["string", "null"], literal(null)],
|
|
218
|
+
["banner.headline", ["string", "null"], literal(null)],
|
|
219
|
+
["banner.tagline", ["string", "null"], literal(null)],
|
|
220
|
+
["visibility", "object", literal({}), { boundary: "sealed" }],
|
|
221
|
+
["visibility.listed", "boolean", literal(true)],
|
|
222
|
+
["visibility.searchable", "boolean", literal(true)],
|
|
223
|
+
["listing", "object", literal({}), { boundary: "sealed" }],
|
|
224
|
+
["listing.priority", "number", literal(0), { minimum: 0 }],
|
|
225
|
+
["render", "object", literal({}), { boundary: "sealed" }],
|
|
226
|
+
["render.math", ["boolean", "string"], literal(false), { values: [false, "katex", "mathjax"] }],
|
|
227
|
+
["render.diagrams", ["boolean", "string", "object"], literal(false), { boundary: "parameter_bag" }],
|
|
228
|
+
["seo", "object", literal({}), { boundary: "sealed" }],
|
|
229
|
+
["seo.open_graph", "object", literal({}), { boundary: "parameter_bag" }],
|
|
230
|
+
["inject", "object", literal({}), { boundary: "sealed" }],
|
|
231
|
+
["inject.head_begin", "string", literal("")],
|
|
232
|
+
["inject.head_end", "string", literal("")],
|
|
233
|
+
["inject.body_begin", "string", literal("")],
|
|
234
|
+
["inject.body_end", "string", literal("")]
|
|
235
|
+
];
|
|
236
|
+
|
|
237
|
+
const CONFIG_TARGET_FIELDS = deepFreeze([
|
|
238
|
+
...fields(CONTENT_CONSUMERS, CONTENT_OVERRIDE_DEFINITIONS, {
|
|
239
|
+
scopes: COLLECTION_SCOPE,
|
|
240
|
+
cascade: path => contentOverrideCascade("collection", path),
|
|
241
|
+
migration: "content-schema/collection",
|
|
242
|
+
status: "delivered"
|
|
243
|
+
}),
|
|
244
|
+
...fields(CONTENT_CONSUMERS, CONTENT_OVERRIDE_DEFINITIONS, {
|
|
245
|
+
scopes: FRONT_MATTER_SCOPE,
|
|
246
|
+
cascade: path => contentOverrideCascade("front_matter", path),
|
|
247
|
+
migration: "content-schema/front-matter",
|
|
248
|
+
status: "delivered"
|
|
249
|
+
}),
|
|
250
|
+
...fields(CONTENT_CONSUMERS, COLLECTION_TARGET_DEFINITIONS, {
|
|
251
|
+
scopes: COLLECTION_SCOPE,
|
|
252
|
+
cascade: COLLECTION_CASCADE,
|
|
253
|
+
migration: "content-schema/collection",
|
|
254
|
+
status: "delivered"
|
|
255
|
+
}),
|
|
256
|
+
...fields(CONTENT_CONSUMERS, FRONT_MATTER_TARGET_DEFINITIONS, {
|
|
257
|
+
scopes: FRONT_MATTER_SCOPE,
|
|
258
|
+
cascade: FRONT_MATTER_CASCADE,
|
|
259
|
+
migration: "content-schema/front-matter",
|
|
260
|
+
status: "delivered"
|
|
261
|
+
})
|
|
262
|
+
]);
|
|
263
|
+
|
|
264
|
+
module.exports = { CONFIG_TARGET_FIELDS };
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
/* global hexo */
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
const { literal } = require("./config-schema");
|
|
5
|
+
const { CONFIG_TARGET_FIELDS } = require("./content-config-rules");
|
|
6
|
+
const { deepFreeze } = require("./schema-utils");
|
|
7
|
+
|
|
8
|
+
const HEXO_FRONT_MATTER_FIELDS = Object.freeze([
|
|
9
|
+
"_content",
|
|
10
|
+
"abbrlink",
|
|
11
|
+
"categories",
|
|
12
|
+
"date",
|
|
13
|
+
"description",
|
|
14
|
+
"disableNunjucks",
|
|
15
|
+
"excerpt",
|
|
16
|
+
"keywords",
|
|
17
|
+
"lang",
|
|
18
|
+
"language",
|
|
19
|
+
"layout",
|
|
20
|
+
"link",
|
|
21
|
+
"permalink",
|
|
22
|
+
"photos",
|
|
23
|
+
"published",
|
|
24
|
+
"robots",
|
|
25
|
+
"sitemap",
|
|
26
|
+
"tags",
|
|
27
|
+
"title",
|
|
28
|
+
"updated"
|
|
29
|
+
]);
|
|
30
|
+
|
|
31
|
+
const LEGACY_COLLECTION_ROOTS = Object.freeze({
|
|
32
|
+
title: "name",
|
|
33
|
+
subtitle: "tagline",
|
|
34
|
+
logo: "leftbar.brand",
|
|
35
|
+
wiki_home: "leftbar.brand.back_button",
|
|
36
|
+
coverpage: "hero.enabled",
|
|
37
|
+
background: "hero.background.image",
|
|
38
|
+
animation: "hero.background.effect",
|
|
39
|
+
menu_id: "active_menu",
|
|
40
|
+
search: "leftbar.brand.search",
|
|
41
|
+
menu: "leftbar.menu",
|
|
42
|
+
type: "article.style",
|
|
43
|
+
indent: "article.paragraph_indent",
|
|
44
|
+
author: "article.author",
|
|
45
|
+
ai_label: "article.ai_label",
|
|
46
|
+
references: "footer.references",
|
|
47
|
+
license: "footer.license",
|
|
48
|
+
share: "footer.share",
|
|
49
|
+
comment_title: "comments.title",
|
|
50
|
+
repo: "source.repository",
|
|
51
|
+
branch: "source.branch",
|
|
52
|
+
available: "audience",
|
|
53
|
+
start: "route.start",
|
|
54
|
+
base_dir: "route.path",
|
|
55
|
+
path: "route.path",
|
|
56
|
+
homepage: "navigation.tree",
|
|
57
|
+
sort: "listing.order",
|
|
58
|
+
pin: "listing.priority",
|
|
59
|
+
order_by: "listing.sort",
|
|
60
|
+
auto_excerpt: "listing.excerpt_length",
|
|
61
|
+
per_page: "listing.per_page",
|
|
62
|
+
note_leftbar: "profiles.note.leftbar.widgets | front matter leftbar.widgets",
|
|
63
|
+
note_rightbar: "profiles.note.rightbar.widgets | front matter rightbar.widgets",
|
|
64
|
+
preview: "hero.preview",
|
|
65
|
+
actions: "hero.actions",
|
|
66
|
+
tree: "navigation.tree"
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
const LEGACY_FRONT_MATTER_ROOTS = Object.freeze({
|
|
70
|
+
wiki: "collection.id",
|
|
71
|
+
topic: "collection.id",
|
|
72
|
+
notebook: "collection.id",
|
|
73
|
+
h1: "banner.headline",
|
|
74
|
+
subtitle: "banner.tagline",
|
|
75
|
+
banner_info: "banner",
|
|
76
|
+
menu_id: "active_menu",
|
|
77
|
+
header: "topbar.enabled",
|
|
78
|
+
search: "leftbar.menu search item",
|
|
79
|
+
menu: "leftbar.menu",
|
|
80
|
+
logo: "topbar.brand | leftbar.brand",
|
|
81
|
+
type: "article.style",
|
|
82
|
+
indent: "article.paragraph_indent",
|
|
83
|
+
author: "article.author",
|
|
84
|
+
ai_label: "article.ai_label",
|
|
85
|
+
references: "footer.references",
|
|
86
|
+
license: "footer.license",
|
|
87
|
+
share: "footer.share",
|
|
88
|
+
comment_title: "comments.title",
|
|
89
|
+
comment_id: "comments.id",
|
|
90
|
+
comments_service: "comments.provider",
|
|
91
|
+
beaudar: "comments.options",
|
|
92
|
+
utterances: "comments.options",
|
|
93
|
+
giscus: "comments.options",
|
|
94
|
+
twikoo: "comments.options",
|
|
95
|
+
waline: "comments.options",
|
|
96
|
+
artalk: "comments.options",
|
|
97
|
+
indexing: "visibility.searchable",
|
|
98
|
+
pin: "listing.priority",
|
|
99
|
+
sticky: "listing.priority",
|
|
100
|
+
repo: "source.repository",
|
|
101
|
+
branch: "source.branch",
|
|
102
|
+
nav_tabs: "profiles.blog_index.listing_nav | profiles.wiki_index.listing_nav",
|
|
103
|
+
wiki_home: "collection leftbar.brand.back_button",
|
|
104
|
+
open_graph: "seo.open_graph",
|
|
105
|
+
katex: "render.math",
|
|
106
|
+
mathjax: "render.math",
|
|
107
|
+
mermaid: "render.diagrams"
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
const COMMENT_PROVIDER_FIELDS = Object.freeze([
|
|
111
|
+
"service",
|
|
112
|
+
"beaudar",
|
|
113
|
+
"utterances",
|
|
114
|
+
"giscus",
|
|
115
|
+
"twikoo",
|
|
116
|
+
"waline",
|
|
117
|
+
"artalk"
|
|
118
|
+
]);
|
|
119
|
+
|
|
120
|
+
function clone(value) {
|
|
121
|
+
if (Array.isArray(value)) return value.map(clone);
|
|
122
|
+
if (value == null || typeof value !== "object") return value;
|
|
123
|
+
return Object.fromEntries(Object.entries(value).map(([key, child]) => [key, clone(child)]));
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function camelCase(value) {
|
|
127
|
+
return value.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function exampleFor(target) {
|
|
131
|
+
if (target.default?.kind === "literal") return clone(target.default.value);
|
|
132
|
+
if (target.type.includes("object")) return {};
|
|
133
|
+
if (target.type.includes("array")) return [];
|
|
134
|
+
if (target.type.includes("string")) return "";
|
|
135
|
+
if (target.type.includes("boolean")) return false;
|
|
136
|
+
if (target.type.includes("number")) return 0;
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function normalizerFor(target) {
|
|
141
|
+
if (target.path === "route.path") return "collection_path";
|
|
142
|
+
if (target.path === "footer.share") return "share_override";
|
|
143
|
+
if (target.boundary === "parameter_bag" || target.boundary === "record") return "parameter_bag";
|
|
144
|
+
if (target.type.includes("object")) return "object";
|
|
145
|
+
if (target.type.includes("array")) return "array";
|
|
146
|
+
return "identity";
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function runtimeKeyFor(target) {
|
|
150
|
+
return target.runtimePath.split(".").at(-1).replace(/\[\]$/, "");
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function targetNode(target) {
|
|
154
|
+
return {
|
|
155
|
+
type: clone(target.type),
|
|
156
|
+
default: clone(target.default),
|
|
157
|
+
scope: target.scopes[0],
|
|
158
|
+
cascade: clone(target.cascade),
|
|
159
|
+
normalizer: normalizerFor(target),
|
|
160
|
+
normalization: target.normalization,
|
|
161
|
+
consumers: clone(target.consumers),
|
|
162
|
+
example: exampleFor(target),
|
|
163
|
+
migration: target.migration,
|
|
164
|
+
runtimeKey: runtimeKeyFor(target),
|
|
165
|
+
...(target.boundary === "sealed" ? { sealed: true } : {}),
|
|
166
|
+
...(target.values ? { values: clone(target.values) } : {}),
|
|
167
|
+
...(target.minimum !== undefined ? { minimum: target.minimum } : {}),
|
|
168
|
+
...(target.exclusiveMinimum !== undefined ? { exclusiveMinimum: target.exclusiveMinimum } : {})
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function syntheticObject(scope, path) {
|
|
173
|
+
return {
|
|
174
|
+
type: ["object"],
|
|
175
|
+
default: literal({}),
|
|
176
|
+
scope,
|
|
177
|
+
cascade: scope === "collection"
|
|
178
|
+
? ["schema default", "theme profile", "collection"]
|
|
179
|
+
: ["schema default", "theme profile", "collection", "front matter"],
|
|
180
|
+
normalizer: "object",
|
|
181
|
+
normalization: "merge declared child fields; deep-freeze the normalized JavaScript object",
|
|
182
|
+
consumers: ["CollectionModel", "PageViewModel"],
|
|
183
|
+
example: {},
|
|
184
|
+
migration: `content-schema/${scope.replace("_", "-")}`,
|
|
185
|
+
runtimeKey: camelCase(path.split(".").at(-1).replace(/\[\]$/, "")),
|
|
186
|
+
sealed: true,
|
|
187
|
+
properties: {}
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function itemNode(scope, path, item) {
|
|
192
|
+
const types = clone(item?.type || ["object"]);
|
|
193
|
+
const parameterBag = item?.boundary === "parameter_bag";
|
|
194
|
+
return {
|
|
195
|
+
type: types,
|
|
196
|
+
default: types.includes("object") ? literal({}) : undefined,
|
|
197
|
+
scope,
|
|
198
|
+
cascade: scope === "collection"
|
|
199
|
+
? ["schema default", "theme profile", "collection"]
|
|
200
|
+
: ["schema default", "theme profile", "collection", "front matter"],
|
|
201
|
+
normalizer: parameterBag ? "parameter_bag" : (types.includes("object") ? "object" : "identity"),
|
|
202
|
+
normalization: "validate the declared item type; preserve the value; deep-freeze the result",
|
|
203
|
+
consumers: ["CollectionModel", "PageViewModel"],
|
|
204
|
+
example: types.includes("object") ? {} : "",
|
|
205
|
+
migration: `content-schema/${scope.replace("_", "-")}`,
|
|
206
|
+
runtimeKey: path,
|
|
207
|
+
...(item?.values ? { values: clone(item.values) } : {}),
|
|
208
|
+
...(types.includes("object") && !parameterBag ? { sealed: true, properties: {} } : {})
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function mergeTargetNode(existing, target) {
|
|
213
|
+
const properties = existing?.properties;
|
|
214
|
+
const items = existing?.items;
|
|
215
|
+
const result = { ...targetNode(target) };
|
|
216
|
+
if (properties) result.properties = properties;
|
|
217
|
+
if (items) result.items = items;
|
|
218
|
+
if (target.items && !result.items) result.items = itemNode(target.scopes[0], target.path, target.items);
|
|
219
|
+
return result;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function insertTarget(root, target) {
|
|
223
|
+
const segments = target.path.split(".");
|
|
224
|
+
let node = root;
|
|
225
|
+
let currentPath = "";
|
|
226
|
+
for (let index = 0; index < segments.length; index += 1) {
|
|
227
|
+
const segment = segments[index];
|
|
228
|
+
const array = segment.endsWith("[]");
|
|
229
|
+
const key = array ? segment.slice(0, -2) : segment;
|
|
230
|
+
currentPath = currentPath ? `${currentPath}.${segment}` : segment;
|
|
231
|
+
node.properties ||= {};
|
|
232
|
+
const last = index === segments.length - 1;
|
|
233
|
+
const existing = node.properties[key];
|
|
234
|
+
node.properties[key] = last
|
|
235
|
+
? mergeTargetNode(existing, target)
|
|
236
|
+
: existing || syntheticObject(target.scopes[0], currentPath);
|
|
237
|
+
const child = node.properties[key];
|
|
238
|
+
if (array) {
|
|
239
|
+
child.items ||= itemNode(target.scopes[0], currentPath, target.items);
|
|
240
|
+
node = child.items;
|
|
241
|
+
} else {
|
|
242
|
+
node = child;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function schemaForScope(scope) {
|
|
248
|
+
const root = syntheticObject(scope, scope);
|
|
249
|
+
root.runtimeKey = scope;
|
|
250
|
+
root.applyDefaults = false;
|
|
251
|
+
root.sealed = true;
|
|
252
|
+
for (const target of CONFIG_TARGET_FIELDS.filter(field => field.scopes.includes(scope))) {
|
|
253
|
+
if (target.status !== "delivered") throw new Error(`配置目标 ${scope}:${target.path} 尚未交付`);
|
|
254
|
+
insertTarget(root, target);
|
|
255
|
+
}
|
|
256
|
+
return root;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
function decorateSharedSchemas(schema) {
|
|
260
|
+
for (const region of ["topbar", "leftbar", "rightbar"]) {
|
|
261
|
+
schema.properties[region].normalizer = "object";
|
|
262
|
+
schema.properties[region].normalization = "accept a Region object; validate children and deep-freeze the normalized object";
|
|
263
|
+
}
|
|
264
|
+
for (const region of ["topbar", "leftbar"]) {
|
|
265
|
+
schema.properties[region].properties.brand.validator = "brand";
|
|
266
|
+
schema.properties[region].properties.brand.properties.href.validator = "nullable_safe_navigation_url";
|
|
267
|
+
schema.properties[region].properties.menu.validator = "menu_items";
|
|
268
|
+
}
|
|
269
|
+
schema.properties.leftbar.properties.footer.properties.actions.validator = "footer_actions";
|
|
270
|
+
|
|
271
|
+
const effect = schema.properties.hero?.properties.background?.properties.effect;
|
|
272
|
+
if (effect) {
|
|
273
|
+
effect.validator = "effect";
|
|
274
|
+
effect.normalizer = "effect";
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const tree = schema.properties.navigation?.properties.tree;
|
|
278
|
+
if (tree) tree.validator = "string_tree";
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
function decorateCommon(schema) {
|
|
282
|
+
schema.properties.comments.properties.provider.validator = "nullable_non_empty_string";
|
|
283
|
+
schema.properties.article.properties.style.values = ["tech", "story"];
|
|
284
|
+
schema.properties.article.properties.paragraph_indent.values = ["auto", "always", "never"];
|
|
285
|
+
schema.properties.article.properties.ai_label.values = ["manual", "reviewed", "polished", "generated", null];
|
|
286
|
+
schema.properties.footer.properties.license.validator = "license_override";
|
|
287
|
+
schema.properties.footer.properties.share.validator = "share_override";
|
|
288
|
+
if (schema.properties.listing?.properties?.priority) {
|
|
289
|
+
schema.properties.listing.properties.priority.validator = "non_negative_integer";
|
|
290
|
+
}
|
|
291
|
+
if (schema.properties.render?.properties?.diagrams) {
|
|
292
|
+
schema.properties.render.properties.diagrams.validator = "diagrams_override";
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
const COLLECTION_CONFIG_SCHEMA = schemaForScope("collection");
|
|
297
|
+
COLLECTION_CONFIG_SCHEMA.requiredProperties = ["name"];
|
|
298
|
+
COLLECTION_CONFIG_SCHEMA.removedProperties = clone(LEGACY_COLLECTION_ROOTS);
|
|
299
|
+
COLLECTION_CONFIG_SCHEMA.properties.name.validator = "non_empty_string";
|
|
300
|
+
COLLECTION_CONFIG_SCHEMA.properties.listing.properties.order.validator = "nullable_non_negative_integer";
|
|
301
|
+
COLLECTION_CONFIG_SCHEMA.properties.listing.properties.excerpt_length.validator = "nullable_non_negative_integer";
|
|
302
|
+
COLLECTION_CONFIG_SCHEMA.properties.listing.properties.per_page.validator = "nullable_non_negative_integer";
|
|
303
|
+
decorateSharedSchemas(COLLECTION_CONFIG_SCHEMA);
|
|
304
|
+
COLLECTION_CONFIG_SCHEMA.properties.comments.removedProperties = Object.fromEntries(
|
|
305
|
+
COMMENT_PROVIDER_FIELDS.map(field => [field, field === "service" ? "provider" : "options"])
|
|
306
|
+
);
|
|
307
|
+
decorateCommon(COLLECTION_CONFIG_SCHEMA);
|
|
308
|
+
|
|
309
|
+
const FRONT_MATTER_CONFIG_SCHEMA = schemaForScope("front_matter");
|
|
310
|
+
FRONT_MATTER_CONFIG_SCHEMA.externalProperties = HEXO_FRONT_MATTER_FIELDS;
|
|
311
|
+
FRONT_MATTER_CONFIG_SCHEMA.removedProperties = clone(LEGACY_FRONT_MATTER_ROOTS);
|
|
312
|
+
FRONT_MATTER_CONFIG_SCHEMA.properties.collection.requiredProperties = ["profile", "id"];
|
|
313
|
+
FRONT_MATTER_CONFIG_SCHEMA.properties.collection.properties.id.validator = "non_empty_string";
|
|
314
|
+
decorateSharedSchemas(FRONT_MATTER_CONFIG_SCHEMA);
|
|
315
|
+
decorateCommon(FRONT_MATTER_CONFIG_SCHEMA);
|
|
316
|
+
|
|
317
|
+
module.exports = {
|
|
318
|
+
COLLECTION_CONFIG_SCHEMA: deepFreeze(COLLECTION_CONFIG_SCHEMA),
|
|
319
|
+
FRONT_MATTER_CONFIG_SCHEMA: deepFreeze(FRONT_MATTER_CONFIG_SCHEMA),
|
|
320
|
+
HEXO_FRONT_MATTER_FIELDS
|
|
321
|
+
};
|