erudit 2.0.0-dev.9 → 3.0.0-dev.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/app/app.vue +172 -172
- package/app/components/Loading.vue +23 -23
- package/app/components/SiteAside.vue +382 -382
- package/app/components/SiteMain.vue +35 -35
- package/app/components/ads/BannerTemplate.vue +51 -51
- package/app/components/ads/BottomBanner.vue +45 -45
- package/app/components/ads/LeftBanner.vue +50 -50
- package/app/components/aside/AsideListItem.vue +74 -74
- package/app/components/aside/AsideMajor.vue +56 -56
- package/app/components/aside/AsideMinor.vue +71 -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 -3
- package/app/components/aside/major/panes/nav/Nav.vue +91 -91
- package/app/components/aside/major/panes/nav/NavBook.vue +86 -86
- 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 +15 -15
- 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 -16
- 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 +203 -203
- package/app/components/aside/minor/topic/TopicTocItem.vue +31 -31
- package/app/components/aside/utils/AsideOverlayPane.vue +40 -40
- package/app/components/bitran/BitranContent.vue +63 -63
- package/app/components/bitran/RenderWrapper.vue +10 -10
- package/app/components/contributor/ContributorAvatar.vue +43 -43
- package/app/components/contributor/ContributorListItem.vue +35 -35
- package/app/components/main/topic/MainTopic.vue +79 -79
- package/app/components/main/topic/TopicPartSwitch.vue +118 -118
- package/app/components/main/utils/Breadcrumb.vue +75 -75
- package/app/components/main/utils/ContentDecoration.vue +29 -29
- package/app/components/main/utils/ContentDescription.vue +19 -20
- package/app/components/main/utils/ContentFlag.vue +15 -16
- package/app/components/main/utils/ContentPopover.vue +176 -176
- package/app/components/main/utils/ContentPopovers.vue +105 -105
- package/app/components/main/utils/ContentReferences.vue +70 -76
- package/app/components/main/utils/ContentSection.vue +45 -42
- package/app/components/main/utils/ContentTitle.vue +39 -37
- package/app/components/main/utils/reference/ReferenceGroup.vue +38 -41
- package/app/components/main/utils/reference/ReferenceItem.vue +68 -64
- package/app/components/main/utils/reference/ReferenceSource.vue +116 -110
- package/app/components/preview/Preview.vue +177 -177
- package/app/components/preview/PreviewDisplay.vue +139 -139
- package/app/components/preview/PreviewFooterAction.vue +73 -73
- package/app/components/preview/PreviewLoading.vue +14 -15
- package/app/components/preview/PreviewScreen.vue +99 -99
- 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 +20 -20
- package/app/components/preview/display/Unique.vue +49 -49
- package/app/components/transition/Fade.vue +19 -22
- package/app/components/tree/TreeContainer.vue +11 -12
- package/app/components/tree/TreeItem.vue +89 -89
- package/app/composables/bitran.ts +127 -127
- package/app/composables/bitranContent.ts +37 -37
- package/app/composables/bitranLocation.ts +7 -7
- package/app/composables/contentData.ts +36 -36
- package/app/composables/contentPage.ts +156 -156
- package/app/composables/contentRoute.ts +45 -45
- package/app/composables/darkMagic.ts +24 -24
- package/app/composables/externalApi.ts +63 -63
- package/app/composables/favicon.ts +8 -8
- package/app/composables/formatText.ts +86 -86
- package/app/composables/majorPane.ts +60 -60
- package/app/composables/phrases.ts +80 -80
- 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 +65 -65
- package/app/pages/index.vue +32 -32
- package/app/pages/members.vue +6 -7
- package/app/pages/practice/[...practice].vue +3 -3
- package/app/pages/summary/[...summaryId].vue +3 -3
- package/app/scripts/_immediate.js +9 -4
- 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 +73 -84
- 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 +20 -20
- package/app/scripts/preview/data/unique.ts +70 -70
- package/app/scripts/preview/data.ts +24 -26
- 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 -3
- package/app/styles/_util.scss +43 -50
- package/app/styles/_utils.scss +44 -44
- package/app/styles/app.scss +91 -91
- package/app/styles/def/_bp.scss +27 -24
- package/app/styles/def/_size.scss +7 -7
- package/app/styles/def/_z.scss +5 -5
- package/app/styles/default.scss +83 -85
- package/app/styles/normalize.scss +63 -63
- package/app/styles/partials/_darkMagic.scss +5 -7
- package/app/styles/partials/_fnav.scss +15 -18
- package/app/styles/partials/_preview.scss +5 -7
- package/globalPath.ts +21 -21
- package/globals/bitran.ts +47 -47
- package/globals/content.ts +22 -22
- package/globals/contributor.ts +5 -5
- package/globals/erudit.ts +5 -5
- package/globals/register.ts +18 -18
- package/languages/en.ts +95 -95
- package/languages/ru.ts +99 -99
- package/module/bitran.ts +34 -34
- package/module/config.ts +34 -34
- package/module/imports.ts +46 -46
- package/module/index.ts +47 -47
- package/module/logger.ts +10 -10
- package/module/paths.ts +22 -22
- package/module/restart.ts +61 -61
- package/nuxt.config.ts +112 -107
- package/package.json +3 -3
- 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 +78 -78
- package/server/api/bitran/content/[location].ts +7 -7
- package/server/api/bitran/toc/[location].ts +7 -7
- package/server/api/content/data.ts +72 -72
- 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/preview/page/[...parts].ts +51 -51
- package/server/api/preview/unique/[location].ts +55 -55
- package/server/plugin/bitran/content.ts +187 -187
- package/server/plugin/bitran/location.ts +25 -25
- package/server/plugin/bitran/products/include.ts +230 -230
- package/server/plugin/bitran/products/link.ts +116 -116
- package/server/plugin/bitran/setup.ts +9 -9
- package/server/plugin/bitran/toc.ts +83 -83
- package/server/plugin/bitran/transpiler.ts +46 -46
- package/server/plugin/build/close.ts +10 -10
- package/server/plugin/build/jobs/content/builderArgs.ts +8 -8
- package/server/plugin/build/jobs/content/generic.ts +176 -176
- package/server/plugin/build/jobs/content/parse.ts +100 -100
- 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 +210 -209
- package/server/plugin/build/process.ts +25 -25
- package/server/plugin/build/rebuild.ts +55 -55
- package/server/plugin/build/setup.ts +21 -21
- package/server/plugin/content/absoluteId.ts +94 -94
- package/server/plugin/content/context.ts +112 -112
- package/server/plugin/db/entities/Book.ts +7 -7
- package/server/plugin/db/entities/Content.ts +49 -49
- package/server/plugin/db/entities/Contribution.ts +10 -10
- package/server/plugin/db/entities/Contributor.ts +16 -16
- 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/setup.ts +34 -34
- package/server/plugin/global.ts +18 -18
- package/server/plugin/importer.ts +12 -12
- package/server/plugin/index.ts +9 -9
- package/server/plugin/logger.ts +23 -23
- package/server/plugin/nav/node.ts +26 -26
- package/server/plugin/nav/utils.ts +129 -129
- package/server/plugin/repository/book.ts +21 -21
- package/server/plugin/repository/content.ts +238 -238
- package/server/plugin/repository/contributor.ts +8 -8
- package/server/plugin/repository/frontNav.ts +148 -148
- package/server/plugin/repository/topic.ts +32 -32
- package/server/tsconfig.json +9 -7
- package/shared/aside/minor.ts +50 -50
- package/shared/asset.ts +15 -15
- package/shared/bitran/context.ts +8 -8
- package/shared/bitran/default.ts +46 -46
- package/shared/bitran/link/Link.vue +167 -167
- package/shared/bitran/link/factory.ts +24 -24
- package/shared/bitran/link/languages/en.ts +7 -7
- package/shared/bitran/link/languages/ru.ts +7 -7
- package/shared/bitran/link/renderer.ts +21 -21
- package/shared/bitran/link/shared.ts +17 -17
- package/shared/bitran/link/target.ts +134 -134
- package/shared/bitran/link/transpiler.ts +10 -10
- package/shared/bitran/location.ts +166 -166
- package/shared/bitran/toc.ts +8 -8
- 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 +25 -25
- package/shared/types/language.ts +75 -75
- package/shared/utils/objectsEqual.ts +4 -4
- package/shared/utils/stringColor.ts +9 -9
- package/test/bitran/link/target.test.ts +141 -141
- package/test/bitran/location.test.ts +143 -143
- package/tsconfig.json +8 -8
- package/utils/stress.ts +9 -9
|
@@ -1,176 +1,176 @@
|
|
|
1
|
-
import { existsSync } from 'node:fs';
|
|
2
|
-
import { globSync } from 'glob';
|
|
3
|
-
import chalk from 'chalk';
|
|
4
|
-
import sizeOf from 'image-size';
|
|
5
|
-
import {
|
|
6
|
-
contentTypes,
|
|
7
|
-
type ContentConfig,
|
|
8
|
-
type ContentReferences,
|
|
9
|
-
type ContentType,
|
|
10
|
-
} from 'erudit-cog/schema';
|
|
11
|
-
import { resolvePaths } from 'erudit-cog/kit';
|
|
12
|
-
|
|
13
|
-
import { PROJECT_DIR } from '#erudit/globalPaths';
|
|
14
|
-
import { stress } from '@erudit/utils/stress';
|
|
15
|
-
|
|
16
|
-
import { debug, logger } from '@server/logger';
|
|
17
|
-
import { ERUDIT_SERVER } from '@server/global';
|
|
18
|
-
import { walkNav } from '@server/nav/utils';
|
|
19
|
-
import { isRootNode, type NavNode } from '@server/nav/node';
|
|
20
|
-
import { DbContent } from '@server/db/entities/Content';
|
|
21
|
-
import { IMPORT } from '@server/importer';
|
|
22
|
-
import { contributorExists } from '@server/repository/contributor';
|
|
23
|
-
import { DbContribution } from '@server/db/entities/Contribution';
|
|
24
|
-
|
|
25
|
-
import { contentAsset } from '@erudit/shared/asset';
|
|
26
|
-
import type { ImageData } from '@erudit/shared/image';
|
|
27
|
-
|
|
28
|
-
import type { BuilderFunctionArgs } from './builderArgs';
|
|
29
|
-
import { contentItemPath } from './path';
|
|
30
|
-
import { buildBook } from './type/book';
|
|
31
|
-
import { buildGroup } from './type/group';
|
|
32
|
-
import { buildTopic } from './type/topic';
|
|
33
|
-
|
|
34
|
-
const typeBuilders: Record<ContentType, Function> = {
|
|
35
|
-
book: buildBook,
|
|
36
|
-
group: buildGroup,
|
|
37
|
-
topic: buildTopic,
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
export async function buildContent() {
|
|
41
|
-
if (!ERUDIT_SERVER.NAV) return;
|
|
42
|
-
|
|
43
|
-
debug.start('Building content...');
|
|
44
|
-
|
|
45
|
-
const counters: Record<ContentType, number> = Object.fromEntries(
|
|
46
|
-
contentTypes.map((contentType) => [contentType, 0]),
|
|
47
|
-
) as any;
|
|
48
|
-
|
|
49
|
-
await walkNav(async (node) => {
|
|
50
|
-
if (isRootNode(node)) return;
|
|
51
|
-
counters[node.type]++;
|
|
52
|
-
await addContentItem(node);
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
logger.success(
|
|
56
|
-
'Content built successfully!',
|
|
57
|
-
chalk.dim(
|
|
58
|
-
'(' +
|
|
59
|
-
Object.entries(counters)
|
|
60
|
-
.map(([k, v]) => `${k.at(0)!.toUpperCase()}: ${v}`)
|
|
61
|
-
.join(', ') +
|
|
62
|
-
')',
|
|
63
|
-
),
|
|
64
|
-
);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
async function addContentItem(navNode: NavNode) {
|
|
68
|
-
debug.start(
|
|
69
|
-
`Adding ${stress(navNode.type)} content item ${stress(navNode.id)}...`,
|
|
70
|
-
);
|
|
71
|
-
|
|
72
|
-
const dbContent = new DbContent();
|
|
73
|
-
dbContent.contentId = navNode.id;
|
|
74
|
-
dbContent.fullId = navNode.fullId;
|
|
75
|
-
dbContent.type = navNode.type;
|
|
76
|
-
dbContent.decoration = getDecoration(navNode);
|
|
77
|
-
dbContent.ogImage = getOgImageData(navNode);
|
|
78
|
-
dbContent.references = await getContentReferences(navNode);
|
|
79
|
-
|
|
80
|
-
let config: Partial<ContentConfig> | undefined;
|
|
81
|
-
|
|
82
|
-
try {
|
|
83
|
-
config = (await IMPORT(contentItemPath(navNode, navNode.type), {
|
|
84
|
-
default: true,
|
|
85
|
-
})) as Partial<ContentConfig>;
|
|
86
|
-
|
|
87
|
-
dbContent.title = config.title;
|
|
88
|
-
dbContent.navTitle = config.navTitle;
|
|
89
|
-
dbContent.description = config.description;
|
|
90
|
-
dbContent.flags = config.flags;
|
|
91
|
-
dbContent.dependencies = config.dependencies;
|
|
92
|
-
|
|
93
|
-
if (config.seo) {
|
|
94
|
-
dbContent.seo = {
|
|
95
|
-
title: config.seo?.title,
|
|
96
|
-
description: config.seo?.description,
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
await addContributions(navNode, config.contributors);
|
|
101
|
-
} catch {}
|
|
102
|
-
|
|
103
|
-
await ERUDIT_SERVER.DB.manager.save(dbContent);
|
|
104
|
-
|
|
105
|
-
await typeBuilders[navNode.type](<BuilderFunctionArgs>{
|
|
106
|
-
navNode,
|
|
107
|
-
dbContent,
|
|
108
|
-
config,
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
function getDecoration(navNode: NavNode) {
|
|
113
|
-
if (existsSync(contentItemPath(navNode, 'decoration.svg')))
|
|
114
|
-
return `/${navNode.path}/decoration.svg`;
|
|
115
|
-
|
|
116
|
-
return undefined;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
async function addContributions(navNode: NavNode, contributors?: string[]) {
|
|
120
|
-
if (!contributors || !contributors.length) {
|
|
121
|
-
if (navNode.type !== 'book' && navNode.type !== 'group')
|
|
122
|
-
logger.warn(
|
|
123
|
-
`${navNode.type.at(0)!.toUpperCase() + navNode.type.slice(1)} ${stress(navNode.id)} has no contributors!`,
|
|
124
|
-
);
|
|
125
|
-
|
|
126
|
-
return;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
for (const contributorId of contributors) {
|
|
130
|
-
if (!(await contributorExists(contributorId))) {
|
|
131
|
-
logger.warn(
|
|
132
|
-
`Skipping unknown contributor ${stress(contributorId)} when adding ${navNode.type} ${stress(navNode.id)}!`,
|
|
133
|
-
);
|
|
134
|
-
continue;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
const dbContribution = new DbContribution();
|
|
138
|
-
dbContribution.contentId = navNode.id;
|
|
139
|
-
dbContribution.contributorId = contributorId;
|
|
140
|
-
await ERUDIT_SERVER.DB.manager.save(dbContribution);
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
function getOgImageData(navNode: NavNode): ImageData | undefined {
|
|
145
|
-
const ogImagePath = globSync(
|
|
146
|
-
contentItemPath(navNode, 'og-image.{svg,webp,jpg,png}'),
|
|
147
|
-
).pop();
|
|
148
|
-
|
|
149
|
-
if (ogImagePath) {
|
|
150
|
-
const size = sizeOf(ogImagePath);
|
|
151
|
-
return {
|
|
152
|
-
src: contentAsset(
|
|
153
|
-
resolvePaths(ogImagePath).replace(
|
|
154
|
-
PROJECT_DIR + '/content/',
|
|
155
|
-
'',
|
|
156
|
-
),
|
|
157
|
-
),
|
|
158
|
-
width: size.width!,
|
|
159
|
-
height: size.height!,
|
|
160
|
-
};
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
return undefined;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
async function getContentReferences(navNode: NavNode) {
|
|
167
|
-
try {
|
|
168
|
-
const references = await IMPORT(
|
|
169
|
-
contentItemPath(navNode, `references`),
|
|
170
|
-
{ default: true },
|
|
171
|
-
);
|
|
172
|
-
return references as ContentReferences;
|
|
173
|
-
} catch (error) {}
|
|
174
|
-
|
|
175
|
-
return undefined;
|
|
176
|
-
}
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { globSync } from 'glob';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import sizeOf from 'image-size';
|
|
5
|
+
import {
|
|
6
|
+
contentTypes,
|
|
7
|
+
type ContentConfig,
|
|
8
|
+
type ContentReferences,
|
|
9
|
+
type ContentType,
|
|
10
|
+
} from 'erudit-cog/schema';
|
|
11
|
+
import { resolvePaths } from 'erudit-cog/kit';
|
|
12
|
+
|
|
13
|
+
import { PROJECT_DIR } from '#erudit/globalPaths';
|
|
14
|
+
import { stress } from '@erudit/utils/stress';
|
|
15
|
+
|
|
16
|
+
import { debug, logger } from '@server/logger';
|
|
17
|
+
import { ERUDIT_SERVER } from '@server/global';
|
|
18
|
+
import { walkNav } from '@server/nav/utils';
|
|
19
|
+
import { isRootNode, type NavNode } from '@server/nav/node';
|
|
20
|
+
import { DbContent } from '@server/db/entities/Content';
|
|
21
|
+
import { IMPORT } from '@server/importer';
|
|
22
|
+
import { contributorExists } from '@server/repository/contributor';
|
|
23
|
+
import { DbContribution } from '@server/db/entities/Contribution';
|
|
24
|
+
|
|
25
|
+
import { contentAsset } from '@erudit/shared/asset';
|
|
26
|
+
import type { ImageData } from '@erudit/shared/image';
|
|
27
|
+
|
|
28
|
+
import type { BuilderFunctionArgs } from './builderArgs';
|
|
29
|
+
import { contentItemPath } from './path';
|
|
30
|
+
import { buildBook } from './type/book';
|
|
31
|
+
import { buildGroup } from './type/group';
|
|
32
|
+
import { buildTopic } from './type/topic';
|
|
33
|
+
|
|
34
|
+
const typeBuilders: Record<ContentType, Function> = {
|
|
35
|
+
book: buildBook,
|
|
36
|
+
group: buildGroup,
|
|
37
|
+
topic: buildTopic,
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export async function buildContent() {
|
|
41
|
+
if (!ERUDIT_SERVER.NAV) return;
|
|
42
|
+
|
|
43
|
+
debug.start('Building content...');
|
|
44
|
+
|
|
45
|
+
const counters: Record<ContentType, number> = Object.fromEntries(
|
|
46
|
+
contentTypes.map((contentType) => [contentType, 0]),
|
|
47
|
+
) as any;
|
|
48
|
+
|
|
49
|
+
await walkNav(async (node) => {
|
|
50
|
+
if (isRootNode(node)) return;
|
|
51
|
+
counters[node.type]++;
|
|
52
|
+
await addContentItem(node);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
logger.success(
|
|
56
|
+
'Content built successfully!',
|
|
57
|
+
chalk.dim(
|
|
58
|
+
'(' +
|
|
59
|
+
Object.entries(counters)
|
|
60
|
+
.map(([k, v]) => `${k.at(0)!.toUpperCase()}: ${v}`)
|
|
61
|
+
.join(', ') +
|
|
62
|
+
')',
|
|
63
|
+
),
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async function addContentItem(navNode: NavNode) {
|
|
68
|
+
debug.start(
|
|
69
|
+
`Adding ${stress(navNode.type)} content item ${stress(navNode.id)}...`,
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
const dbContent = new DbContent();
|
|
73
|
+
dbContent.contentId = navNode.id;
|
|
74
|
+
dbContent.fullId = navNode.fullId;
|
|
75
|
+
dbContent.type = navNode.type;
|
|
76
|
+
dbContent.decoration = getDecoration(navNode);
|
|
77
|
+
dbContent.ogImage = getOgImageData(navNode);
|
|
78
|
+
dbContent.references = await getContentReferences(navNode);
|
|
79
|
+
|
|
80
|
+
let config: Partial<ContentConfig> | undefined;
|
|
81
|
+
|
|
82
|
+
try {
|
|
83
|
+
config = (await IMPORT(contentItemPath(navNode, navNode.type), {
|
|
84
|
+
default: true,
|
|
85
|
+
})) as Partial<ContentConfig>;
|
|
86
|
+
|
|
87
|
+
dbContent.title = config.title;
|
|
88
|
+
dbContent.navTitle = config.navTitle;
|
|
89
|
+
dbContent.description = config.description;
|
|
90
|
+
dbContent.flags = config.flags;
|
|
91
|
+
dbContent.dependencies = config.dependencies;
|
|
92
|
+
|
|
93
|
+
if (config.seo) {
|
|
94
|
+
dbContent.seo = {
|
|
95
|
+
title: config.seo?.title,
|
|
96
|
+
description: config.seo?.description,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
await addContributions(navNode, config.contributors);
|
|
101
|
+
} catch {}
|
|
102
|
+
|
|
103
|
+
await ERUDIT_SERVER.DB.manager.save(dbContent);
|
|
104
|
+
|
|
105
|
+
await typeBuilders[navNode.type](<BuilderFunctionArgs>{
|
|
106
|
+
navNode,
|
|
107
|
+
dbContent,
|
|
108
|
+
config,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function getDecoration(navNode: NavNode) {
|
|
113
|
+
if (existsSync(contentItemPath(navNode, 'decoration.svg')))
|
|
114
|
+
return `/${navNode.path}/decoration.svg`;
|
|
115
|
+
|
|
116
|
+
return undefined;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
async function addContributions(navNode: NavNode, contributors?: string[]) {
|
|
120
|
+
if (!contributors || !contributors.length) {
|
|
121
|
+
if (navNode.type !== 'book' && navNode.type !== 'group')
|
|
122
|
+
logger.warn(
|
|
123
|
+
`${navNode.type.at(0)!.toUpperCase() + navNode.type.slice(1)} ${stress(navNode.id)} has no contributors!`,
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
for (const contributorId of contributors) {
|
|
130
|
+
if (!(await contributorExists(contributorId))) {
|
|
131
|
+
logger.warn(
|
|
132
|
+
`Skipping unknown contributor ${stress(contributorId)} when adding ${navNode.type} ${stress(navNode.id)}!`,
|
|
133
|
+
);
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const dbContribution = new DbContribution();
|
|
138
|
+
dbContribution.contentId = navNode.id;
|
|
139
|
+
dbContribution.contributorId = contributorId;
|
|
140
|
+
await ERUDIT_SERVER.DB.manager.save(dbContribution);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function getOgImageData(navNode: NavNode): ImageData | undefined {
|
|
145
|
+
const ogImagePath = globSync(
|
|
146
|
+
contentItemPath(navNode, 'og-image.{svg,webp,jpg,png}'),
|
|
147
|
+
).pop();
|
|
148
|
+
|
|
149
|
+
if (ogImagePath) {
|
|
150
|
+
const size = sizeOf(ogImagePath);
|
|
151
|
+
return {
|
|
152
|
+
src: contentAsset(
|
|
153
|
+
resolvePaths(ogImagePath).replace(
|
|
154
|
+
PROJECT_DIR + '/content/',
|
|
155
|
+
'',
|
|
156
|
+
),
|
|
157
|
+
),
|
|
158
|
+
width: size.width!,
|
|
159
|
+
height: size.height!,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return undefined;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
async function getContentReferences(navNode: NavNode) {
|
|
167
|
+
try {
|
|
168
|
+
const references = await IMPORT(
|
|
169
|
+
contentItemPath(navNode, `references`),
|
|
170
|
+
{ default: true },
|
|
171
|
+
);
|
|
172
|
+
return references as ContentReferences;
|
|
173
|
+
} catch (error) {}
|
|
174
|
+
|
|
175
|
+
return undefined;
|
|
176
|
+
}
|
|
@@ -1,100 +1,100 @@
|
|
|
1
|
-
import { ElementNode, walkForward } from '@bitran-js/core';
|
|
2
|
-
import { type BitranTranspiler } from '@bitran-js/transpiler';
|
|
3
|
-
import {
|
|
4
|
-
AliasesNode,
|
|
5
|
-
mergeAliases,
|
|
6
|
-
NO_ALIASES,
|
|
7
|
-
} from '@erudit-js/bitran-elements/aliases/shared';
|
|
8
|
-
import { HeadingNode } from '@erudit-js/bitran-elements/heading/shared';
|
|
9
|
-
|
|
10
|
-
import { createBitranTranspiler } from '@server/bitran/transpiler';
|
|
11
|
-
import { ERUDIT_SERVER } from '@server/global';
|
|
12
|
-
import { DbUnique } from '@server/db/entities/Unique';
|
|
13
|
-
|
|
14
|
-
import type { BitranContext } from '@shared/bitran/context';
|
|
15
|
-
import {
|
|
16
|
-
stringifyBitranLocation,
|
|
17
|
-
type BitranLocation,
|
|
18
|
-
} from '@shared/bitran/location';
|
|
19
|
-
|
|
20
|
-
let context: BitranContext = {} as any;
|
|
21
|
-
let bitranTranspiler: BitranTranspiler;
|
|
22
|
-
|
|
23
|
-
const blocksAfterHeading = 2;
|
|
24
|
-
|
|
25
|
-
export async function parseBitranContent(
|
|
26
|
-
location: BitranLocation,
|
|
27
|
-
biCode: string,
|
|
28
|
-
) {
|
|
29
|
-
// Reset Bitran context in order not to create core each time
|
|
30
|
-
context.location = location;
|
|
31
|
-
context.aliases = NO_ALIASES();
|
|
32
|
-
|
|
33
|
-
bitranTranspiler ||= await createBitranTranspiler();
|
|
34
|
-
|
|
35
|
-
// Tracking heading nodes to deal with them later
|
|
36
|
-
const headings: HeadingNode[] = [];
|
|
37
|
-
|
|
38
|
-
await bitranTranspiler.parser.parse(biCode, {
|
|
39
|
-
async step(node) {
|
|
40
|
-
const meta = node.meta;
|
|
41
|
-
const uniqueId = meta?.id;
|
|
42
|
-
|
|
43
|
-
if (node instanceof AliasesNode) {
|
|
44
|
-
mergeAliases(context.aliases, node.parseData);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
if (uniqueId) {
|
|
48
|
-
if (node instanceof HeadingNode) {
|
|
49
|
-
headings.push(node);
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
await addUnique(node);
|
|
54
|
-
}
|
|
55
|
-
},
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
for (const heading of headings) {
|
|
59
|
-
let blocksAfter = 0;
|
|
60
|
-
let content = await bitranTranspiler.stringifier.stringify(heading);
|
|
61
|
-
|
|
62
|
-
await walkForward(heading, async (node) => {
|
|
63
|
-
if (blocksAfter >= blocksAfterHeading) return false;
|
|
64
|
-
|
|
65
|
-
if (node instanceof AliasesNode) return;
|
|
66
|
-
// Spoiler
|
|
67
|
-
// Todo
|
|
68
|
-
|
|
69
|
-
content +=
|
|
70
|
-
'\n\n' + (await bitranTranspiler.stringifier.stringify(node));
|
|
71
|
-
|
|
72
|
-
blocksAfter++;
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
await addUnique(heading, content);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
//
|
|
79
|
-
//
|
|
80
|
-
//
|
|
81
|
-
|
|
82
|
-
function createUniqueLocation(node: ElementNode) {
|
|
83
|
-
return stringifyBitranLocation({
|
|
84
|
-
...location,
|
|
85
|
-
...{ unique: node.meta.id! },
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
async function addUnique(node: ElementNode, content?: string) {
|
|
90
|
-
const dbUnique = new DbUnique();
|
|
91
|
-
dbUnique.location = createUniqueLocation(node);
|
|
92
|
-
dbUnique.content =
|
|
93
|
-
content || (await bitranTranspiler.stringifier.stringify(node));
|
|
94
|
-
dbUnique.title = node.parseData?.title || node.meta?.title;
|
|
95
|
-
dbUnique.productName = node.name;
|
|
96
|
-
dbUnique.context = context;
|
|
97
|
-
|
|
98
|
-
await ERUDIT_SERVER.DB.manager.save(dbUnique);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
1
|
+
import { ElementNode, walkForward } from '@bitran-js/core';
|
|
2
|
+
import { type BitranTranspiler } from '@bitran-js/transpiler';
|
|
3
|
+
import {
|
|
4
|
+
AliasesNode,
|
|
5
|
+
mergeAliases,
|
|
6
|
+
NO_ALIASES,
|
|
7
|
+
} from '@erudit-js/bitran-elements/aliases/shared';
|
|
8
|
+
import { HeadingNode } from '@erudit-js/bitran-elements/heading/shared';
|
|
9
|
+
|
|
10
|
+
import { createBitranTranspiler } from '@server/bitran/transpiler';
|
|
11
|
+
import { ERUDIT_SERVER } from '@server/global';
|
|
12
|
+
import { DbUnique } from '@server/db/entities/Unique';
|
|
13
|
+
|
|
14
|
+
import type { BitranContext } from '@shared/bitran/context';
|
|
15
|
+
import {
|
|
16
|
+
stringifyBitranLocation,
|
|
17
|
+
type BitranLocation,
|
|
18
|
+
} from '@shared/bitran/location';
|
|
19
|
+
|
|
20
|
+
let context: BitranContext = {} as any;
|
|
21
|
+
let bitranTranspiler: BitranTranspiler;
|
|
22
|
+
|
|
23
|
+
const blocksAfterHeading = 2;
|
|
24
|
+
|
|
25
|
+
export async function parseBitranContent(
|
|
26
|
+
location: BitranLocation,
|
|
27
|
+
biCode: string,
|
|
28
|
+
) {
|
|
29
|
+
// Reset Bitran context in order not to create core each time
|
|
30
|
+
context.location = location;
|
|
31
|
+
context.aliases = NO_ALIASES();
|
|
32
|
+
|
|
33
|
+
bitranTranspiler ||= await createBitranTranspiler();
|
|
34
|
+
|
|
35
|
+
// Tracking heading nodes to deal with them later
|
|
36
|
+
const headings: HeadingNode[] = [];
|
|
37
|
+
|
|
38
|
+
await bitranTranspiler.parser.parse(biCode, {
|
|
39
|
+
async step(node) {
|
|
40
|
+
const meta = node.meta;
|
|
41
|
+
const uniqueId = meta?.id;
|
|
42
|
+
|
|
43
|
+
if (node instanceof AliasesNode) {
|
|
44
|
+
mergeAliases(context.aliases, node.parseData);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (uniqueId) {
|
|
48
|
+
if (node instanceof HeadingNode) {
|
|
49
|
+
headings.push(node);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
await addUnique(node);
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
for (const heading of headings) {
|
|
59
|
+
let blocksAfter = 0;
|
|
60
|
+
let content = await bitranTranspiler.stringifier.stringify(heading);
|
|
61
|
+
|
|
62
|
+
await walkForward(heading, async (node) => {
|
|
63
|
+
if (blocksAfter >= blocksAfterHeading) return false;
|
|
64
|
+
|
|
65
|
+
if (node instanceof AliasesNode) return;
|
|
66
|
+
// Spoiler
|
|
67
|
+
// Todo
|
|
68
|
+
|
|
69
|
+
content +=
|
|
70
|
+
'\n\n' + (await bitranTranspiler.stringifier.stringify(node));
|
|
71
|
+
|
|
72
|
+
blocksAfter++;
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
await addUnique(heading, content);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
//
|
|
79
|
+
//
|
|
80
|
+
//
|
|
81
|
+
|
|
82
|
+
function createUniqueLocation(node: ElementNode) {
|
|
83
|
+
return stringifyBitranLocation({
|
|
84
|
+
...location,
|
|
85
|
+
...{ unique: node.meta.id! },
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
async function addUnique(node: ElementNode, content?: string) {
|
|
90
|
+
const dbUnique = new DbUnique();
|
|
91
|
+
dbUnique.location = createUniqueLocation(node);
|
|
92
|
+
dbUnique.content =
|
|
93
|
+
content || (await bitranTranspiler.stringifier.stringify(node));
|
|
94
|
+
dbUnique.title = node.parseData?.title || node.meta?.title;
|
|
95
|
+
dbUnique.productName = node.name;
|
|
96
|
+
dbUnique.context = context;
|
|
97
|
+
|
|
98
|
+
await ERUDIT_SERVER.DB.manager.save(dbUnique);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { PROJECT_DIR } from '#erudit/globalPaths';
|
|
2
|
-
import type { NavNode } from '@server/nav/node';
|
|
3
|
-
|
|
4
|
-
export function contentItemPath(navNode: NavNode, path?: string) {
|
|
5
|
-
return PROJECT_DIR + `/content/${navNode.path}${path ? '/' + path : ''}`;
|
|
6
|
-
}
|
|
1
|
+
import { PROJECT_DIR } from '#erudit/globalPaths';
|
|
2
|
+
import type { NavNode } from '@server/nav/node';
|
|
3
|
+
|
|
4
|
+
export function contentItemPath(navNode: NavNode, path?: string) {
|
|
5
|
+
return PROJECT_DIR + `/content/${navNode.path}${path ? '/' + path : ''}`;
|
|
6
|
+
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { DbBook } from '@server/db/entities/Book';
|
|
2
|
-
import { ERUDIT_SERVER } from '@server/global';
|
|
3
|
-
import type { BuilderFunctionArgs } from '../builderArgs';
|
|
4
|
-
|
|
5
|
-
export async function buildBook({ dbContent }: BuilderFunctionArgs) {
|
|
6
|
-
const dbBook = new DbBook();
|
|
7
|
-
dbBook.contentId = dbContent.contentId;
|
|
8
|
-
await ERUDIT_SERVER.DB.manager.save(dbBook);
|
|
9
|
-
}
|
|
1
|
+
import { DbBook } from '@server/db/entities/Book';
|
|
2
|
+
import { ERUDIT_SERVER } from '@server/global';
|
|
3
|
+
import type { BuilderFunctionArgs } from '../builderArgs';
|
|
4
|
+
|
|
5
|
+
export async function buildBook({ dbContent }: BuilderFunctionArgs) {
|
|
6
|
+
const dbBook = new DbBook();
|
|
7
|
+
dbBook.contentId = dbContent.contentId;
|
|
8
|
+
await ERUDIT_SERVER.DB.manager.save(dbBook);
|
|
9
|
+
}
|
|
@@ -1,37 +1,37 @@
|
|
|
1
|
-
import { readFileSync } from 'node:fs';
|
|
2
|
-
import type { GroupConfig } from 'erudit-cog/schema';
|
|
3
|
-
|
|
4
|
-
import { DbGroup } from '@server/db/entities/Group';
|
|
5
|
-
import { ERUDIT_SERVER } from '@erudit/server/plugin/global';
|
|
6
|
-
import type { BuilderFunctionArgs } from '../builderArgs';
|
|
7
|
-
import { contentItemPath } from '../path';
|
|
8
|
-
import { parseBitranContent } from '../parse';
|
|
9
|
-
|
|
10
|
-
export async function buildGroup({
|
|
11
|
-
navNode,
|
|
12
|
-
config,
|
|
13
|
-
}: BuilderFunctionArgs<GroupConfig>) {
|
|
14
|
-
const dbGroup = new DbGroup();
|
|
15
|
-
dbGroup.contentId = navNode.id;
|
|
16
|
-
dbGroup.type = config?.type || 'folder';
|
|
17
|
-
|
|
18
|
-
try {
|
|
19
|
-
const strContent = readFileSync(
|
|
20
|
-
contentItemPath(navNode, 'content.bi'),
|
|
21
|
-
'utf-8',
|
|
22
|
-
);
|
|
23
|
-
|
|
24
|
-
if (strContent) {
|
|
25
|
-
dbGroup.content = strContent;
|
|
26
|
-
await parseBitranContent(
|
|
27
|
-
{
|
|
28
|
-
type: 'group',
|
|
29
|
-
path: navNode.id,
|
|
30
|
-
},
|
|
31
|
-
strContent,
|
|
32
|
-
);
|
|
33
|
-
}
|
|
34
|
-
} catch {}
|
|
35
|
-
|
|
36
|
-
await ERUDIT_SERVER.DB.manager.save(dbGroup);
|
|
37
|
-
}
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import type { GroupConfig } from 'erudit-cog/schema';
|
|
3
|
+
|
|
4
|
+
import { DbGroup } from '@server/db/entities/Group';
|
|
5
|
+
import { ERUDIT_SERVER } from '@erudit/server/plugin/global';
|
|
6
|
+
import type { BuilderFunctionArgs } from '../builderArgs';
|
|
7
|
+
import { contentItemPath } from '../path';
|
|
8
|
+
import { parseBitranContent } from '../parse';
|
|
9
|
+
|
|
10
|
+
export async function buildGroup({
|
|
11
|
+
navNode,
|
|
12
|
+
config,
|
|
13
|
+
}: BuilderFunctionArgs<GroupConfig>) {
|
|
14
|
+
const dbGroup = new DbGroup();
|
|
15
|
+
dbGroup.contentId = navNode.id;
|
|
16
|
+
dbGroup.type = config?.type || 'folder';
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
const strContent = readFileSync(
|
|
20
|
+
contentItemPath(navNode, 'content.bi'),
|
|
21
|
+
'utf-8',
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
if (strContent) {
|
|
25
|
+
dbGroup.content = strContent;
|
|
26
|
+
await parseBitranContent(
|
|
27
|
+
{
|
|
28
|
+
type: 'group',
|
|
29
|
+
path: navNode.id,
|
|
30
|
+
},
|
|
31
|
+
strContent,
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
} catch {}
|
|
35
|
+
|
|
36
|
+
await ERUDIT_SERVER.DB.manager.save(dbGroup);
|
|
37
|
+
}
|