erudit 3.0.0-dev.17 → 3.0.0-dev.18
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 +193 -191
- package/app/components/Loading.vue +23 -23
- package/app/components/SiteAside.vue +393 -393
- package/app/components/SiteMain.vue +32 -32
- package/app/components/aside/AsideListItem.vue +74 -74
- package/app/components/aside/AsideMajor.vue +56 -56
- package/app/components/aside/AsideMinor.vue +73 -73
- 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 -88
- package/app/components/main/topic/TopicPartSwitch.vue +118 -118
- package/app/components/main/utils/Breadcrumb.vue +74 -74
- 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 -120
- 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 -22
- 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/adsAllowed.ts +11 -0
- package/app/composables/bitran.ts +108 -108
- package/app/composables/bitranContent.ts +96 -92
- package/app/composables/bitranLocation.ts +7 -7
- package/app/composables/contentData.ts +38 -38
- package/app/composables/contentPage.ts +168 -158
- package/app/composables/contentRoute.ts +45 -45
- package/app/composables/darkMagic.ts +24 -24
- package/app/composables/externalApi.ts +69 -69
- 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 -66
- package/app/pages/index.vue +32 -32
- package/app/pages/members.vue +5 -6
- package/app/pages/practice/[...practice].vue +3 -3
- package/app/pages/summary/[...summaryId].vue +3 -3
- package/app/plugins/analytics.ts +8 -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 -47
- package/module/logger.ts +10 -10
- package/module/paths.ts +22 -22
- package/module/restart.ts +61 -61
- package/nuxt.config.ts +131 -131
- package/package.json +4 -4
- package/server/api/aside/major/nav/bookIds.ts +5 -5
- package/server/api/aside/major/nav/bookNav/[...bookId].ts +17 -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 +19 -120
- package/server/api/preview/page/[...parts].ts +78 -78
- package/server/api/preview/unique/[...location].ts +61 -61
- package/server/plugin/bitran/content.ts +237 -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 -345
- 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 +179 -175
- package/server/plugin/repository/book.ts +23 -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
|
@@ -1,229 +1,229 @@
|
|
|
1
|
-
import { BlockNode, type ElementNode } from '@bitran-js/core';
|
|
2
|
-
import type { BitranTranspiler } from '@bitran-js/transpiler';
|
|
3
|
-
import {
|
|
4
|
-
parseBitranLocation,
|
|
5
|
-
parsePartialBitranLocation,
|
|
6
|
-
stringifyBitranLocation,
|
|
7
|
-
tryReplaceAlias,
|
|
8
|
-
type BitranAliases,
|
|
9
|
-
type BitranContext,
|
|
10
|
-
} from '@erudit-js/cog/schema';
|
|
11
|
-
import { IncludeNode } from '@erudit-js/bitran-elements/include/shared';
|
|
12
|
-
import { AliasesNode } from '@erudit-js/bitran-elements/aliases/shared';
|
|
13
|
-
|
|
14
|
-
import { createBitranTranspiler } from '@server/bitran/transpiler';
|
|
15
|
-
import { ERUDIT_SERVER } from '@server/global';
|
|
16
|
-
import { DbUnique } from '@server/db/entities/Unique';
|
|
17
|
-
import {
|
|
18
|
-
resolveClientContentId,
|
|
19
|
-
serverAbsolutizeContentPath,
|
|
20
|
-
} from '@server/repository/contentId';
|
|
21
|
-
|
|
22
|
-
export type TraverseEnterFn = (payload: {
|
|
23
|
-
_location: string;
|
|
24
|
-
_bitranTranspiler: BitranTranspiler;
|
|
25
|
-
_biCode: string;
|
|
26
|
-
}) => Promise<any>;
|
|
27
|
-
|
|
28
|
-
export type TraverseStepFn = (payload: {
|
|
29
|
-
_location: string;
|
|
30
|
-
_bitranTranspiler: BitranTranspiler;
|
|
31
|
-
_node: ElementNode;
|
|
32
|
-
}) => Promise<any>;
|
|
33
|
-
|
|
34
|
-
export type TraverseLeaveFn = (payload: { _location: string }) => Promise<any>;
|
|
35
|
-
|
|
36
|
-
export async function traverseInclude(
|
|
37
|
-
includeNode: IncludeNode,
|
|
38
|
-
context: BitranContext,
|
|
39
|
-
listeners: {
|
|
40
|
-
enter?: TraverseEnterFn;
|
|
41
|
-
step?: TraverseStepFn;
|
|
42
|
-
leave?: TraverseLeaveFn;
|
|
43
|
-
},
|
|
44
|
-
): Promise<BlockNode[]> {
|
|
45
|
-
const rawLocation = parsePartialBitranLocation(
|
|
46
|
-
includeNode.id,
|
|
47
|
-
context.location,
|
|
48
|
-
);
|
|
49
|
-
|
|
50
|
-
if (rawLocation.path) {
|
|
51
|
-
rawLocation.path = serverAbsolutizeContentPath(
|
|
52
|
-
rawLocation.path,
|
|
53
|
-
context.location.path!,
|
|
54
|
-
);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const absEntryLocation = stringifyBitranLocation(rawLocation);
|
|
58
|
-
|
|
59
|
-
const travelMap: Record<string, string | null> = {
|
|
60
|
-
[absEntryLocation]: null,
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
try {
|
|
64
|
-
return await _traverseInclude(
|
|
65
|
-
includeNode,
|
|
66
|
-
absEntryLocation,
|
|
67
|
-
context.aliases,
|
|
68
|
-
listeners,
|
|
69
|
-
travelMap,
|
|
70
|
-
);
|
|
71
|
-
} catch (message) {
|
|
72
|
-
let finalMessage = `Include Traversal Error!\n\n${message instanceof Error ? message.message : message}\n\n`;
|
|
73
|
-
|
|
74
|
-
// Print the traversal path in the order of traversal
|
|
75
|
-
for (const location of Object.keys(travelMap)) {
|
|
76
|
-
const includeTarget = travelMap[location];
|
|
77
|
-
if (includeTarget === null) continue;
|
|
78
|
-
finalMessage += `at "${printIncludeTarget(includeTarget)}" in "${location}"\n`;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
throw new Error(finalMessage);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
async function _traverseInclude(
|
|
86
|
-
includeNode: IncludeNode,
|
|
87
|
-
location: string,
|
|
88
|
-
aliases: BitranAliases,
|
|
89
|
-
listeners: {
|
|
90
|
-
enter?: TraverseEnterFn;
|
|
91
|
-
step?: TraverseStepFn;
|
|
92
|
-
leave?: TraverseLeaveFn;
|
|
93
|
-
},
|
|
94
|
-
travelMap: Record<string, string | null>,
|
|
95
|
-
): Promise<BlockNode[]> {
|
|
96
|
-
let includeTargetLocation: string;
|
|
97
|
-
|
|
98
|
-
try {
|
|
99
|
-
const parsedLocation = parseBitranLocation(location);
|
|
100
|
-
|
|
101
|
-
includeTargetLocation = (() => {
|
|
102
|
-
const _location = parsePartialBitranLocation(
|
|
103
|
-
tryReplaceAlias(includeNode.parseData.location, aliases),
|
|
104
|
-
parsedLocation,
|
|
105
|
-
);
|
|
106
|
-
|
|
107
|
-
if (_location.path) {
|
|
108
|
-
_location.path = serverAbsolutizeContentPath(
|
|
109
|
-
_location.path,
|
|
110
|
-
parsedLocation.path!,
|
|
111
|
-
);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
return stringifyBitranLocation(_location);
|
|
115
|
-
})();
|
|
116
|
-
} catch (error) {
|
|
117
|
-
travelMap[location] = includeNode.parseData.location;
|
|
118
|
-
throw new Error(
|
|
119
|
-
`Failed to resolve include target location "${includeNode.parseData.location}" from "${location}": ${error instanceof Error ? error.message : error}`,
|
|
120
|
-
);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// Use only absolute locations as keys for infinite loop detection
|
|
124
|
-
if (includeTargetLocation in travelMap)
|
|
125
|
-
throw new Error(
|
|
126
|
-
`Include "${printIncludeTarget(includeNode.parseData.location)}" targets "${includeTargetLocation}" which creates infinite loop!`,
|
|
127
|
-
);
|
|
128
|
-
|
|
129
|
-
travelMap[location] = includeNode.parseData.location;
|
|
130
|
-
|
|
131
|
-
//
|
|
132
|
-
// Loading Unique this Include is referencing to.
|
|
133
|
-
//
|
|
134
|
-
|
|
135
|
-
const dbUnique = await ERUDIT_SERVER.DB.manager.findOne(DbUnique, {
|
|
136
|
-
where: { location: includeTargetLocation },
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
if (!dbUnique)
|
|
140
|
-
throw new Error(
|
|
141
|
-
`Include "${printIncludeTarget(includeNode.parseData.location)}" is targeting non-existing unique "${includeTargetLocation}"!`,
|
|
142
|
-
);
|
|
143
|
-
|
|
144
|
-
//
|
|
145
|
-
// Creating Bitran core within loaded unique's location context.
|
|
146
|
-
//
|
|
147
|
-
|
|
148
|
-
const context: BitranContext = {
|
|
149
|
-
location: parseBitranLocation(includeTargetLocation),
|
|
150
|
-
aliases: dbUnique.context.aliases,
|
|
151
|
-
};
|
|
152
|
-
|
|
153
|
-
const bitranTranspiler = await createBitranTranspiler({
|
|
154
|
-
eruditConfig: ERUDIT_SERVER.CONFIG,
|
|
155
|
-
context: structuredClone(context),
|
|
156
|
-
insideInclude: true,
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
if (listeners.enter) {
|
|
160
|
-
await listeners.enter({
|
|
161
|
-
_biCode: dbUnique.content,
|
|
162
|
-
_location: includeTargetLocation,
|
|
163
|
-
_bitranTranspiler: bitranTranspiler,
|
|
164
|
-
});
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
//
|
|
168
|
-
// Parsing unique content and sub-traversing all includes if any.
|
|
169
|
-
//
|
|
170
|
-
|
|
171
|
-
let stepErrorMessage: string | Error | undefined;
|
|
172
|
-
|
|
173
|
-
const rootNode = await bitranTranspiler.parser.parse(dbUnique.content, {
|
|
174
|
-
step: async (node) => {
|
|
175
|
-
if (stepErrorMessage) return;
|
|
176
|
-
|
|
177
|
-
// Skip Alias nodes to prevent them being injected into calling document context and possibly conflicting with other aliases, includes and links...
|
|
178
|
-
if (node instanceof AliasesNode) return;
|
|
179
|
-
|
|
180
|
-
// Replacing block ids with absolute ones to make possible to link to them
|
|
181
|
-
if (node instanceof BlockNode)
|
|
182
|
-
node.meta.id = Object.keys(travelMap)
|
|
183
|
-
.concat([location])
|
|
184
|
-
.join('__');
|
|
185
|
-
|
|
186
|
-
if (!(node instanceof IncludeNode)) {
|
|
187
|
-
if (listeners.step) {
|
|
188
|
-
await listeners.step({
|
|
189
|
-
_location: includeTargetLocation,
|
|
190
|
-
_node: node,
|
|
191
|
-
_bitranTranspiler: bitranTranspiler,
|
|
192
|
-
});
|
|
193
|
-
}
|
|
194
|
-
return;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
try {
|
|
198
|
-
await _traverseInclude(
|
|
199
|
-
node,
|
|
200
|
-
includeTargetLocation,
|
|
201
|
-
context.aliases,
|
|
202
|
-
listeners,
|
|
203
|
-
travelMap,
|
|
204
|
-
);
|
|
205
|
-
} catch (err: any) {
|
|
206
|
-
stepErrorMessage =
|
|
207
|
-
err instanceof Error ? err : new Error(String(err));
|
|
208
|
-
}
|
|
209
|
-
},
|
|
210
|
-
});
|
|
211
|
-
|
|
212
|
-
if (stepErrorMessage) throw stepErrorMessage;
|
|
213
|
-
|
|
214
|
-
//
|
|
215
|
-
// Leaving from current Include
|
|
216
|
-
//
|
|
217
|
-
|
|
218
|
-
if (listeners.leave) {
|
|
219
|
-
await listeners.leave({
|
|
220
|
-
_location: includeTargetLocation,
|
|
221
|
-
});
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
return (rootNode.children as BlockNode[]) ?? [];
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
function printIncludeTarget(target: string) {
|
|
228
|
-
return `<~ ${target}`;
|
|
229
|
-
}
|
|
1
|
+
import { BlockNode, type ElementNode } from '@bitran-js/core';
|
|
2
|
+
import type { BitranTranspiler } from '@bitran-js/transpiler';
|
|
3
|
+
import {
|
|
4
|
+
parseBitranLocation,
|
|
5
|
+
parsePartialBitranLocation,
|
|
6
|
+
stringifyBitranLocation,
|
|
7
|
+
tryReplaceAlias,
|
|
8
|
+
type BitranAliases,
|
|
9
|
+
type BitranContext,
|
|
10
|
+
} from '@erudit-js/cog/schema';
|
|
11
|
+
import { IncludeNode } from '@erudit-js/bitran-elements/include/shared';
|
|
12
|
+
import { AliasesNode } from '@erudit-js/bitran-elements/aliases/shared';
|
|
13
|
+
|
|
14
|
+
import { createBitranTranspiler } from '@server/bitran/transpiler';
|
|
15
|
+
import { ERUDIT_SERVER } from '@server/global';
|
|
16
|
+
import { DbUnique } from '@server/db/entities/Unique';
|
|
17
|
+
import {
|
|
18
|
+
resolveClientContentId,
|
|
19
|
+
serverAbsolutizeContentPath,
|
|
20
|
+
} from '@server/repository/contentId';
|
|
21
|
+
|
|
22
|
+
export type TraverseEnterFn = (payload: {
|
|
23
|
+
_location: string;
|
|
24
|
+
_bitranTranspiler: BitranTranspiler;
|
|
25
|
+
_biCode: string;
|
|
26
|
+
}) => Promise<any>;
|
|
27
|
+
|
|
28
|
+
export type TraverseStepFn = (payload: {
|
|
29
|
+
_location: string;
|
|
30
|
+
_bitranTranspiler: BitranTranspiler;
|
|
31
|
+
_node: ElementNode;
|
|
32
|
+
}) => Promise<any>;
|
|
33
|
+
|
|
34
|
+
export type TraverseLeaveFn = (payload: { _location: string }) => Promise<any>;
|
|
35
|
+
|
|
36
|
+
export async function traverseInclude(
|
|
37
|
+
includeNode: IncludeNode,
|
|
38
|
+
context: BitranContext,
|
|
39
|
+
listeners: {
|
|
40
|
+
enter?: TraverseEnterFn;
|
|
41
|
+
step?: TraverseStepFn;
|
|
42
|
+
leave?: TraverseLeaveFn;
|
|
43
|
+
},
|
|
44
|
+
): Promise<BlockNode[]> {
|
|
45
|
+
const rawLocation = parsePartialBitranLocation(
|
|
46
|
+
includeNode.id,
|
|
47
|
+
context.location,
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
if (rawLocation.path) {
|
|
51
|
+
rawLocation.path = serverAbsolutizeContentPath(
|
|
52
|
+
rawLocation.path,
|
|
53
|
+
context.location.path!,
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const absEntryLocation = stringifyBitranLocation(rawLocation);
|
|
58
|
+
|
|
59
|
+
const travelMap: Record<string, string | null> = {
|
|
60
|
+
[absEntryLocation]: null,
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
try {
|
|
64
|
+
return await _traverseInclude(
|
|
65
|
+
includeNode,
|
|
66
|
+
absEntryLocation,
|
|
67
|
+
context.aliases,
|
|
68
|
+
listeners,
|
|
69
|
+
travelMap,
|
|
70
|
+
);
|
|
71
|
+
} catch (message) {
|
|
72
|
+
let finalMessage = `Include Traversal Error!\n\n${message instanceof Error ? message.message : message}\n\n`;
|
|
73
|
+
|
|
74
|
+
// Print the traversal path in the order of traversal
|
|
75
|
+
for (const location of Object.keys(travelMap)) {
|
|
76
|
+
const includeTarget = travelMap[location];
|
|
77
|
+
if (includeTarget === null) continue;
|
|
78
|
+
finalMessage += `at "${printIncludeTarget(includeTarget)}" in "${location}"\n`;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
throw new Error(finalMessage);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async function _traverseInclude(
|
|
86
|
+
includeNode: IncludeNode,
|
|
87
|
+
location: string,
|
|
88
|
+
aliases: BitranAliases,
|
|
89
|
+
listeners: {
|
|
90
|
+
enter?: TraverseEnterFn;
|
|
91
|
+
step?: TraverseStepFn;
|
|
92
|
+
leave?: TraverseLeaveFn;
|
|
93
|
+
},
|
|
94
|
+
travelMap: Record<string, string | null>,
|
|
95
|
+
): Promise<BlockNode[]> {
|
|
96
|
+
let includeTargetLocation: string;
|
|
97
|
+
|
|
98
|
+
try {
|
|
99
|
+
const parsedLocation = parseBitranLocation(location);
|
|
100
|
+
|
|
101
|
+
includeTargetLocation = (() => {
|
|
102
|
+
const _location = parsePartialBitranLocation(
|
|
103
|
+
tryReplaceAlias(includeNode.parseData.location, aliases),
|
|
104
|
+
parsedLocation,
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
if (_location.path) {
|
|
108
|
+
_location.path = serverAbsolutizeContentPath(
|
|
109
|
+
_location.path,
|
|
110
|
+
parsedLocation.path!,
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return stringifyBitranLocation(_location);
|
|
115
|
+
})();
|
|
116
|
+
} catch (error) {
|
|
117
|
+
travelMap[location] = includeNode.parseData.location;
|
|
118
|
+
throw new Error(
|
|
119
|
+
`Failed to resolve include target location "${includeNode.parseData.location}" from "${location}": ${error instanceof Error ? error.message : error}`,
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Use only absolute locations as keys for infinite loop detection
|
|
124
|
+
if (includeTargetLocation in travelMap)
|
|
125
|
+
throw new Error(
|
|
126
|
+
`Include "${printIncludeTarget(includeNode.parseData.location)}" targets "${includeTargetLocation}" which creates infinite loop!`,
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
travelMap[location] = includeNode.parseData.location;
|
|
130
|
+
|
|
131
|
+
//
|
|
132
|
+
// Loading Unique this Include is referencing to.
|
|
133
|
+
//
|
|
134
|
+
|
|
135
|
+
const dbUnique = await ERUDIT_SERVER.DB.manager.findOne(DbUnique, {
|
|
136
|
+
where: { location: includeTargetLocation },
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
if (!dbUnique)
|
|
140
|
+
throw new Error(
|
|
141
|
+
`Include "${printIncludeTarget(includeNode.parseData.location)}" is targeting non-existing unique "${includeTargetLocation}"!`,
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
//
|
|
145
|
+
// Creating Bitran core within loaded unique's location context.
|
|
146
|
+
//
|
|
147
|
+
|
|
148
|
+
const context: BitranContext = {
|
|
149
|
+
location: parseBitranLocation(includeTargetLocation),
|
|
150
|
+
aliases: dbUnique.context.aliases,
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
const bitranTranspiler = await createBitranTranspiler({
|
|
154
|
+
eruditConfig: ERUDIT_SERVER.CONFIG,
|
|
155
|
+
context: structuredClone(context),
|
|
156
|
+
insideInclude: true,
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
if (listeners.enter) {
|
|
160
|
+
await listeners.enter({
|
|
161
|
+
_biCode: dbUnique.content,
|
|
162
|
+
_location: includeTargetLocation,
|
|
163
|
+
_bitranTranspiler: bitranTranspiler,
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
//
|
|
168
|
+
// Parsing unique content and sub-traversing all includes if any.
|
|
169
|
+
//
|
|
170
|
+
|
|
171
|
+
let stepErrorMessage: string | Error | undefined;
|
|
172
|
+
|
|
173
|
+
const rootNode = await bitranTranspiler.parser.parse(dbUnique.content, {
|
|
174
|
+
step: async (node) => {
|
|
175
|
+
if (stepErrorMessage) return;
|
|
176
|
+
|
|
177
|
+
// Skip Alias nodes to prevent them being injected into calling document context and possibly conflicting with other aliases, includes and links...
|
|
178
|
+
if (node instanceof AliasesNode) return;
|
|
179
|
+
|
|
180
|
+
// Replacing block ids with absolute ones to make possible to link to them
|
|
181
|
+
if (node instanceof BlockNode)
|
|
182
|
+
node.meta.id = Object.keys(travelMap)
|
|
183
|
+
.concat([location])
|
|
184
|
+
.join('__');
|
|
185
|
+
|
|
186
|
+
if (!(node instanceof IncludeNode)) {
|
|
187
|
+
if (listeners.step) {
|
|
188
|
+
await listeners.step({
|
|
189
|
+
_location: includeTargetLocation,
|
|
190
|
+
_node: node,
|
|
191
|
+
_bitranTranspiler: bitranTranspiler,
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
try {
|
|
198
|
+
await _traverseInclude(
|
|
199
|
+
node,
|
|
200
|
+
includeTargetLocation,
|
|
201
|
+
context.aliases,
|
|
202
|
+
listeners,
|
|
203
|
+
travelMap,
|
|
204
|
+
);
|
|
205
|
+
} catch (err: any) {
|
|
206
|
+
stepErrorMessage =
|
|
207
|
+
err instanceof Error ? err : new Error(String(err));
|
|
208
|
+
}
|
|
209
|
+
},
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
if (stepErrorMessage) throw stepErrorMessage;
|
|
213
|
+
|
|
214
|
+
//
|
|
215
|
+
// Leaving from current Include
|
|
216
|
+
//
|
|
217
|
+
|
|
218
|
+
if (listeners.leave) {
|
|
219
|
+
await listeners.leave({
|
|
220
|
+
_location: includeTargetLocation,
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
return (rootNode.children as BlockNode[]) ?? [];
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function printIncludeTarget(target: string) {
|
|
228
|
+
return `<~ ${target}`;
|
|
229
|
+
}
|
|
@@ -1,39 +1,39 @@
|
|
|
1
|
-
import {
|
|
2
|
-
decodeBitranLocation,
|
|
3
|
-
parseBitranLocation,
|
|
4
|
-
} from '@erudit-js/cog/schema';
|
|
5
|
-
|
|
6
|
-
import { getFullContentId } from '@server/repository/contentId';
|
|
7
|
-
|
|
8
|
-
export async function parseClientBitranLocation(clientLocation: string) {
|
|
9
|
-
clientLocation = decodeURIComponent(clientLocation);
|
|
10
|
-
clientLocation = decodeBitranLocation(clientLocation);
|
|
11
|
-
|
|
12
|
-
if (!clientLocation) {
|
|
13
|
-
throw createError({
|
|
14
|
-
statusCode: 400,
|
|
15
|
-
statusText: 'Empty content location router parameter!',
|
|
16
|
-
});
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
try {
|
|
20
|
-
const location = parseBitranLocation(clientLocation);
|
|
21
|
-
|
|
22
|
-
if (location.path) {
|
|
23
|
-
location.path = await getFullContentId(location.path);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
return location;
|
|
27
|
-
} catch (_error) {
|
|
28
|
-
let error = `Failed to parse client location "${clientLocation}"!`;
|
|
29
|
-
|
|
30
|
-
if (_error) {
|
|
31
|
-
error += '\n\n' + _error;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
throw createError({
|
|
35
|
-
statusCode: 400,
|
|
36
|
-
statusText: error,
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
}
|
|
1
|
+
import {
|
|
2
|
+
decodeBitranLocation,
|
|
3
|
+
parseBitranLocation,
|
|
4
|
+
} from '@erudit-js/cog/schema';
|
|
5
|
+
|
|
6
|
+
import { getFullContentId } from '@server/repository/contentId';
|
|
7
|
+
|
|
8
|
+
export async function parseClientBitranLocation(clientLocation: string) {
|
|
9
|
+
clientLocation = decodeURIComponent(clientLocation);
|
|
10
|
+
clientLocation = decodeBitranLocation(clientLocation);
|
|
11
|
+
|
|
12
|
+
if (!clientLocation) {
|
|
13
|
+
throw createError({
|
|
14
|
+
statusCode: 400,
|
|
15
|
+
statusText: 'Empty content location router parameter!',
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
const location = parseBitranLocation(clientLocation);
|
|
21
|
+
|
|
22
|
+
if (location.path) {
|
|
23
|
+
location.path = await getFullContentId(location.path);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return location;
|
|
27
|
+
} catch (_error) {
|
|
28
|
+
let error = `Failed to parse client location "${clientLocation}"!`;
|
|
29
|
+
|
|
30
|
+
if (_error) {
|
|
31
|
+
error += '\n\n' + _error;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
throw createError({
|
|
35
|
+
statusCode: 400,
|
|
36
|
+
statusText: error,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
}
|