erudit 4.0.0-dev.4 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (336) hide show
  1. package/.nuxtrc +1 -1
  2. package/app/app.vue +34 -34
  3. package/app/components/EruditLink.ts +7 -7
  4. package/app/components/FancyBold.vue +16 -16
  5. package/app/components/FancyCard.vue +52 -58
  6. package/app/components/FancyCardTag.vue +16 -16
  7. package/app/components/Loading.vue +7 -7
  8. package/app/components/Prose.vue +55 -52
  9. package/app/components/ScrollHolder.vue +13 -13
  10. package/app/components/SmartMedia.vue +107 -112
  11. package/app/components/ads/Ads.vue +17 -17
  12. package/app/components/ads/AdsBannerAside.vue +29 -29
  13. package/app/components/ads/AdsBannerBottom.vue +6 -6
  14. package/app/components/ads/AdsReplacer.vue +19 -21
  15. package/app/components/ads/provider/Custom.vue +9 -9
  16. package/app/components/ads/provider/Yandex.vue +56 -56
  17. package/app/components/aside/AsideListItem.vue +47 -52
  18. package/app/components/aside/AsideMajor.vue +6 -6
  19. package/app/components/aside/AsideMinor.vue +47 -52
  20. package/app/components/aside/AsidePlainMessage.vue +9 -9
  21. package/app/components/aside/AsideSwitch.vue +53 -54
  22. package/app/components/aside/major/PaneHolder.vue +61 -61
  23. package/app/components/aside/major/PaneSwitcher.vue +50 -55
  24. package/app/components/aside/major/PaneSwitcherButton.vue +24 -24
  25. package/app/components/aside/major/PaneTemplate.vue +3 -3
  26. package/app/components/aside/major/SiteInfo.vue +40 -42
  27. package/app/components/aside/major/contentNav/PaneBookNav.vue +107 -116
  28. package/app/components/aside/major/contentNav/PaneGlobalNav.vue +19 -19
  29. package/app/components/aside/major/contentNav/items/ContentNavBook.vue +8 -8
  30. package/app/components/aside/major/contentNav/items/ContentNavFolder.vue +55 -56
  31. package/app/components/aside/major/contentNav/items/ContentNavItem.vue +16 -16
  32. package/app/components/aside/major/contentNav/items/ContentNavPage.vue +2 -6
  33. package/app/components/aside/major/contentNav/items/ContentNavSeparator.vue +34 -35
  34. package/app/components/aside/major/contentNav/items/ContentNavTopic.vue +6 -6
  35. package/app/components/aside/major/contentNav/items/Flags.vue +31 -33
  36. package/app/components/aside/major/contentNav/items/ItemTemplate.vue +13 -13
  37. package/app/components/aside/major/languages/PaneLanguages.vue +40 -40
  38. package/app/components/aside/major/pages/PanePages.vue +45 -45
  39. package/app/components/aside/major/search/PaneSearch.vue +109 -100
  40. package/app/components/aside/major/search/SearchInput.vue +52 -53
  41. package/app/components/aside/major/search/SearchResult.vue +123 -75
  42. package/app/components/aside/major/search/SearchStatus.vue +28 -28
  43. package/app/components/aside/major/search/search.worker.ts +129 -129
  44. package/app/components/aside/major/settings/BuildTime.vue +15 -15
  45. package/app/components/aside/major/settings/EngineVersion.vue +8 -7
  46. package/app/components/aside/major/settings/PaneSettings.vue +8 -8
  47. package/app/components/aside/major/settings/ThemeSwitcher.vue +36 -36
  48. package/app/components/aside/major/settings/repository/Repository.vue +18 -18
  49. package/app/components/aside/major/settings/repository/SecondaryGitHub.vue +47 -47
  50. package/app/components/aside/minor/AsideMinorPane.vue +5 -5
  51. package/app/components/aside/minor/AsideMinorPlainHeader.vue +20 -20
  52. package/app/components/aside/minor/content/AsideMinorContentContributions.vue +47 -51
  53. package/app/components/aside/minor/content/AsideMinorContentPage.vue +37 -37
  54. package/app/components/aside/minor/content/AsideMinorContentTopic.vue +61 -66
  55. package/app/components/aside/minor/content/ButtonPaneContributions.vue +101 -114
  56. package/app/components/aside/minor/content/ButtonPaneImprove.vue +112 -123
  57. package/app/components/aside/minor/content/Contribution.vue +36 -36
  58. package/app/components/aside/minor/content/Toc.vue +163 -163
  59. package/app/components/aside/minor/content/TocItem.vue +91 -91
  60. package/app/components/aside/minor/content/TopicPartButton.vue +35 -35
  61. package/app/components/aside/minor/contributor/AsideMinorContributor.vue +36 -39
  62. package/app/components/aside/minor/contributor/ItemBook.vue +33 -39
  63. package/app/components/aside/minor/contributor/ItemContent.vue +17 -17
  64. package/app/components/aside/minor/news/AsideMinorNews.vue +132 -132
  65. package/app/components/aside/minor/news/NewsItem.vue +69 -69
  66. package/app/components/aside/minor/news/RenderNewsElement.vue +42 -42
  67. package/app/components/aside/minor/news/elements/Mix.vue +11 -11
  68. package/app/components/aside/minor/news/elements/P.vue +14 -14
  69. package/app/components/aside/minor/news/elements/Ref.vue +59 -58
  70. package/app/components/aside/minor/news/elements/Text.vue +18 -18
  71. package/app/components/indexPage/IndexPagePersons.vue +116 -117
  72. package/app/components/main/MainAction.vue +26 -26
  73. package/app/components/main/MainBreadcrumbs.vue +28 -28
  74. package/app/components/main/MainContentChild.vue +44 -47
  75. package/app/components/main/MainContentChildren.vue +13 -14
  76. package/app/components/main/MainDecoration.vue +15 -15
  77. package/app/components/main/MainDescription.vue +13 -13
  78. package/app/components/main/MainFlag.vue +129 -133
  79. package/app/components/main/MainFlags.vue +17 -17
  80. package/app/components/main/MainGlow.vue +12 -12
  81. package/app/components/main/MainQuickLink.vue +90 -91
  82. package/app/components/main/MainQuickLinks.vue +40 -40
  83. package/app/components/main/MainQuote.vue +149 -161
  84. package/app/components/main/MainQuoteLoader.vue +86 -86
  85. package/app/components/main/MainSection.vue +44 -44
  86. package/app/components/main/MainSectionPreamble.vue +5 -5
  87. package/app/components/main/MainSubTitle.vue +11 -12
  88. package/app/components/main/MainTitle.vue +32 -32
  89. package/app/components/main/MainTopicPartPage.vue +88 -88
  90. package/app/components/main/MainTopicPartSwitch.vue +67 -71
  91. package/app/components/main/connections/Deps.vue +30 -34
  92. package/app/components/main/connections/Externals.vue +80 -104
  93. package/app/components/main/connections/MainConnections.vue +90 -94
  94. package/app/components/main/connections/MainConnectionsButton.vue +81 -81
  95. package/app/components/main/connections/ScrollPane.vue +10 -10
  96. package/app/components/main/contentStats/Item.vue +28 -34
  97. package/app/components/main/contentStats/ItemElement.vue +19 -19
  98. package/app/components/main/contentStats/ItemMaterials.vue +11 -11
  99. package/app/components/main/contentStats/MainContentStats.vue +50 -53
  100. package/app/components/preview/Preview.vue +110 -118
  101. package/app/components/preview/PreviewError.vue +4 -4
  102. package/app/components/preview/PreviewLoading.vue +3 -3
  103. package/app/components/preview/PreviewScreen.vue +48 -48
  104. package/app/components/preview/PreviewScreenButton.vue +27 -27
  105. package/app/components/preview/screen/ContentPage.vue +27 -30
  106. package/app/components/preview/screen/DirectLink.vue +13 -13
  107. package/app/components/preview/screen/Unique.vue +31 -32
  108. package/app/components/site/SiteAside.vue +50 -51
  109. package/app/components/site/SiteAsideOverlay.vue +8 -8
  110. package/app/components/site/SiteMain.vue +11 -11
  111. package/app/components/transition/Fade.vue +16 -16
  112. package/app/components/transition/Slide.vue +27 -27
  113. package/app/components/tree/TreeContainer.vue +3 -3
  114. package/app/components/tree/TreeItem.vue +27 -31
  115. package/app/composables/ads.ts +11 -11
  116. package/app/composables/analytics.ts +102 -102
  117. package/app/composables/appElements.ts +21 -21
  118. package/app/composables/aside.ts +15 -15
  119. package/app/composables/asideMajorPane.ts +82 -82
  120. package/app/composables/asideMinor.ts +109 -109
  121. package/app/composables/contentNav.ts +7 -7
  122. package/app/composables/favicon.ts +103 -108
  123. package/app/composables/file.ts +4 -3
  124. package/app/composables/formatText.ts +100 -100
  125. package/app/composables/loading.ts +26 -26
  126. package/app/composables/mainContent.ts +22 -22
  127. package/app/composables/og.ts +184 -182
  128. package/app/composables/phrases.ts +98 -98
  129. package/app/composables/preview.ts +44 -44
  130. package/app/composables/route.ts +4 -2
  131. package/app/composables/theme.ts +47 -51
  132. package/app/composables/url.ts +19 -11
  133. package/app/formatters/ru.ts +14 -14
  134. package/app/pages/article/[...articleId].vue +12 -12
  135. package/app/pages/book/[...bookId].vue +56 -56
  136. package/app/pages/contributor/[contributorId].vue +144 -150
  137. package/app/pages/contributors.vue +95 -102
  138. package/app/pages/group/[...groupId].vue +58 -58
  139. package/app/pages/index.vue +113 -117
  140. package/app/pages/page/[...pageId].vue +60 -60
  141. package/app/pages/practice/[...practiceId].vue +12 -12
  142. package/app/pages/sponsors.vue +88 -92
  143. package/app/pages/summary/[...summaryId].vue +12 -12
  144. package/app/plugins/appSetup/client/htmlBranding.ts +6 -6
  145. package/app/plugins/appSetup/client/welcome.ts +37 -35
  146. package/app/plugins/appSetup/config.ts +6 -6
  147. package/app/plugins/appSetup/global.ts +3 -3
  148. package/app/plugins/appSetup/index.ts +27 -28
  149. package/app/plugins/prerender.server.ts +40 -40
  150. package/app/router.options.ts +5 -5
  151. package/app/scripts/theme.js +21 -24
  152. package/app/styles/main.css +128 -124
  153. package/bin/erudit.js +12 -0
  154. package/modules/erudit/env.ts +8 -0
  155. package/modules/erudit/globals/content.ts +4 -4
  156. package/modules/erudit/globals/contributor.ts +1 -1
  157. package/modules/erudit/globals/eruditConfig.ts +5 -10
  158. package/modules/erudit/globals/problem.ts +1 -1
  159. package/modules/erudit/globals/prose.ts +5 -1
  160. package/modules/erudit/globals/public.ts +18 -18
  161. package/modules/erudit/index.ts +50 -60
  162. package/modules/erudit/logger.ts +10 -10
  163. package/modules/erudit/setup/elements/appTemplate.ts +44 -45
  164. package/modules/erudit/setup/elements/globalTemplate.ts +82 -82
  165. package/modules/erudit/setup/elements/globalTypes.ts +259 -273
  166. package/modules/erudit/setup/elements/setup.ts +163 -167
  167. package/modules/erudit/setup/elements/shared.ts +10 -10
  168. package/modules/erudit/setup/elements/tagsTable.ts +28 -28
  169. package/modules/erudit/setup/fullRestart.ts +61 -71
  170. package/modules/erudit/setup/globals.ts +210 -196
  171. package/modules/erudit/setup/publicAssets.ts +43 -52
  172. package/modules/erudit/setup/runtimeConfig.ts +106 -58
  173. package/modules/erudit/watcher.ts +20 -27
  174. package/nuxt.config.ts +102 -84
  175. package/package.json +51 -55
  176. package/server/api/aside/major/frontNav/book/[...shortId].ts +10 -10
  177. package/server/api/aside/major/frontNav/global.ts +5 -5
  178. package/server/api/aside/major/pages.ts +6 -6
  179. package/server/api/contributor/list.ts +60 -61
  180. package/server/api/contributor/page/[contributorId].ts +68 -68
  181. package/server/api/indexPage.ts +81 -81
  182. package/server/api/language/functions.ts +11 -11
  183. package/server/api/language/phrase/[phraseKey].ts +35 -35
  184. package/server/api/main/content/[...contentTypePath].ts +149 -153
  185. package/server/api/news/batch/[batchIndex].ts +5 -5
  186. package/server/api/pageSponsors.ts +56 -58
  187. package/server/api/prerender/content.ts +79 -82
  188. package/server/api/prerender/default.ts +35 -35
  189. package/server/api/prerender/files.ts +10 -10
  190. package/server/api/prerender/frontNav.ts +13 -13
  191. package/server/api/prerender/language.ts +7 -7
  192. package/server/api/prerender/news.ts +8 -8
  193. package/server/api/prerender/quotes.ts +15 -15
  194. package/server/api/preview/contentPage/[...contentTypePath].ts +63 -63
  195. package/server/api/preview/contentUnique/[...contentTypePathUnique].ts +73 -81
  196. package/server/api/problemScript/[...problemScriptPath].ts +88 -92
  197. package/server/api/quote/data/[quoteId].ts +84 -87
  198. package/server/api/quote/ids.ts +3 -3
  199. package/server/erudit/build.ts +132 -137
  200. package/server/erudit/cameos/build.ts +161 -161
  201. package/server/erudit/config.ts +13 -13
  202. package/server/erudit/content/global/build.ts +300 -297
  203. package/server/erudit/content/global/singleton.ts +5 -5
  204. package/server/erudit/content/nav/build.ts +459 -463
  205. package/server/erudit/content/nav/front.ts +125 -127
  206. package/server/erudit/content/nav/repository/books.ts +37 -40
  207. package/server/erudit/content/nav/repository/get.ts +33 -33
  208. package/server/erudit/content/nav/repository/hasChildren.ts +5 -5
  209. package/server/erudit/content/nav/repository/hasNav.ts +3 -3
  210. package/server/erudit/content/nav/repository/hasParent.ts +5 -5
  211. package/server/erudit/content/nav/repository/id.ts +9 -9
  212. package/server/erudit/content/nav/repository/index.ts +9 -9
  213. package/server/erudit/content/nav/repository/order.ts +14 -14
  214. package/server/erudit/content/nav/repository/previousNext.ts +35 -35
  215. package/server/erudit/content/nav/repository/walk.ts +127 -127
  216. package/server/erudit/content/nav/setup.ts +13 -13
  217. package/server/erudit/content/nav/types.ts +24 -24
  218. package/server/erudit/content/repository/breadcrumbs.ts +24 -24
  219. package/server/erudit/content/repository/children.ts +47 -47
  220. package/server/erudit/content/repository/connections.ts +35 -35
  221. package/server/erudit/content/repository/contentLink.ts +16 -16
  222. package/server/erudit/content/repository/decoration.ts +23 -23
  223. package/server/erudit/content/repository/deps.ts +121 -84
  224. package/server/erudit/content/repository/description.ts +11 -11
  225. package/server/erudit/content/repository/elementSnippets.ts +105 -105
  226. package/server/erudit/content/repository/externals.ts +50 -50
  227. package/server/erudit/content/repository/flags.ts +33 -33
  228. package/server/erudit/content/repository/seo.ts +12 -12
  229. package/server/erudit/content/repository/stats.ts +97 -97
  230. package/server/erudit/content/repository/title.ts +27 -27
  231. package/server/erudit/content/repository/topicParts.ts +39 -39
  232. package/server/erudit/content/repository/unique.ts +76 -76
  233. package/server/erudit/content/resolve/book.ts +29 -32
  234. package/server/erudit/content/resolve/group.ts +34 -39
  235. package/server/erudit/content/resolve/index.ts +272 -290
  236. package/server/erudit/content/resolve/page.ts +80 -87
  237. package/server/erudit/content/resolve/topic.ts +220 -246
  238. package/server/erudit/content/resolve/utils/contentError.ts +10 -10
  239. package/server/erudit/content/resolve/utils/insertContentItem.ts +113 -122
  240. package/server/erudit/content/resolve/utils/insertContentResolved.ts +126 -132
  241. package/server/erudit/content/search.ts +146 -163
  242. package/server/erudit/contributors/build.ts +158 -166
  243. package/server/erudit/contributors/global.ts +3 -3
  244. package/server/erudit/contributors/repository/avatarUrl.ts +10 -10
  245. package/server/erudit/contributors/repository/contributions.ts +171 -178
  246. package/server/erudit/contributors/repository/count.ts +3 -3
  247. package/server/erudit/contributors/search.ts +34 -34
  248. package/server/erudit/db/repository/pushFile.ts +23 -26
  249. package/server/erudit/db/repository/pushProblemScript.ts +19 -19
  250. package/server/erudit/db/repository/pushProseLink.ts +40 -40
  251. package/server/erudit/db/schema/cameos.ts +7 -7
  252. package/server/erudit/db/schema/content.ts +18 -18
  253. package/server/erudit/db/schema/contentContributions.ts +15 -15
  254. package/server/erudit/db/schema/contentDeps.ts +21 -21
  255. package/server/erudit/db/schema/contentElementStats.ts +20 -20
  256. package/server/erudit/db/schema/contentProseLinks.ts +23 -23
  257. package/server/erudit/db/schema/contentSnippets.ts +15 -15
  258. package/server/erudit/db/schema/contentToc.ts +16 -16
  259. package/server/erudit/db/schema/contentUniques.ts +19 -25
  260. package/server/erudit/db/schema/contributors.ts +12 -12
  261. package/server/erudit/db/schema/files.ts +11 -11
  262. package/server/erudit/db/schema/groups.ts +6 -6
  263. package/server/erudit/db/schema/index.ts +17 -17
  264. package/server/erudit/db/schema/news.ts +7 -7
  265. package/server/erudit/db/schema/pages.ts +7 -7
  266. package/server/erudit/db/schema/problemScripts.ts +14 -14
  267. package/server/erudit/db/schema/sponsors.ts +9 -9
  268. package/server/erudit/db/schema/topics.ts +9 -9
  269. package/server/erudit/db/setup.ts +62 -62
  270. package/server/erudit/db/types.ts +10 -10
  271. package/server/erudit/global.ts +38 -33
  272. package/server/erudit/importer.ts +94 -97
  273. package/server/erudit/index.ts +96 -90
  274. package/server/erudit/language/list/en.ts +116 -116
  275. package/server/erudit/language/list/ru.ts +120 -120
  276. package/server/erudit/language/list.ts +6 -6
  277. package/server/erudit/language/setup.ts +36 -36
  278. package/server/erudit/language/types.ts +16 -16
  279. package/server/erudit/logger.ts +73 -77
  280. package/server/erudit/news/build.ts +112 -114
  281. package/server/erudit/news/repository/batch.ts +61 -61
  282. package/server/erudit/path.ts +19 -0
  283. package/server/erudit/prose/repository/finalize.ts +68 -68
  284. package/server/erudit/prose/repository/get.ts +54 -54
  285. package/server/erudit/prose/repository/resolve.ts +17 -17
  286. package/server/erudit/prose/storage/callout.ts +16 -14
  287. package/server/erudit/prose/storage/image.ts +22 -20
  288. package/server/erudit/prose/storage/link.ts +222 -226
  289. package/server/erudit/prose/storage/problemScript.ts +23 -21
  290. package/server/erudit/prose/storage/video.ts +16 -14
  291. package/server/erudit/prose/transform/bundleProblemScript.ts +6 -6
  292. package/server/erudit/prose/transform/extensions.ts +15 -15
  293. package/server/erudit/quote/repository/ids.ts +31 -31
  294. package/server/erudit/repository.ts +96 -96
  295. package/server/erudit/sponsors/build.ts +161 -165
  296. package/server/erudit/sponsors/repository/avatarUrl.ts +10 -10
  297. package/server/erudit/sponsors/repository/count.ts +4 -4
  298. package/server/erudit/staticFile.ts +28 -28
  299. package/server/plugins/augmentCss.ts +17 -17
  300. package/server/plugins/lang.ts +5 -7
  301. package/server/plugins/metaViewport.ts +15 -15
  302. package/server/plugins/theme.ts +13 -13
  303. package/server/routes/file/[...path].ts +18 -18
  304. package/server/routes/robots.txt.ts +9 -9
  305. package/server/routes/search.json.gz.ts +76 -75
  306. package/server/routes/sitemap.xml.ts +83 -81
  307. package/shared/search/encoders.ts +10 -10
  308. package/shared/types/asideMajorPages.ts +2 -2
  309. package/shared/types/breadcrumbs.ts +3 -3
  310. package/shared/types/contentChildren.ts +10 -10
  311. package/shared/types/contentConnections.ts +27 -27
  312. package/shared/types/contentStats.ts +6 -6
  313. package/shared/types/elementSnippet.ts +14 -14
  314. package/shared/types/frontContentNav.ts +17 -17
  315. package/shared/types/indexPage.ts +20 -20
  316. package/shared/types/language.ts +174 -174
  317. package/shared/types/mainContent.ts +40 -40
  318. package/shared/types/news.ts +13 -13
  319. package/shared/types/preview.ts +28 -28
  320. package/shared/types/runtimeConfig.ts +29 -48
  321. package/shared/types/search.ts +32 -32
  322. package/shared/utils/contentTypePath.ts +44 -44
  323. package/shared/utils/icons.ts +7 -7
  324. package/shared/utils/pages.ts +19 -20
  325. package/shared/utils/stringColor.ts +8 -8
  326. package/shared/utils/toStringEqual.ts +13 -13
  327. package/shared/utils/zip.ts +64 -64
  328. package/test/shared/utils/zip.test.ts +8 -8
  329. package/tsconfig.json +15 -15
  330. package/bin/erudit.mjs +0 -2
  331. package/modules/erudit/setup/aliases.ts +0 -17
  332. package/modules/erudit/setup/baseUrl.ts +0 -19
  333. package/modules/erudit/setup/nuxtConfig.ts +0 -62
  334. package/modules/erudit/setup/projectConfig.ts +0 -115
  335. package/shared/utils/slasher.ts +0 -64
  336. package/test/shared/utils/slasher.test.ts +0 -75
