erudit 3.0.0-dev.15 → 3.0.0-dev.17
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/app/app.vue +191 -195
- package/app/components/Loading.vue +23 -23
- package/app/components/SiteAside.vue +393 -393
- package/app/components/SiteMain.vue +32 -32
- package/app/components/ads/Ads.vue +35 -0
- package/app/components/ads/AdsBannerAside.vue +61 -0
- package/app/components/ads/AdsBannerBottom.vue +22 -0
- package/app/components/ads/AdsProviderCustom.vue +35 -0
- package/app/components/ads/AdsProviderYandex.vue +54 -0
- package/app/components/ads/AdsReplacer.vue +73 -0
- package/app/components/aside/AsideListItem.vue +74 -74
- package/app/components/aside/AsideMajor.vue +56 -56
- package/app/components/aside/AsideMinor.vue +73 -71
- package/app/components/aside/major/PaneContentScroll.vue +23 -23
- package/app/components/aside/major/PaneSwitch.vue +54 -54
- package/app/components/aside/major/PaneSwitchButton.vue +63 -63
- package/app/components/aside/major/SiteInfo.vue +85 -85
- package/app/components/aside/major/panes/Language.vue +79 -79
- package/app/components/aside/major/panes/Pages.vue +34 -34
- package/app/components/aside/major/panes/Search.vue +11 -11
- package/app/components/aside/major/panes/nav/Nav.vue +92 -92
- package/app/components/aside/major/panes/nav/NavBook.vue +95 -95
- package/app/components/aside/major/panes/nav/NavBookLoading.vue +24 -24
- package/app/components/aside/major/panes/nav/NavGlobal.vue +16 -16
- package/app/components/aside/major/panes/nav/fnav/FNav.vue +105 -105
- package/app/components/aside/major/panes/nav/fnav/FNavBook.vue +32 -32
- package/app/components/aside/major/panes/nav/fnav/FNavFlags.vue +40 -40
- package/app/components/aside/major/panes/nav/fnav/FNavFolder.vue +60 -60
- package/app/components/aside/major/panes/nav/fnav/FNavItem.vue +34 -34
- package/app/components/aside/major/panes/nav/fnav/FNavSeparator.vue +80 -80
- package/app/components/aside/major/panes/nav/fnav/FNavTopic.vue +24 -24
- package/app/components/aside/major/panes/other/ItemContent.vue +29 -29
- package/app/components/aside/major/panes/other/ItemGenerator.vue +13 -13
- package/app/components/aside/major/panes/other/ItemTheme.vue +54 -54
- package/app/components/aside/major/panes/other/Other.vue +16 -16
- package/app/components/aside/minor/AsideMinorContributor.vue +5 -5
- package/app/components/aside/minor/AsideMinorNews.vue +11 -11
- package/app/components/aside/minor/AsideMinorPane.vue +15 -15
- package/app/components/aside/minor/AsideMinorTopLink.vue +67 -67
- package/app/components/aside/minor/Contribute.vue +145 -145
- package/app/components/aside/minor/content/AsideMinorContent.vue +92 -92
- package/app/components/aside/minor/topic/AsideMinorTopic.vue +32 -32
- package/app/components/aside/minor/topic/TopicContributors.vue +177 -177
- package/app/components/aside/minor/topic/TopicNav.vue +49 -49
- package/app/components/aside/minor/topic/TopicToc.vue +214 -214
- package/app/components/aside/minor/topic/TopicTocItem.vue +32 -32
- package/app/components/aside/utils/AsideOverlayPane.vue +40 -40
- package/app/components/bitran/BitranContent.vue +91 -91
- package/app/components/bitran/RenderWrapper.vue +10 -10
- package/app/components/contributor/ContributorAvatar.vue +45 -45
- package/app/components/contributor/ContributorListItem.vue +35 -35
- package/app/components/main/topic/MainTopic.vue +88 -78
- package/app/components/main/topic/TopicPartSwitch.vue +118 -118
- package/app/components/main/utils/Breadcrumb.vue +74 -70
- package/app/components/main/utils/ContentDecoration.vue +29 -29
- package/app/components/main/utils/ContentDescription.vue +19 -19
- package/app/components/main/utils/ContentPopover.vue +188 -188
- package/app/components/main/utils/ContentPopovers.vue +111 -111
- package/app/components/main/utils/ContentReferences.vue +70 -70
- package/app/components/main/utils/ContentSection.vue +45 -45
- package/app/components/main/utils/ContentTitle.vue +63 -63
- package/app/components/main/utils/reference/ReferenceGroup.vue +38 -38
- package/app/components/main/utils/reference/ReferenceItem.vue +70 -70
- package/app/components/main/utils/reference/ReferenceSource.vue +120 -118
- package/app/components/preview/Preview.vue +186 -186
- package/app/components/preview/PreviewDisplay.vue +139 -139
- package/app/components/preview/PreviewFooterAction.vue +73 -73
- package/app/components/preview/PreviewLoading.vue +14 -14
- package/app/components/preview/PreviewScreen.vue +141 -141
- package/app/components/preview/display/Alert.vue +50 -50
- package/app/components/preview/display/Custom.vue +18 -18
- package/app/components/preview/display/GenericLink.vue +48 -48
- package/app/components/preview/display/PageLink.vue +22 -20
- package/app/components/preview/display/Unique.vue +55 -55
- package/app/components/transition/Fade.vue +19 -19
- package/app/components/tree/TreeContainer.vue +11 -11
- package/app/components/tree/TreeItem.vue +89 -89
- package/app/composables/bitran.ts +108 -108
- package/app/composables/bitranContent.ts +92 -92
- package/app/composables/bitranLocation.ts +7 -7
- package/app/composables/contentData.ts +38 -38
- package/app/composables/contentPage.ts +158 -158
- package/app/composables/contentRoute.ts +45 -45
- package/app/composables/darkMagic.ts +24 -24
- package/app/composables/externalApi.ts +69 -63
- package/app/composables/favicon.ts +8 -8
- package/app/composables/formatText.ts +99 -99
- package/app/composables/majorPane.ts +60 -60
- package/app/composables/phrases.ts +65 -65
- package/app/composables/theme.ts +29 -29
- package/app/composables/url.ts +33 -33
- package/app/pages/_test/preview.vue +110 -110
- package/app/pages/article/[...articleId].vue +3 -3
- package/app/pages/book/[...bookId].vue +47 -47
- package/app/pages/group/[...groupId].vue +66 -64
- package/app/pages/index.vue +32 -32
- package/app/pages/members.vue +6 -6
- package/app/pages/practice/[...practice].vue +3 -3
- package/app/pages/summary/[...summaryId].vue +3 -3
- package/app/plugins/analytics.ts +87 -0
- package/app/plugins/prerender.server.ts +22 -22
- package/app/scripts/_immediate.js +9 -9
- package/app/scripts/aside/index.ts +59 -59
- package/app/scripts/aside/major/nav.ts +26 -26
- package/app/scripts/aside/minor/state.ts +37 -37
- package/app/scripts/aside/minor/topic.ts +3 -3
- package/app/scripts/flag.ts +28 -28
- package/app/scripts/og.ts +27 -27
- package/app/scripts/preview/build.ts +76 -76
- package/app/scripts/preview/data/alert.ts +19 -19
- package/app/scripts/preview/data/custom.ts +8 -8
- package/app/scripts/preview/data/genericLink.ts +24 -24
- package/app/scripts/preview/data/pageLink.ts +23 -23
- package/app/scripts/preview/data/unique.ts +72 -72
- package/app/scripts/preview/data.ts +24 -24
- package/app/scripts/preview/display.ts +37 -37
- package/app/scripts/preview/footer.ts +9 -9
- package/app/scripts/preview/request.ts +51 -51
- package/app/scripts/preview/state.ts +63 -63
- package/app/styles/_immediate.css +7 -7
- package/app/styles/_util.scss +43 -43
- package/app/styles/_utils.scss +44 -44
- package/app/styles/app.scss +91 -91
- package/app/styles/def/_bp.scss +27 -27
- package/app/styles/def/_size.scss +7 -7
- package/app/styles/def/_z.scss +5 -5
- package/app/styles/normalize.scss +49 -49
- package/app/styles/partials/_darkMagic.scss +5 -5
- package/app/styles/partials/_fnav.scss +15 -15
- package/app/styles/partials/_preview.scss +5 -5
- package/bin/erudit.mjs +2 -2
- package/const.ts +4 -4
- package/globalPath.ts +21 -21
- package/globals/bitran.ts +1 -1
- package/globals/content.ts +27 -27
- package/globals/contributor.ts +5 -5
- package/globals/erudit.ts +5 -5
- package/globals/register.ts +18 -18
- package/languages/en.ts +94 -94
- package/languages/ru.ts +98 -98
- package/module/bitran.ts +66 -66
- package/module/config.ts +35 -35
- package/module/imports.ts +67 -67
- package/module/index.ts +47 -49
- package/module/logger.ts +10 -10
- package/module/paths.ts +22 -22
- package/module/restart.ts +61 -61
- package/nuxt.config.ts +131 -134
- package/package.json +8 -7
- package/server/api/aside/major/nav/bookIds.ts +5 -5
- package/server/api/aside/major/nav/bookNav/[...bookId].ts +20 -20
- package/server/api/aside/major/nav/global.ts +7 -7
- package/server/api/aside/minor/news.ts +7 -7
- package/server/api/aside/minor/path.ts +82 -82
- package/server/api/bitran/content/[...location].ts +10 -10
- package/server/api/bitran/toc/[...location].ts +9 -9
- package/server/api/content/data.ts +75 -75
- package/server/api/contributor/count.ts +6 -6
- package/server/api/fake/content.ts +11 -11
- package/server/api/fake/shared/languages.ts +12 -12
- package/server/api/language/functions.ts +12 -12
- package/server/api/language/phrase/[phraseId].ts +19 -19
- package/server/api/language/phraseIds.ts +8 -8
- package/server/api/prerender.ts +120 -120
- package/server/api/preview/page/[...parts].ts +78 -78
- package/server/api/preview/unique/[...location].ts +61 -61
- package/server/api/problem/generator/[...path].ts +26 -0
- package/server/plugin/bitran/content.ts +190 -190
- package/server/plugin/bitran/elements/include.ts +229 -229
- package/server/plugin/bitran/location.ts +39 -39
- package/server/plugin/bitran/toc.ts +94 -94
- package/server/plugin/bitran/transpiler.ts +18 -18
- package/server/plugin/build/close.ts +12 -12
- package/server/plugin/build/jobs/content/builderArgs.ts +8 -8
- package/server/plugin/build/jobs/content/generic.ts +191 -191
- package/server/plugin/build/jobs/content/parse.ts +113 -113
- package/server/plugin/build/jobs/content/path.ts +6 -6
- package/server/plugin/build/jobs/content/type/book.ts +9 -9
- package/server/plugin/build/jobs/content/type/group.ts +37 -37
- package/server/plugin/build/jobs/content/type/topic.ts +36 -36
- package/server/plugin/build/jobs/contributors.ts +66 -66
- package/server/plugin/build/jobs/language.ts +36 -36
- package/server/plugin/build/jobs/nav.ts +345 -265
- package/server/plugin/build/process.ts +32 -32
- package/server/plugin/build/rebuild.ts +66 -66
- package/server/plugin/build/setup.ts +19 -19
- package/server/plugin/content/context.ts +119 -119
- package/server/plugin/db/entities/Book.ts +7 -7
- package/server/plugin/db/entities/Content.ts +45 -45
- package/server/plugin/db/entities/Contribution.ts +10 -10
- package/server/plugin/db/entities/Contributor.ts +16 -16
- package/server/plugin/db/entities/File.ts +10 -10
- package/server/plugin/db/entities/Group.ts +14 -14
- package/server/plugin/db/entities/Hash.ts +15 -15
- package/server/plugin/db/entities/Topic.ts +20 -20
- package/server/plugin/db/entities/Unique.ts +21 -21
- package/server/plugin/db/reset.ts +12 -12
- package/server/plugin/db/setup.ts +49 -49
- package/server/plugin/global.ts +16 -16
- package/server/plugin/importer.ts +16 -16
- package/server/plugin/index.ts +9 -9
- package/server/plugin/logger.ts +23 -23
- package/server/plugin/nav/node.ts +27 -27
- package/server/plugin/nav/utils.ts +175 -175
- package/server/plugin/repository/book.ts +21 -21
- package/server/plugin/repository/content.ts +240 -240
- package/server/plugin/repository/contentId.ts +40 -40
- package/server/plugin/repository/contributor.ts +8 -8
- package/server/plugin/repository/file.ts +10 -10
- package/server/plugin/repository/frontNav.ts +145 -145
- package/server/plugin/repository/topic.ts +35 -35
- package/server/tsconfig.json +9 -9
- package/shared/aside/minor.ts +51 -51
- package/shared/asset.ts +22 -22
- package/shared/bitran/contentId.ts +56 -56
- package/shared/bitran/stringContent.ts +6 -6
- package/shared/bitran/toc.ts +8 -8
- package/shared/content/bookId.ts +12 -12
- package/shared/content/context.ts +9 -9
- package/shared/content/data/base.ts +32 -32
- package/shared/content/data/index.ts +5 -5
- package/shared/content/data/type/book.ts +5 -5
- package/shared/content/data/type/group.ts +6 -6
- package/shared/content/data/type/topic.ts +11 -11
- package/shared/content/previousNext.ts +9 -9
- package/shared/contributor.ts +5 -5
- package/shared/frontNav.ts +41 -41
- package/shared/icons.ts +38 -38
- package/shared/image.ts +5 -5
- package/shared/link.ts +28 -28
- package/shared/popover.ts +8 -8
- package/shared/types/language.ts +74 -74
- package/shared/utils/objectsEqual.ts +4 -4
- package/shared/utils/stringColor.ts +9 -9
- package/test/contentId.test.ts +91 -91
- package/tsconfig.json +8 -8
- package/utils/contentPath.ts +67 -67
- package/utils/slash.ts +11 -11
- package/utils/stress.ts +9 -9
- package/app/components/ads/BannerTemplate.vue +0 -51
- package/app/components/ads/BottomBanner.vue +0 -45
- package/app/components/ads/LeftBanner.vue +0 -50
- package/module/problemGenerators.ts +0 -46
|
@@ -1,94 +1,94 @@
|
|
|
1
|
-
import { type ElementNode } from '@bitran-js/core';
|
|
2
|
-
import { NO_ALIASES, type BitranLocation } from '@erudit-js/cog/schema';
|
|
3
|
-
import {
|
|
4
|
-
headingName,
|
|
5
|
-
HeadingNode,
|
|
6
|
-
} from '@erudit-js/bitran-elements/heading/shared';
|
|
7
|
-
import {
|
|
8
|
-
ProblemNode,
|
|
9
|
-
ProblemsNode,
|
|
10
|
-
} from '@erudit-js/bitran-elements/problem/shared';
|
|
11
|
-
|
|
12
|
-
import type { Toc } from '@erudit/shared/bitran/toc';
|
|
13
|
-
import { ERUDIT_SERVER } from '@server/global';
|
|
14
|
-
import { getBitranContent } from './content';
|
|
15
|
-
import { createBitranTranspiler } from './transpiler';
|
|
16
|
-
|
|
17
|
-
export async function getBitranToc(location: BitranLocation) {
|
|
18
|
-
const content = await getBitranContent(location, false);
|
|
19
|
-
|
|
20
|
-
const bitranCore = await createBitranTranspiler({
|
|
21
|
-
eruditConfig: ERUDIT_SERVER.CONFIG,
|
|
22
|
-
insideInclude: false,
|
|
23
|
-
context: { aliases: NO_ALIASES(), location },
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
const toc: Toc = [];
|
|
27
|
-
|
|
28
|
-
await bitranCore.parser.parse(content.biCode, {
|
|
29
|
-
async step(node) {
|
|
30
|
-
tryAddToToc(node as ElementNode);
|
|
31
|
-
},
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
return toc;
|
|
35
|
-
|
|
36
|
-
function tryAddToToc(node: ElementNode) {
|
|
37
|
-
const tocItemBase = {
|
|
38
|
-
id: node.id,
|
|
39
|
-
productName: node.name,
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
// Check if node is manually excluded from TOC
|
|
43
|
-
if (typeof node.meta?.toc === 'boolean' && !node.meta?.toc) return;
|
|
44
|
-
|
|
45
|
-
if (node instanceof HeadingNode) {
|
|
46
|
-
toc.push({
|
|
47
|
-
...tocItemBase,
|
|
48
|
-
level: node.parseData.level - 1,
|
|
49
|
-
title: node.parseData.title,
|
|
50
|
-
});
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const notHeadingLevel = () => {
|
|
55
|
-
// If TOC is empty, we're at the root level
|
|
56
|
-
if (toc.length === 0) return 0;
|
|
57
|
-
|
|
58
|
-
// Find the most recent heading to determine parent level
|
|
59
|
-
for (let i = toc.length - 1; i >= 0; i--) {
|
|
60
|
-
if (toc[i].productName === headingName) {
|
|
61
|
-
// Found a heading, return its level + 1
|
|
62
|
-
return toc[i].level + 1;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// No heading found in TOC, place at root level
|
|
67
|
-
return 0;
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
// Problems by default are in TOC
|
|
71
|
-
if (node instanceof ProblemsNode || node instanceof ProblemNode) {
|
|
72
|
-
toc.push({
|
|
73
|
-
...tocItemBase,
|
|
74
|
-
level: notHeadingLevel(),
|
|
75
|
-
title: node.meta?.title || node.parseData.info.title,
|
|
76
|
-
});
|
|
77
|
-
return;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
if (
|
|
81
|
-
ERUDIT_SERVER.CONFIG.bitran?.toc?.includes(node.name) ||
|
|
82
|
-
node.meta?.toc
|
|
83
|
-
) {
|
|
84
|
-
// Erudit Bitran config says to add these products to TOC
|
|
85
|
-
// Or show in TOC any product with truthy `toc` meta property
|
|
86
|
-
toc.push({
|
|
87
|
-
...tocItemBase,
|
|
88
|
-
level: notHeadingLevel(),
|
|
89
|
-
title: node.meta?.title || node.parseData?.title,
|
|
90
|
-
});
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
}
|
|
1
|
+
import { type ElementNode } from '@bitran-js/core';
|
|
2
|
+
import { NO_ALIASES, type BitranLocation } from '@erudit-js/cog/schema';
|
|
3
|
+
import {
|
|
4
|
+
headingName,
|
|
5
|
+
HeadingNode,
|
|
6
|
+
} from '@erudit-js/bitran-elements/heading/shared';
|
|
7
|
+
import {
|
|
8
|
+
ProblemNode,
|
|
9
|
+
ProblemsNode,
|
|
10
|
+
} from '@erudit-js/bitran-elements/problem/shared';
|
|
11
|
+
|
|
12
|
+
import type { Toc } from '@erudit/shared/bitran/toc';
|
|
13
|
+
import { ERUDIT_SERVER } from '@server/global';
|
|
14
|
+
import { getBitranContent } from './content';
|
|
15
|
+
import { createBitranTranspiler } from './transpiler';
|
|
16
|
+
|
|
17
|
+
export async function getBitranToc(location: BitranLocation) {
|
|
18
|
+
const content = await getBitranContent(location, false);
|
|
19
|
+
|
|
20
|
+
const bitranCore = await createBitranTranspiler({
|
|
21
|
+
eruditConfig: ERUDIT_SERVER.CONFIG,
|
|
22
|
+
insideInclude: false,
|
|
23
|
+
context: { aliases: NO_ALIASES(), location },
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const toc: Toc = [];
|
|
27
|
+
|
|
28
|
+
await bitranCore.parser.parse(content.biCode, {
|
|
29
|
+
async step(node) {
|
|
30
|
+
tryAddToToc(node as ElementNode);
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
return toc;
|
|
35
|
+
|
|
36
|
+
function tryAddToToc(node: ElementNode) {
|
|
37
|
+
const tocItemBase = {
|
|
38
|
+
id: node.id,
|
|
39
|
+
productName: node.name,
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// Check if node is manually excluded from TOC
|
|
43
|
+
if (typeof node.meta?.toc === 'boolean' && !node.meta?.toc) return;
|
|
44
|
+
|
|
45
|
+
if (node instanceof HeadingNode) {
|
|
46
|
+
toc.push({
|
|
47
|
+
...tocItemBase,
|
|
48
|
+
level: node.parseData.level - 1,
|
|
49
|
+
title: node.parseData.title,
|
|
50
|
+
});
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const notHeadingLevel = () => {
|
|
55
|
+
// If TOC is empty, we're at the root level
|
|
56
|
+
if (toc.length === 0) return 0;
|
|
57
|
+
|
|
58
|
+
// Find the most recent heading to determine parent level
|
|
59
|
+
for (let i = toc.length - 1; i >= 0; i--) {
|
|
60
|
+
if (toc[i].productName === headingName) {
|
|
61
|
+
// Found a heading, return its level + 1
|
|
62
|
+
return toc[i].level + 1;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// No heading found in TOC, place at root level
|
|
67
|
+
return 0;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
// Problems by default are in TOC
|
|
71
|
+
if (node instanceof ProblemsNode || node instanceof ProblemNode) {
|
|
72
|
+
toc.push({
|
|
73
|
+
...tocItemBase,
|
|
74
|
+
level: notHeadingLevel(),
|
|
75
|
+
title: node.meta?.title || node.parseData.info.title,
|
|
76
|
+
});
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (
|
|
81
|
+
ERUDIT_SERVER.CONFIG.bitran?.toc?.includes(node.name) ||
|
|
82
|
+
node.meta?.toc
|
|
83
|
+
) {
|
|
84
|
+
// Erudit Bitran config says to add these products to TOC
|
|
85
|
+
// Or show in TOC any product with truthy `toc` meta property
|
|
86
|
+
toc.push({
|
|
87
|
+
...tocItemBase,
|
|
88
|
+
level: notHeadingLevel(),
|
|
89
|
+
title: node.meta?.title || node.parseData?.title,
|
|
90
|
+
});
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import { defineBitranTranspiler } from '@bitran-js/transpiler';
|
|
2
|
-
import {
|
|
3
|
-
setEruditBitranRuntime,
|
|
4
|
-
type EruditBitranRuntime,
|
|
5
|
-
} from '@erudit-js/cog/schema';
|
|
6
|
-
|
|
7
|
-
import getServerTranspilers from '#erudit/bitran/server';
|
|
8
|
-
|
|
9
|
-
export async function createBitranTranspiler(runtime: EruditBitranRuntime) {
|
|
10
|
-
const serverTranspiler = await getServerTranspilers();
|
|
11
|
-
const bitranTranspiler = defineBitranTranspiler(serverTranspiler);
|
|
12
|
-
|
|
13
|
-
[bitranTranspiler.parser, bitranTranspiler.stringifier].forEach((item) => {
|
|
14
|
-
setEruditBitranRuntime(item, runtime);
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
return bitranTranspiler;
|
|
18
|
-
}
|
|
1
|
+
import { defineBitranTranspiler } from '@bitran-js/transpiler';
|
|
2
|
+
import {
|
|
3
|
+
setEruditBitranRuntime,
|
|
4
|
+
type EruditBitranRuntime,
|
|
5
|
+
} from '@erudit-js/cog/schema';
|
|
6
|
+
|
|
7
|
+
import getServerTranspilers from '#erudit/bitran/server';
|
|
8
|
+
|
|
9
|
+
export async function createBitranTranspiler(runtime: EruditBitranRuntime) {
|
|
10
|
+
const serverTranspiler = await getServerTranspilers();
|
|
11
|
+
const bitranTranspiler = defineBitranTranspiler(serverTranspiler);
|
|
12
|
+
|
|
13
|
+
[bitranTranspiler.parser, bitranTranspiler.stringifier].forEach((item) => {
|
|
14
|
+
setEruditBitranRuntime(item, runtime);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
return bitranTranspiler;
|
|
18
|
+
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { debug, logger } from '@server/logger';
|
|
2
|
-
import { ERUDIT_SERVER } from '@server/global';
|
|
3
|
-
|
|
4
|
-
export async function close() {
|
|
5
|
-
debug.start('Shutting down server...');
|
|
6
|
-
|
|
7
|
-
if (ERUDIT_SERVER.DB && ERUDIT_SERVER.DB.isInitialized) {
|
|
8
|
-
await ERUDIT_SERVER.DB.destroy();
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
logger.success('Server shut down gracefully!');
|
|
12
|
-
}
|
|
1
|
+
import { debug, logger } from '@server/logger';
|
|
2
|
+
import { ERUDIT_SERVER } from '@server/global';
|
|
3
|
+
|
|
4
|
+
export async function close() {
|
|
5
|
+
debug.start('Shutting down server...');
|
|
6
|
+
|
|
7
|
+
if (ERUDIT_SERVER.DB && ERUDIT_SERVER.DB.isInitialized) {
|
|
8
|
+
await ERUDIT_SERVER.DB.destroy();
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
logger.success('Server shut down gracefully!');
|
|
12
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type { DbContent } from '@server/db/entities/Content';
|
|
2
|
-
import type { NavNode } from '@server/nav/node';
|
|
3
|
-
|
|
4
|
-
export interface BuilderFunctionArgs<T = any> {
|
|
5
|
-
navNode: NavNode;
|
|
6
|
-
dbContent: DbContent;
|
|
7
|
-
config?: Partial<T>;
|
|
8
|
-
}
|
|
1
|
+
import type { DbContent } from '@server/db/entities/Content';
|
|
2
|
+
import type { NavNode } from '@server/nav/node';
|
|
3
|
+
|
|
4
|
+
export interface BuilderFunctionArgs<T = any> {
|
|
5
|
+
navNode: NavNode;
|
|
6
|
+
dbContent: DbContent;
|
|
7
|
+
config?: Partial<T>;
|
|
8
|
+
}
|
|
@@ -1,191 +1,191 @@
|
|
|
1
|
-
import { existsSync } from 'node:fs';
|
|
2
|
-
import { globSync } from 'glob';
|
|
3
|
-
import chalk from 'chalk';
|
|
4
|
-
import { imageSizeFromFile } from 'image-size/fromFile';
|
|
5
|
-
import {
|
|
6
|
-
contentTypes,
|
|
7
|
-
type ContentConfig,
|
|
8
|
-
type ContentReferences,
|
|
9
|
-
type ContentType,
|
|
10
|
-
} from '@erudit-js/cog/schema';
|
|
11
|
-
import { resolvePaths } from '@erudit-js/cog/kit';
|
|
12
|
-
|
|
13
|
-
import { PROJECT_DIR } from '#erudit/globalPaths';
|
|
14
|
-
import { scanContentPaths } from '@erudit/utils/contentPath';
|
|
15
|
-
import { stress } from '@erudit/utils/stress';
|
|
16
|
-
|
|
17
|
-
import { debug, logger } from '@server/logger';
|
|
18
|
-
import { ERUDIT_SERVER } from '@server/global';
|
|
19
|
-
import { walkNav } from '@server/nav/utils';
|
|
20
|
-
import { isRootNode, type NavNode } from '@server/nav/node';
|
|
21
|
-
import { DbContent } from '@server/db/entities/Content';
|
|
22
|
-
import { IMPORT } from '@server/importer';
|
|
23
|
-
import { contributorExists } from '@server/repository/contributor';
|
|
24
|
-
import { DbContribution } from '@server/db/entities/Contribution';
|
|
25
|
-
import { DbFile } from '@server/db/entities/File';
|
|
26
|
-
|
|
27
|
-
import { contentAsset } from '@erudit/shared/asset';
|
|
28
|
-
import type { ImageData } from '@erudit/shared/image';
|
|
29
|
-
|
|
30
|
-
import type { BuilderFunctionArgs } from './builderArgs';
|
|
31
|
-
import { contentItemPath } from './path';
|
|
32
|
-
import { buildBook } from './type/book';
|
|
33
|
-
import { buildGroup } from './type/group';
|
|
34
|
-
import { buildTopic } from './type/topic';
|
|
35
|
-
|
|
36
|
-
const typeBuilders: Record<ContentType, Function> = {
|
|
37
|
-
book: buildBook,
|
|
38
|
-
group: buildGroup,
|
|
39
|
-
topic: buildTopic,
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
export async function buildContent() {
|
|
43
|
-
if (!ERUDIT_SERVER.NAV) return;
|
|
44
|
-
|
|
45
|
-
debug.start('Building content...');
|
|
46
|
-
|
|
47
|
-
await scanContentFiles();
|
|
48
|
-
|
|
49
|
-
const counters: Record<ContentType, number> = Object.fromEntries(
|
|
50
|
-
contentTypes.map((contentType) => [contentType, 0]),
|
|
51
|
-
) as any;
|
|
52
|
-
|
|
53
|
-
await walkNav(async (node) => {
|
|
54
|
-
if (isRootNode(node)) return;
|
|
55
|
-
counters[node.type]++;
|
|
56
|
-
await addContentItem(node);
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
logger.success(
|
|
60
|
-
'Content built successfully!',
|
|
61
|
-
chalk.dim(
|
|
62
|
-
'(' +
|
|
63
|
-
Object.entries(counters)
|
|
64
|
-
.map(([k, v]) => `${k.at(0)!.toUpperCase()}: ${v}`)
|
|
65
|
-
.join(', ') +
|
|
66
|
-
')',
|
|
67
|
-
),
|
|
68
|
-
);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
async function scanContentFiles() {
|
|
72
|
-
const contentFiles = scanContentPaths(PROJECT_DIR + '/content');
|
|
73
|
-
for (const [path, fullPath] of Object.entries(contentFiles)) {
|
|
74
|
-
const dbFile = new DbFile();
|
|
75
|
-
dbFile.path = path;
|
|
76
|
-
dbFile.fullPath = fullPath;
|
|
77
|
-
await ERUDIT_SERVER.DB.manager.save(dbFile);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
async function addContentItem(navNode: NavNode) {
|
|
82
|
-
debug.start(
|
|
83
|
-
`Adding ${stress(navNode.type)} content item ${stress(navNode.shortId)}...`,
|
|
84
|
-
);
|
|
85
|
-
|
|
86
|
-
const dbContent = new DbContent();
|
|
87
|
-
dbContent.contentId = navNode.fullId;
|
|
88
|
-
dbContent.type = navNode.type;
|
|
89
|
-
dbContent.decoration = getDecoration(navNode);
|
|
90
|
-
dbContent.ogImage = await getOgImageData(navNode);
|
|
91
|
-
dbContent.references = await getContentReferences(navNode);
|
|
92
|
-
|
|
93
|
-
let config: Partial<ContentConfig> | undefined;
|
|
94
|
-
|
|
95
|
-
try {
|
|
96
|
-
config = (await IMPORT(contentItemPath(navNode, navNode.type), {
|
|
97
|
-
default: true,
|
|
98
|
-
})) as Partial<ContentConfig>;
|
|
99
|
-
|
|
100
|
-
dbContent.title = config.title;
|
|
101
|
-
dbContent.navTitle = config.navTitle;
|
|
102
|
-
dbContent.description = config.description;
|
|
103
|
-
dbContent.flags = config.flags;
|
|
104
|
-
dbContent.dependencies = config.dependencies;
|
|
105
|
-
|
|
106
|
-
if (config.seo) {
|
|
107
|
-
dbContent.seo = {
|
|
108
|
-
title: config.seo?.title,
|
|
109
|
-
description: config.seo?.description,
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
await addContributions(navNode, config.contributors);
|
|
114
|
-
} catch {}
|
|
115
|
-
|
|
116
|
-
await ERUDIT_SERVER.DB.manager.save(dbContent);
|
|
117
|
-
|
|
118
|
-
await typeBuilders[navNode.type](<BuilderFunctionArgs>{
|
|
119
|
-
navNode,
|
|
120
|
-
dbContent,
|
|
121
|
-
config,
|
|
122
|
-
});
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
function getDecoration(navNode: NavNode) {
|
|
126
|
-
if (existsSync(contentItemPath(navNode, 'decoration.svg')))
|
|
127
|
-
return `/${navNode.
|
|
128
|
-
|
|
129
|
-
return undefined;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
async function addContributions(navNode: NavNode, contributors?: string[]) {
|
|
133
|
-
if (!contributors || !contributors.length) {
|
|
134
|
-
if (navNode.type !== 'book' && navNode.type !== 'group')
|
|
135
|
-
logger.warn(
|
|
136
|
-
`${navNode.type.at(0)!.toUpperCase() + navNode.type.slice(1)} ${stress(navNode.fullId)} has no contributors!`,
|
|
137
|
-
);
|
|
138
|
-
|
|
139
|
-
return;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
for (const contributorId of contributors) {
|
|
143
|
-
if (!(await contributorExists(contributorId))) {
|
|
144
|
-
logger.warn(
|
|
145
|
-
`Skipping unknown contributor ${stress(contributorId)} when adding ${navNode.type} ${stress(navNode.fullId)}!`,
|
|
146
|
-
);
|
|
147
|
-
continue;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
const dbContribution = new DbContribution();
|
|
151
|
-
dbContribution.contentId = navNode.fullId;
|
|
152
|
-
dbContribution.contributorId = contributorId;
|
|
153
|
-
await ERUDIT_SERVER.DB.manager.save(dbContribution);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
async function getOgImageData(
|
|
158
|
-
navNode: NavNode,
|
|
159
|
-
): Promise<ImageData | undefined> {
|
|
160
|
-
const ogImagePath = globSync(
|
|
161
|
-
contentItemPath(navNode, 'og-image.{svg,webp,jpg,png}'),
|
|
162
|
-
).pop();
|
|
163
|
-
|
|
164
|
-
if (ogImagePath) {
|
|
165
|
-
const size = await imageSizeFromFile(ogImagePath);
|
|
166
|
-
return {
|
|
167
|
-
src: contentAsset(
|
|
168
|
-
resolvePaths(ogImagePath).replace(
|
|
169
|
-
PROJECT_DIR + '/content/',
|
|
170
|
-
'',
|
|
171
|
-
),
|
|
172
|
-
),
|
|
173
|
-
width: size.width,
|
|
174
|
-
height: size.height,
|
|
175
|
-
};
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
return undefined;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
async function getContentReferences(navNode: NavNode) {
|
|
182
|
-
try {
|
|
183
|
-
const references = await IMPORT(
|
|
184
|
-
contentItemPath(navNode, `references`),
|
|
185
|
-
{ default: true },
|
|
186
|
-
);
|
|
187
|
-
return references as ContentReferences;
|
|
188
|
-
} catch (error) {}
|
|
189
|
-
|
|
190
|
-
return undefined;
|
|
191
|
-
}
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { globSync } from 'glob';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { imageSizeFromFile } from 'image-size/fromFile';
|
|
5
|
+
import {
|
|
6
|
+
contentTypes,
|
|
7
|
+
type ContentConfig,
|
|
8
|
+
type ContentReferences,
|
|
9
|
+
type ContentType,
|
|
10
|
+
} from '@erudit-js/cog/schema';
|
|
11
|
+
import { resolvePaths } from '@erudit-js/cog/kit';
|
|
12
|
+
|
|
13
|
+
import { PROJECT_DIR } from '#erudit/globalPaths';
|
|
14
|
+
import { scanContentPaths } from '@erudit/utils/contentPath';
|
|
15
|
+
import { stress } from '@erudit/utils/stress';
|
|
16
|
+
|
|
17
|
+
import { debug, logger } from '@server/logger';
|
|
18
|
+
import { ERUDIT_SERVER } from '@server/global';
|
|
19
|
+
import { walkNav } from '@server/nav/utils';
|
|
20
|
+
import { isRootNode, type NavNode } from '@server/nav/node';
|
|
21
|
+
import { DbContent } from '@server/db/entities/Content';
|
|
22
|
+
import { IMPORT } from '@server/importer';
|
|
23
|
+
import { contributorExists } from '@server/repository/contributor';
|
|
24
|
+
import { DbContribution } from '@server/db/entities/Contribution';
|
|
25
|
+
import { DbFile } from '@server/db/entities/File';
|
|
26
|
+
|
|
27
|
+
import { contentAsset } from '@erudit/shared/asset';
|
|
28
|
+
import type { ImageData } from '@erudit/shared/image';
|
|
29
|
+
|
|
30
|
+
import type { BuilderFunctionArgs } from './builderArgs';
|
|
31
|
+
import { contentItemPath } from './path';
|
|
32
|
+
import { buildBook } from './type/book';
|
|
33
|
+
import { buildGroup } from './type/group';
|
|
34
|
+
import { buildTopic } from './type/topic';
|
|
35
|
+
|
|
36
|
+
const typeBuilders: Record<ContentType, Function> = {
|
|
37
|
+
book: buildBook,
|
|
38
|
+
group: buildGroup,
|
|
39
|
+
topic: buildTopic,
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export async function buildContent() {
|
|
43
|
+
if (!ERUDIT_SERVER.NAV) return;
|
|
44
|
+
|
|
45
|
+
debug.start('Building content...');
|
|
46
|
+
|
|
47
|
+
await scanContentFiles();
|
|
48
|
+
|
|
49
|
+
const counters: Record<ContentType, number> = Object.fromEntries(
|
|
50
|
+
contentTypes.map((contentType) => [contentType, 0]),
|
|
51
|
+
) as any;
|
|
52
|
+
|
|
53
|
+
await walkNav(async (node) => {
|
|
54
|
+
if (isRootNode(node)) return;
|
|
55
|
+
counters[node.type]++;
|
|
56
|
+
await addContentItem(node);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
logger.success(
|
|
60
|
+
'Content built successfully!',
|
|
61
|
+
chalk.dim(
|
|
62
|
+
'(' +
|
|
63
|
+
Object.entries(counters)
|
|
64
|
+
.map(([k, v]) => `${k.at(0)!.toUpperCase()}: ${v}`)
|
|
65
|
+
.join(', ') +
|
|
66
|
+
')',
|
|
67
|
+
),
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async function scanContentFiles() {
|
|
72
|
+
const contentFiles = scanContentPaths(PROJECT_DIR + '/content');
|
|
73
|
+
for (const [path, fullPath] of Object.entries(contentFiles)) {
|
|
74
|
+
const dbFile = new DbFile();
|
|
75
|
+
dbFile.path = path;
|
|
76
|
+
dbFile.fullPath = fullPath;
|
|
77
|
+
await ERUDIT_SERVER.DB.manager.save(dbFile);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async function addContentItem(navNode: NavNode) {
|
|
82
|
+
debug.start(
|
|
83
|
+
`Adding ${stress(navNode.type)} content item ${stress(navNode.shortId)}...`,
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
const dbContent = new DbContent();
|
|
87
|
+
dbContent.contentId = navNode.fullId;
|
|
88
|
+
dbContent.type = navNode.type;
|
|
89
|
+
dbContent.decoration = getDecoration(navNode);
|
|
90
|
+
dbContent.ogImage = await getOgImageData(navNode);
|
|
91
|
+
dbContent.references = await getContentReferences(navNode);
|
|
92
|
+
|
|
93
|
+
let config: Partial<ContentConfig> | undefined;
|
|
94
|
+
|
|
95
|
+
try {
|
|
96
|
+
config = (await IMPORT(contentItemPath(navNode, navNode.type), {
|
|
97
|
+
default: true,
|
|
98
|
+
})) as Partial<ContentConfig>;
|
|
99
|
+
|
|
100
|
+
dbContent.title = config.title;
|
|
101
|
+
dbContent.navTitle = config.navTitle;
|
|
102
|
+
dbContent.description = config.description;
|
|
103
|
+
dbContent.flags = config.flags;
|
|
104
|
+
dbContent.dependencies = config.dependencies;
|
|
105
|
+
|
|
106
|
+
if (config.seo) {
|
|
107
|
+
dbContent.seo = {
|
|
108
|
+
title: config.seo?.title,
|
|
109
|
+
description: config.seo?.description,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
await addContributions(navNode, config.contributors);
|
|
114
|
+
} catch {}
|
|
115
|
+
|
|
116
|
+
await ERUDIT_SERVER.DB.manager.save(dbContent);
|
|
117
|
+
|
|
118
|
+
await typeBuilders[navNode.type](<BuilderFunctionArgs>{
|
|
119
|
+
navNode,
|
|
120
|
+
dbContent,
|
|
121
|
+
config,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function getDecoration(navNode: NavNode) {
|
|
126
|
+
if (existsSync(contentItemPath(navNode, 'decoration.svg')))
|
|
127
|
+
return `/${navNode.fsPath}/decoration.svg`;
|
|
128
|
+
|
|
129
|
+
return undefined;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
async function addContributions(navNode: NavNode, contributors?: string[]) {
|
|
133
|
+
if (!contributors || !contributors.length) {
|
|
134
|
+
if (navNode.type !== 'book' && navNode.type !== 'group')
|
|
135
|
+
logger.warn(
|
|
136
|
+
`${navNode.type.at(0)!.toUpperCase() + navNode.type.slice(1)} ${stress(navNode.fullId)} has no contributors!`,
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
for (const contributorId of contributors) {
|
|
143
|
+
if (!(await contributorExists(contributorId))) {
|
|
144
|
+
logger.warn(
|
|
145
|
+
`Skipping unknown contributor ${stress(contributorId)} when adding ${navNode.type} ${stress(navNode.fullId)}!`,
|
|
146
|
+
);
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const dbContribution = new DbContribution();
|
|
151
|
+
dbContribution.contentId = navNode.fullId;
|
|
152
|
+
dbContribution.contributorId = contributorId;
|
|
153
|
+
await ERUDIT_SERVER.DB.manager.save(dbContribution);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
async function getOgImageData(
|
|
158
|
+
navNode: NavNode,
|
|
159
|
+
): Promise<ImageData | undefined> {
|
|
160
|
+
const ogImagePath = globSync(
|
|
161
|
+
contentItemPath(navNode, 'og-image.{svg,webp,jpg,png}'),
|
|
162
|
+
).pop();
|
|
163
|
+
|
|
164
|
+
if (ogImagePath) {
|
|
165
|
+
const size = await imageSizeFromFile(ogImagePath);
|
|
166
|
+
return {
|
|
167
|
+
src: contentAsset(
|
|
168
|
+
resolvePaths(ogImagePath).replace(
|
|
169
|
+
PROJECT_DIR + '/content/',
|
|
170
|
+
'',
|
|
171
|
+
),
|
|
172
|
+
),
|
|
173
|
+
width: size.width,
|
|
174
|
+
height: size.height,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return undefined;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
async function getContentReferences(navNode: NavNode) {
|
|
182
|
+
try {
|
|
183
|
+
const references = await IMPORT(
|
|
184
|
+
contentItemPath(navNode, `references`),
|
|
185
|
+
{ default: true },
|
|
186
|
+
);
|
|
187
|
+
return references as ContentReferences;
|
|
188
|
+
} catch (error) {}
|
|
189
|
+
|
|
190
|
+
return undefined;
|
|
191
|
+
}
|