@@ -1,97 +1,97 @@
1
- import { and, eq, sql } from 'drizzle-orm';
2
-
3
- export async function addContentElementCount(
4
- fullId: string,
5
- schemaName: string,
6
- amount: number,
7
- ): Promise<void> {
8
- await ERUDIT.db
9
- .insert(ERUDIT.db.schema.contentElementStats)
10
- .values({
11
- fullId,
12
- schemaName,
13
- count: 0,
14
- })
15
- .onConflictDoNothing();
16
-
17
- await ERUDIT.db
18
- .update(ERUDIT.db.schema.contentElementStats)
19
- .set({
20
- count: sql`${ERUDIT.db.schema.contentElementStats.count} + ${amount}`,
21
- })
22
- .where(
23
- and(
24
- eq(ERUDIT.db.schema.contentElementStats.fullId, fullId),
25
- eq(ERUDIT.db.schema.contentElementStats.schemaName, schemaName),
26
- ),
27
- );
28
- }
29
-
30
- export async function getContentStats(
31
- fullContentId?: string,
32
- ): Promise<ContentStats | undefined> {
33
- const stats: ContentStats = {};
34
-
35
- const rootNavNode = fullContentId
36
- ? ERUDIT.contentNav.getNodeOrThrow(fullContentId)
37
- : ({
38
- type: '_root',
39
- children: Array.from(ERUDIT.contentNav.id2Root.values()),
40
- } as const);
41
-
42
- if (rootNavNode.type !== 'topic' && rootNavNode.type !== 'page') {
43
- // Container node, so look for materials inside it
44
- let materialCount = 0;
45
- await ERUDIT.contentNav.walk((navNode) => {
46
- if (navNode.type === 'topic' || navNode.type === 'page') {
47
- materialCount++;
48
- }
49
- }, rootNavNode as any);
50
-
51
- if (materialCount > 0) {
52
- stats.materials = materialCount;
53
- }
54
- }
55
-
56
- const schema2Count: Record<string, number> = {};
57
-
58
- const rows = await ERUDIT.db.query.contentElementStats.findMany({
59
- where: fullContentId
60
- ? sql`${ERUDIT.db.schema.contentElementStats.fullId} = ${fullContentId} OR ${ERUDIT.db.schema.contentElementStats.fullId} LIKE ${fullContentId + '/%'}`
61
- : sql`1=1`,
62
- });
63
-
64
- for (const row of rows) {
65
- if (row.count > 0) {
66
- schema2Count[row.schemaName] =
67
- (schema2Count[row.schemaName] || 0) + row.count;
68
- }
69
- }
70
-
71
- // Possible merge arrays of schema names into single stats entry
72
- const actualElementStats = ERUDIT.config.project.countElements.reduce<
73
- Record<string, number>
74
- >((acc, current) => {
75
- if (Array.isArray(current)) {
76
- const firstKey = current[0]!;
77
- const sum = current.reduce((sum, name) => {
78
- return sum + (schema2Count[name] || 0);
79
- }, 0);
80
- if (sum > 0) {
81
- acc[firstKey] = sum;
82
- }
83
- } else {
84
- const count = schema2Count[current] || 0;
85
- if (count > 0) {
86
- acc[current] = count;
87
- }
88
- }
89
- return acc;
90
- }, {});
91
-
92
- if (Object.keys(actualElementStats).length > 0) {
93
- stats.elements = actualElementStats;
94
- }
95
-
96
- return Object.keys(stats).length > 0 ? stats : undefined;
97
- }
1
+ import { and, eq, sql } from 'drizzle-orm';
2
+
3
+ export async function addContentElementCount(
4
+ fullId: string,
5
+ schemaName: string,
6
+ amount: number,
7
+ ): Promise<void> {
8
+ await ERUDIT.db
9
+ .insert(ERUDIT.db.schema.contentElementStats)
10
+ .values({
11
+ fullId,
12
+ schemaName,
13
+ count: 0,
14
+ })
15
+ .onConflictDoNothing();
16
+
17
+ await ERUDIT.db
18
+ .update(ERUDIT.db.schema.contentElementStats)
19
+ .set({
20
+ count: sql`${ERUDIT.db.schema.contentElementStats.count} + ${amount}`,
21
+ })
22
+ .where(
23
+ and(
24
+ eq(ERUDIT.db.schema.contentElementStats.fullId, fullId),
25
+ eq(ERUDIT.db.schema.contentElementStats.schemaName, schemaName),
26
+ ),
27
+ );
28
+ }
29
+
30
+ export async function getContentStats(
31
+ fullContentId?: string,
32
+ ): Promise<ContentStats | undefined> {
33
+ const stats: ContentStats = {};
34
+
35
+ const rootNavNode = fullContentId
36
+ ? ERUDIT.contentNav.getNodeOrThrow(fullContentId)
37
+ : ({
38
+ type: '_root',
39
+ children: Array.from(ERUDIT.contentNav.id2Root.values()),
40
+ } as const);
41
+
42
+ if (rootNavNode.type !== 'topic' && rootNavNode.type !== 'page') {
43
+ // Container node, so look for materials inside it
44
+ let materialCount = 0;
45
+ await ERUDIT.contentNav.walk((navNode) => {
46
+ if (navNode.type === 'topic' || navNode.type === 'page') {
47
+ materialCount++;
48
+ }
49
+ }, rootNavNode as any);
50
+
51
+ if (materialCount > 0) {
52
+ stats.materials = materialCount;
53
+ }
54
+ }
55
+
56
+ const schema2Count: Record<string, number> = {};
57
+
58
+ const rows = await ERUDIT.db.query.contentElementStats.findMany({
59
+ where: fullContentId
60
+ ? sql`${ERUDIT.db.schema.contentElementStats.fullId} = ${fullContentId} OR ${ERUDIT.db.schema.contentElementStats.fullId} LIKE ${fullContentId + '/%'}`
61
+ : sql`1=1`,
62
+ });
63
+
64
+ for (const row of rows) {
65
+ if (row.count > 0) {
66
+ schema2Count[row.schemaName] =
67
+ (schema2Count[row.schemaName] || 0) + row.count;
68
+ }
69
+ }
70
+
71
+ // Possible merge arrays of schema names into single stats entry
72
+ const actualElementStats = ERUDIT.config.countElements.reduce<
73
+ Record<string, number>
74
+ >((acc, current) => {
75
+ if (Array.isArray(current)) {
76
+ const firstKey = current[0]!;
77
+ const sum = current.reduce((sum, name) => {
78
+ return sum + (schema2Count[name] || 0);
79
+ }, 0);
80
+ if (sum > 0) {
81
+ acc[firstKey] = sum;
82
+ }
83
+ } else {
84
+ const count = schema2Count[current] || 0;
85
+ if (count > 0) {
86
+ acc[current] = count;
87
+ }
88
+ }
89
+ return acc;
90
+ }, {});
91
+
92
+ if (Object.keys(actualElementStats).length > 0) {
93
+ stats.elements = actualElementStats;
94
+ }
95
+
96
+ return Object.keys(stats).length > 0 ? stats : undefined;
97
+ }
@@ -1,27 +1,27 @@
1
- import { eq } from 'drizzle-orm';
2
-
3
- export async function getContentTitle(
4
- fullContentId: string,
5
- type: 'normal' | 'nav' = 'normal',
6
- ) {
7
- const dbContentItem = await ERUDIT.db.query.content.findFirst({
8
- columns: {
9
- title: true,
10
- navTitle: true,
11
- },
12
- where: eq(ERUDIT.db.schema.content.fullId, fullContentId),
13
- });
14
-
15
- if (!dbContentItem) {
16
- throw createError({
17
- statusCode: 404,
18
- message: `Content with id "${fullContentId}" not found!`,
19
- });
20
- }
21
-
22
- if (type === 'nav' && dbContentItem.navTitle) {
23
- return dbContentItem.navTitle;
24
- }
25
-
26
- return dbContentItem.title || fullContentId.split('/').pop()!;
27
- }
1
+ import { eq } from 'drizzle-orm';
2
+
3
+ export async function getContentTitle(
4
+ fullContentId: string,
5
+ type: 'normal' | 'nav' = 'normal',
6
+ ) {
7
+ const dbContentItem = await ERUDIT.db.query.content.findFirst({
8
+ columns: {
9
+ title: true,
10
+ navTitle: true,
11
+ },
12
+ where: eq(ERUDIT.db.schema.content.fullId, fullContentId),
13
+ });
14
+
15
+ if (!dbContentItem) {
16
+ throw createError({
17
+ statusCode: 404,
18
+ message: `Content with id "${fullContentId}" not found!`,
19
+ });
20
+ }
21
+
22
+ if (type === 'nav' && dbContentItem.navTitle) {
23
+ return dbContentItem.navTitle;
24
+ }
25
+
26
+ return dbContentItem.title || fullContentId.split('/').pop()!;
27
+ }
@@ -1,39 +1,39 @@
1
- import { eq, sql } from 'drizzle-orm';
2
- import type { TopicPart } from '@erudit-js/core/content/topic';
3
-
4
- export async function getTopicParts(fullId: string): Promise<TopicPart[]> {
5
- const dbResult = await ERUDIT.db
6
- .select({
7
- hasArticle: sql<boolean>`(${ERUDIT.db.schema.topics.article} IS NOT NULL)`,
8
- hasSummary: sql<boolean>`(${ERUDIT.db.schema.topics.summary} IS NOT NULL)`,
9
- hasPractice: sql<boolean>`(${ERUDIT.db.schema.topics.practice} IS NOT NULL)`,
10
- })
11
- .from(ERUDIT.db.schema.topics)
12
- .where(eq(ERUDIT.db.schema.topics.fullId, fullId));
13
-
14
- const topic = dbResult?.[0];
15
- if (!topic) {
16
- return [];
17
- }
18
-
19
- const parts: TopicPart[] = [];
20
-
21
- if (topic.hasArticle) {
22
- parts.push('article');
23
- }
24
-
25
- if (topic.hasSummary) {
26
- parts.push('summary');
27
- }
28
-
29
- if (topic.hasPractice) {
30
- parts.push('practice');
31
- }
32
-
33
- return parts;
34
- }
35
-
36
- export async function getDefaultTopicPart(fullId: string): Promise<TopicPart> {
37
- const parts = await getTopicParts(fullId);
38
- return parts[0];
39
- }
1
+ import { eq, sql } from 'drizzle-orm';
2
+ import type { TopicPart } from '@erudit-js/core/content/topic';
3
+
4
+ export async function getTopicParts(fullId: string): Promise<TopicPart[]> {
5
+ const dbResult = await ERUDIT.db
6
+ .select({
7
+ hasArticle: sql<boolean>`(${ERUDIT.db.schema.topics.article} IS NOT NULL)`,
8
+ hasSummary: sql<boolean>`(${ERUDIT.db.schema.topics.summary} IS NOT NULL)`,
9
+ hasPractice: sql<boolean>`(${ERUDIT.db.schema.topics.practice} IS NOT NULL)`,
10
+ })
11
+ .from(ERUDIT.db.schema.topics)
12
+ .where(eq(ERUDIT.db.schema.topics.fullId, fullId));
13
+
14
+ const topic = dbResult?.[0];
15
+ if (!topic) {
16
+ return [];
17
+ }
18
+
19
+ const parts: TopicPart[] = [];
20
+
21
+ if (topic.hasArticle) {
22
+ parts.push('article');
23
+ }
24
+
25
+ if (topic.hasSummary) {
26
+ parts.push('summary');
27
+ }
28
+
29
+ if (topic.hasPractice) {
30
+ parts.push('practice');
31
+ }
32
+
33
+ return parts;
34
+ }
35
+
36
+ export async function getDefaultTopicPart(fullId: string): Promise<TopicPart> {
37
+ const parts = await getTopicParts(fullId);
38
+ return parts[0];
39
+ }
@@ -1,76 +1,76 @@
1
- import { and, eq } from 'drizzle-orm';
2
- import {
3
- mixSchema,
4
- walkElements,
5
- WalkNoDeeper,
6
- WalkStop,
7
- type AnySchema,
8
- type ProseElement,
9
- } from '@jsprose/core';
10
- import type { ContentProseType } from '@erudit-js/core/content/prose';
11
- import { headingSchema } from '@erudit-js/prose/elements/heading/core';
12
-
13
- export async function getContentUnique(
14
- fullId: string,
15
- proseType: ContentProseType,
16
- uniqueName: string,
17
- ) {
18
- const dbContentUnique = await ERUDIT.db.query.contentUniques.findFirst({
19
- where: and(
20
- eq(ERUDIT.db.schema.contentUniques.contentFullId, fullId),
21
- eq(ERUDIT.db.schema.contentUniques.contentProseType, proseType),
22
- eq(ERUDIT.db.schema.contentUniques.uniqueName, uniqueName),
23
- ),
24
- });
25
-
26
- if (!dbContentUnique) {
27
- throw createError({
28
- statusCode: 404,
29
- message: `Content unique with name "${uniqueName}" for content "${fullId}" and prose type "${proseType}" not found!`,
30
- });
31
- }
32
-
33
- return dbContentUnique;
34
- }
35
-
36
- export async function getContentHeadingUnique(
37
- fullId: string,
38
- proseType: ContentProseType,
39
- uniqueName: string,
40
- ) {
41
- const contentProse = await ERUDIT.repository.prose.getContent(
42
- proseType,
43
- fullId,
44
- );
45
-
46
- const afterHeadingElements: ProseElement<AnySchema>[] = [];
47
- let adding = false;
48
-
49
- await walkElements(contentProse, async (element) => {
50
- if (
51
- element.schemaName === headingSchema.name &&
52
- element.uniqueName === uniqueName
53
- ) {
54
- adding = true;
55
- }
56
-
57
- if (adding) {
58
- afterHeadingElements.push(element);
59
-
60
- if (afterHeadingElements.length === 4) {
61
- adding = false;
62
- return WalkStop;
63
- }
64
-
65
- return WalkNoDeeper;
66
- }
67
- });
68
-
69
- const mix: ProseElement<typeof mixSchema> = {
70
- __JSPROSE_element: true,
71
- schemaName: mixSchema.name,
72
- children: afterHeadingElements,
73
- } as ProseElement<typeof mixSchema>;
74
-
75
- return mix;
76
- }
1
+ import { and, eq } from 'drizzle-orm';
2
+ import {
3
+ mixSchema,
4
+ walkElements,
5
+ WalkNoDeeper,
6
+ WalkStop,
7
+ type AnySchema,
8
+ type ProseElement,
9
+ } from '@jsprose/core';
10
+ import type { ContentProseType } from '@erudit-js/core/content/prose';
11
+ import { headingSchema } from '@erudit-js/prose/elements/heading/core';
12
+
13
+ export async function getContentUnique(
14
+ fullId: string,
15
+ proseType: ContentProseType,
16
+ uniqueName: string,
17
+ ) {
18
+ const dbContentUnique = await ERUDIT.db.query.contentUniques.findFirst({
19
+ where: and(
20
+ eq(ERUDIT.db.schema.contentUniques.contentFullId, fullId),
21
+ eq(ERUDIT.db.schema.contentUniques.contentProseType, proseType),
22
+ eq(ERUDIT.db.schema.contentUniques.uniqueName, uniqueName),
23
+ ),
24
+ });
25
+
26
+ if (!dbContentUnique) {
27
+ throw createError({
28
+ statusCode: 404,
29
+ message: `Content unique with name "${uniqueName}" for content "${fullId}" and prose type "${proseType}" not found!`,
30
+ });
31
+ }
32
+
33
+ return dbContentUnique;
34
+ }
35
+
36
+ export async function getContentHeadingUnique(
37
+ fullId: string,
38
+ proseType: ContentProseType,
39
+ uniqueName: string,
40
+ ) {
41
+ const contentProse = await ERUDIT.repository.prose.getContent(
42
+ proseType,
43
+ fullId,
44
+ );
45
+
46
+ const afterHeadingElements: ProseElement<AnySchema>[] = [];
47
+ let adding = false;
48
+
49
+ await walkElements(contentProse, async (element) => {
50
+ if (
51
+ element.schemaName === headingSchema.name &&
52
+ element.uniqueName === uniqueName
53
+ ) {
54
+ adding = true;
55
+ }
56
+
57
+ if (adding) {
58
+ afterHeadingElements.push(element);
59
+
60
+ if (afterHeadingElements.length === 4) {
61
+ adding = false;
62
+ return WalkStop;
63
+ }
64
+
65
+ return WalkNoDeeper;
66
+ }
67
+ });
68
+
69
+ const mix: ProseElement<typeof mixSchema> = {
70
+ __JSPROSE_element: true,
71
+ schemaName: mixSchema.name,
72
+ children: afterHeadingElements,
73
+ } as ProseElement<typeof mixSchema>;
74
+
75
+ return mix;
76
+ }
@@ -1,32 +1,29 @@
1
- import type { BookContentItem } from '@erudit-js/core/content/book';
2
- import { isContentItem } from '@erudit-js/core/content/item';
3
-
4
- import type { ContentNavNode } from '../nav/types';
5
- import { logContentError } from './utils/contentError';
6
- import { insertContentItem } from './utils/insertContentItem';
7
-
8
- export async function resolveBook(bookNode: ContentNavNode) {
9
- ERUDIT.log.debug.start(
10
- `Resolving book ${ERUDIT.log.stress(bookNode.fullId)}...`,
11
- );
12
-
13
- try {
14
- const bookModule = await ERUDIT.import<{ default: BookContentItem }>(
15
- ERUDIT.config.paths.project +
16
- '/content/' +
17
- bookNode.contentRelPath +
18
- '/book',
19
- );
20
-
21
- if (!isContentItem<BookContentItem>(bookModule?.default, 'book')) {
22
- throw new Error('Book default export must be a book content item!');
23
- }
24
-
25
- const bookContentItem = bookModule.default;
26
-
27
- await insertContentItem(bookNode, bookContentItem);
28
- } catch (error) {
29
- logContentError(bookNode);
30
- throw error;
31
- }
32
- }
1
+ import type { BookContentItem } from '@erudit-js/core/content/book';
2
+ import { isContentItem } from '@erudit-js/core/content/item';
3
+
4
+ import type { ContentNavNode } from '../nav/types';
5
+ import { logContentError } from './utils/contentError';
6
+ import { insertContentItem } from './utils/insertContentItem';
7
+
8
+ export async function resolveBook(bookNode: ContentNavNode) {
9
+ ERUDIT.log.debug.start(
10
+ `Resolving book ${ERUDIT.log.stress(bookNode.fullId)}...`,
11
+ );
12
+
13
+ try {
14
+ const bookModule = await ERUDIT.import<{ default: BookContentItem }>(
15
+ ERUDIT.paths.project(`content/${bookNode.contentRelPath}/book`),
16
+ );
17
+
18
+ if (!isContentItem<BookContentItem>(bookModule?.default, 'book')) {
19
+ throw new Error('Book default export must be a book content item!');
20
+ }
21
+
22
+ const bookContentItem = bookModule.default;
23
+
24
+ await insertContentItem(bookNode, bookContentItem);
25
+ } catch (error) {
26
+ logContentError(bookNode);
27
+ throw error;
28
+ }
29
+ }
@@ -1,39 +1,34 @@
1
- import type { GroupContentItem } from '@erudit-js/core/content/group';
2
- import { isContentItem } from '@erudit-js/core/content/item';
3
-
4
- import type { ContentNavNode } from '../nav/types';
5
- import { logContentError } from './utils/contentError';
6
- import { insertContentItem } from './utils/insertContentItem';
7
-
8
- export async function resolveGroup(groupNode: ContentNavNode) {
9
- ERUDIT.log.debug.start(
10
- `Resolving group ${ERUDIT.log.stress(groupNode.fullId)}...`,
11
- );
12
-
13
- try {
14
- const groupModule = await ERUDIT.import<{ default: GroupContentItem }>(
15
- ERUDIT.config.paths.project +
16
- '/content/' +
17
- groupNode.contentRelPath +
18
- '/group',
19
- );
20
-
21
- if (!isContentItem<GroupContentItem>(groupModule?.default, 'group')) {
22
- throw new Error(
23
- 'Group default export must be a group content item!',
24
- );
25
- }
26
-
27
- const groupContentItem = groupModule.default;
28
-
29
- await insertContentItem(groupNode, groupContentItem);
30
-
31
- await ERUDIT.db.insert(ERUDIT.db.schema.groups).values({
32
- fullId: groupNode.fullId,
33
- separator: groupContentItem.separator ?? false,
34
- });
35
- } catch (error) {
36
- logContentError(groupNode);
37
- throw error;
38
- }
39
- }
1
+ import type { GroupContentItem } from '@erudit-js/core/content/group';
2
+ import { isContentItem } from '@erudit-js/core/content/item';
3
+
4
+ import type { ContentNavNode } from '../nav/types';
5
+ import { logContentError } from './utils/contentError';
6
+ import { insertContentItem } from './utils/insertContentItem';
7
+
8
+ export async function resolveGroup(groupNode: ContentNavNode) {
9
+ ERUDIT.log.debug.start(
10
+ `Resolving group ${ERUDIT.log.stress(groupNode.fullId)}...`,
11
+ );
12
+
13
+ try {
14
+ const groupModule = await ERUDIT.import<{ default: GroupContentItem }>(
15
+ ERUDIT.paths.project(`content/${groupNode.contentRelPath}/group`),
16
+ );
17
+
18
+ if (!isContentItem<GroupContentItem>(groupModule?.default, 'group')) {
19
+ throw new Error('Group default export must be a group content item!');
20
+ }
21
+
22
+ const groupContentItem = groupModule.default;
23
+
24
+ await insertContentItem(groupNode, groupContentItem);
25
+
26
+ await ERUDIT.db.insert(ERUDIT.db.schema.groups).values({
27
+ fullId: groupNode.fullId,
28
+ separator: groupContentItem.separator ?? false,
29
+ });
30
+ } catch (error) {
31
+ logContentError(groupNode);
32
+ throw error;
33
+ }
34
+ }