erudit 3.0.0-dev.1 → 3.0.0-dev.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (252) hide show
  1. package/app/app.vue +195 -172
  2. package/app/components/Loading.vue +23 -23
  3. package/app/components/SiteAside.vue +393 -382
  4. package/app/components/SiteMain.vue +34 -35
  5. package/app/components/ads/BannerTemplate.vue +51 -51
  6. package/app/components/ads/BottomBanner.vue +45 -45
  7. package/app/components/ads/LeftBanner.vue +50 -50
  8. package/app/components/aside/AsideListItem.vue +74 -74
  9. package/app/components/aside/AsideMajor.vue +56 -56
  10. package/app/components/aside/AsideMinor.vue +71 -71
  11. package/app/components/aside/major/PaneContentScroll.vue +23 -23
  12. package/app/components/aside/major/PaneSwitch.vue +54 -54
  13. package/app/components/aside/major/PaneSwitchButton.vue +63 -63
  14. package/app/components/aside/major/SiteInfo.vue +85 -85
  15. package/app/components/aside/major/panes/Language.vue +79 -79
  16. package/app/components/aside/major/panes/Pages.vue +34 -34
  17. package/app/components/aside/major/panes/Search.vue +11 -11
  18. package/app/components/aside/major/panes/nav/Nav.vue +87 -91
  19. package/app/components/aside/major/panes/nav/NavBook.vue +87 -86
  20. package/app/components/aside/major/panes/nav/NavBookLoading.vue +24 -24
  21. package/app/components/aside/major/panes/nav/NavGlobal.vue +16 -16
  22. package/app/components/aside/major/panes/nav/fnav/FNav.vue +105 -105
  23. package/app/components/aside/major/panes/nav/fnav/FNavBook.vue +32 -32
  24. package/app/components/aside/major/panes/nav/fnav/FNavFlags.vue +40 -40
  25. package/app/components/aside/major/panes/nav/fnav/FNavFolder.vue +60 -60
  26. package/app/components/aside/major/panes/nav/fnav/FNavItem.vue +34 -34
  27. package/app/components/aside/major/panes/nav/fnav/FNavSeparator.vue +80 -80
  28. package/app/components/aside/major/panes/nav/fnav/FNavTopic.vue +24 -24
  29. package/app/components/aside/major/panes/other/ItemContent.vue +29 -29
  30. package/app/components/aside/major/panes/other/ItemGenerator.vue +13 -15
  31. package/app/components/aside/major/panes/other/ItemTheme.vue +54 -54
  32. package/app/components/aside/major/panes/other/Other.vue +16 -16
  33. package/app/components/aside/minor/AsideMinorContributor.vue +5 -5
  34. package/app/components/aside/minor/AsideMinorNews.vue +11 -11
  35. package/app/components/aside/minor/AsideMinorPane.vue +15 -15
  36. package/app/components/aside/minor/AsideMinorTopLink.vue +67 -67
  37. package/app/components/aside/minor/Contribute.vue +145 -145
  38. package/app/components/aside/minor/content/AsideMinorContent.vue +92 -92
  39. package/app/components/aside/minor/topic/AsideMinorTopic.vue +32 -32
  40. package/app/components/aside/minor/topic/TopicContributors.vue +177 -177
  41. package/app/components/aside/minor/topic/TopicNav.vue +49 -49
  42. package/app/components/aside/minor/topic/TopicToc.vue +219 -203
  43. package/app/components/aside/minor/topic/TopicTocItem.vue +30 -31
  44. package/app/components/aside/utils/AsideOverlayPane.vue +40 -40
  45. package/app/components/bitran/BitranContent.vue +91 -63
  46. package/app/components/bitran/RenderWrapper.vue +10 -10
  47. package/app/components/contributor/ContributorAvatar.vue +45 -43
  48. package/app/components/contributor/ContributorListItem.vue +35 -35
  49. package/app/components/main/topic/MainTopic.vue +78 -79
  50. package/app/components/main/topic/TopicPartSwitch.vue +118 -118
  51. package/app/components/main/utils/Breadcrumb.vue +70 -75
  52. package/app/components/main/utils/ContentDecoration.vue +29 -29
  53. package/app/components/main/utils/ContentDescription.vue +19 -19
  54. package/app/components/main/utils/ContentPopover.vue +188 -176
  55. package/app/components/main/utils/ContentPopovers.vue +111 -105
  56. package/app/components/main/utils/ContentReferences.vue +70 -70
  57. package/app/components/main/utils/ContentSection.vue +45 -45
  58. package/app/components/main/utils/ContentTitle.vue +63 -39
  59. package/app/components/main/utils/reference/ReferenceGroup.vue +38 -38
  60. package/app/components/main/utils/reference/ReferenceItem.vue +68 -68
  61. package/app/components/main/utils/reference/ReferenceSource.vue +116 -116
  62. package/app/components/preview/Preview.vue +186 -177
  63. package/app/components/preview/PreviewDisplay.vue +139 -139
  64. package/app/components/preview/PreviewFooterAction.vue +73 -73
  65. package/app/components/preview/PreviewLoading.vue +14 -14
  66. package/app/components/preview/PreviewScreen.vue +141 -99
  67. package/app/components/preview/display/Alert.vue +50 -50
  68. package/app/components/preview/display/Custom.vue +18 -18
  69. package/app/components/preview/display/GenericLink.vue +48 -48
  70. package/app/components/preview/display/PageLink.vue +20 -20
  71. package/app/components/preview/display/Unique.vue +55 -49
  72. package/app/components/transition/Fade.vue +19 -19
  73. package/app/components/tree/TreeContainer.vue +11 -11
  74. package/app/components/tree/TreeItem.vue +89 -89
  75. package/app/composables/bitran.ts +108 -127
  76. package/app/composables/bitranContent.ts +69 -37
  77. package/app/composables/bitranLocation.ts +7 -7
  78. package/app/composables/contentData.ts +36 -36
  79. package/app/composables/contentPage.ts +157 -156
  80. package/app/composables/contentRoute.ts +45 -45
  81. package/app/composables/darkMagic.ts +24 -24
  82. package/app/composables/externalApi.ts +63 -63
  83. package/app/composables/favicon.ts +8 -8
  84. package/app/composables/formatText.ts +86 -86
  85. package/app/composables/majorPane.ts +60 -60
  86. package/app/composables/phrases.ts +81 -80
  87. package/app/composables/theme.ts +29 -29
  88. package/app/composables/url.ts +33 -33
  89. package/app/pages/_test/preview.vue +110 -110
  90. package/app/pages/article/[...articleId].vue +3 -3
  91. package/app/pages/book/[...bookId].vue +47 -47
  92. package/app/pages/group/[...groupId].vue +64 -65
  93. package/app/pages/index.vue +32 -32
  94. package/app/pages/members.vue +6 -6
  95. package/app/pages/practice/[...practice].vue +3 -3
  96. package/app/pages/summary/[...summaryId].vue +3 -3
  97. package/app/public/favicon/article.svg +5 -5
  98. package/app/public/favicon/default.svg +3 -3
  99. package/app/public/favicon/practice.svg +3 -3
  100. package/app/public/favicon/summary.svg +4 -4
  101. package/app/public/logotype.svg +2 -2
  102. package/app/scripts/_immediate.js +9 -9
  103. package/app/scripts/aside/index.ts +59 -59
  104. package/app/scripts/aside/major/nav.ts +26 -26
  105. package/app/scripts/aside/minor/state.ts +37 -37
  106. package/app/scripts/aside/minor/topic.ts +3 -3
  107. package/app/scripts/flag.ts +28 -28
  108. package/app/scripts/og.ts +27 -27
  109. package/app/scripts/preview/build.ts +73 -73
  110. package/app/scripts/preview/data/alert.ts +19 -19
  111. package/app/scripts/preview/data/custom.ts +8 -8
  112. package/app/scripts/preview/data/genericLink.ts +24 -24
  113. package/app/scripts/preview/data/pageLink.ts +22 -20
  114. package/app/scripts/preview/data/unique.ts +72 -70
  115. package/app/scripts/preview/data.ts +24 -24
  116. package/app/scripts/preview/display.ts +37 -37
  117. package/app/scripts/preview/footer.ts +9 -9
  118. package/app/scripts/preview/request.ts +51 -51
  119. package/app/scripts/preview/state.ts +63 -63
  120. package/app/styles/_immediate.css +7 -7
  121. package/app/styles/_util.scss +43 -43
  122. package/app/styles/_utils.scss +44 -44
  123. package/app/styles/app.scss +91 -91
  124. package/app/styles/def/_bp.scss +27 -27
  125. package/app/styles/def/_size.scss +7 -7
  126. package/app/styles/def/_z.scss +5 -5
  127. package/app/styles/normalize.scss +63 -63
  128. package/app/styles/partials/_darkMagic.scss +5 -5
  129. package/app/styles/partials/_fnav.scss +15 -15
  130. package/app/styles/partials/_preview.scss +5 -5
  131. package/bin/erudit.mjs +2 -0
  132. package/const.ts +4 -0
  133. package/globalPath.ts +21 -21
  134. package/globals/bitran.ts +1 -47
  135. package/globals/content.ts +22 -22
  136. package/globals/contributor.ts +5 -5
  137. package/globals/erudit.ts +5 -5
  138. package/globals/register.ts +18 -18
  139. package/languages/en.ts +94 -95
  140. package/languages/ru.ts +98 -99
  141. package/module/bitran.ts +66 -34
  142. package/module/config.ts +35 -34
  143. package/module/imports.ts +61 -46
  144. package/module/index.ts +47 -47
  145. package/module/logger.ts +10 -10
  146. package/module/paths.ts +22 -22
  147. package/module/restart.ts +61 -61
  148. package/nuxt.config.ts +123 -111
  149. package/package.json +19 -13
  150. package/server/api/aside/major/nav/bookIds.ts +5 -5
  151. package/server/api/aside/major/nav/bookNav/[...bookId].ts +20 -20
  152. package/server/api/aside/major/nav/global.ts +7 -7
  153. package/server/api/aside/minor/news.ts +7 -7
  154. package/server/api/aside/minor/path.ts +77 -78
  155. package/server/api/bitran/content/{[location].ts → [...location].ts} +8 -7
  156. package/server/api/bitran/toc/{[location].ts → [...location].ts} +7 -7
  157. package/server/api/content/data.ts +72 -72
  158. package/server/api/contributor/count.ts +6 -6
  159. package/server/api/fake/content.ts +11 -11
  160. package/server/api/fake/shared/languages.ts +12 -12
  161. package/server/api/language/functions.ts +12 -12
  162. package/server/api/language/phrase/[phraseId].ts +19 -19
  163. package/server/api/language/phraseIds.ts +8 -8
  164. package/server/api/preview/page/[...parts].ts +52 -51
  165. package/server/api/preview/unique/[location].ts +60 -55
  166. package/server/plugin/bitran/content.ts +214 -187
  167. package/server/plugin/bitran/{products → elements}/include.ts +216 -230
  168. package/server/plugin/bitran/location.ts +25 -25
  169. package/server/plugin/bitran/toc.ts +75 -83
  170. package/server/plugin/bitran/transpiler.ts +9 -46
  171. package/server/plugin/build/close.ts +10 -10
  172. package/server/plugin/build/jobs/content/builderArgs.ts +8 -8
  173. package/server/plugin/build/jobs/content/files.ts +79 -0
  174. package/server/plugin/build/jobs/content/generic.ts +192 -176
  175. package/server/plugin/build/jobs/content/parse.ts +109 -100
  176. package/server/plugin/build/jobs/content/path.ts +6 -6
  177. package/server/plugin/build/jobs/content/type/book.ts +9 -9
  178. package/server/plugin/build/jobs/content/type/group.ts +37 -37
  179. package/server/plugin/build/jobs/content/type/topic.ts +36 -36
  180. package/server/plugin/build/jobs/contributors.ts +66 -66
  181. package/server/plugin/build/jobs/language.ts +36 -36
  182. package/server/plugin/build/jobs/nav.ts +214 -209
  183. package/server/plugin/build/process.ts +25 -25
  184. package/server/plugin/build/rebuild.ts +55 -55
  185. package/server/plugin/build/setup.ts +19 -21
  186. package/server/plugin/content/context.ts +116 -112
  187. package/server/plugin/db/entities/Book.ts +7 -7
  188. package/server/plugin/db/entities/Content.ts +49 -49
  189. package/server/plugin/db/entities/Contribution.ts +10 -10
  190. package/server/plugin/db/entities/Contributor.ts +16 -16
  191. package/server/plugin/db/entities/File.ts +10 -0
  192. package/server/plugin/db/entities/Group.ts +14 -14
  193. package/server/plugin/db/entities/Hash.ts +15 -15
  194. package/server/plugin/db/entities/Topic.ts +20 -20
  195. package/server/plugin/db/entities/Unique.ts +21 -21
  196. package/server/plugin/db/setup.ts +36 -34
  197. package/server/plugin/global.ts +16 -18
  198. package/server/plugin/importer.ts +12 -12
  199. package/server/plugin/index.ts +9 -9
  200. package/server/plugin/logger.ts +23 -23
  201. package/server/plugin/nav/node.ts +26 -26
  202. package/server/plugin/nav/utils.ts +133 -129
  203. package/server/plugin/repository/book.ts +21 -21
  204. package/server/plugin/repository/content.ts +237 -238
  205. package/server/plugin/repository/contributor.ts +8 -8
  206. package/server/plugin/repository/file.ts +10 -0
  207. package/server/plugin/repository/frontNav.ts +148 -148
  208. package/server/plugin/repository/topic.ts +32 -32
  209. package/server/tsconfig.json +9 -7
  210. package/shared/aside/minor.ts +51 -50
  211. package/shared/asset.ts +22 -15
  212. package/shared/bitran/contentId.ts +88 -0
  213. package/shared/bitran/stringContent.ts +6 -0
  214. package/shared/bitran/toc.ts +8 -8
  215. package/shared/content/context.ts +9 -9
  216. package/shared/content/data/base.ts +32 -32
  217. package/shared/content/data/index.ts +5 -5
  218. package/shared/content/data/type/book.ts +5 -5
  219. package/shared/content/data/type/group.ts +6 -6
  220. package/shared/content/data/type/topic.ts +11 -11
  221. package/shared/content/previousNext.ts +9 -9
  222. package/shared/contributor.ts +5 -5
  223. package/shared/frontNav.ts +41 -41
  224. package/shared/icons.ts +38 -38
  225. package/shared/image.ts +5 -5
  226. package/shared/link.ts +28 -25
  227. package/shared/popover.ts +8 -0
  228. package/shared/types/language.ts +74 -75
  229. package/shared/utils/objectsEqual.ts +4 -4
  230. package/shared/utils/stringColor.ts +9 -9
  231. package/test/contentId.test.ts +91 -0
  232. package/tsconfig.json +8 -8
  233. package/utils/stress.ts +9 -9
  234. package/app/components/main/utils/ContentFlag.vue +0 -15
  235. package/app/styles/default.scss +0 -83
  236. package/server/plugin/bitran/products/link.ts +0 -116
  237. package/server/plugin/bitran/setup.ts +0 -9
  238. package/server/plugin/content/absoluteId.ts +0 -94
  239. package/shared/bitran/context.ts +0 -8
  240. package/shared/bitran/default.ts +0 -46
  241. package/shared/bitran/link/Link.vue +0 -167
  242. package/shared/bitran/link/factory.ts +0 -24
  243. package/shared/bitran/link/icon.svg +0 -3
  244. package/shared/bitran/link/languages/en.ts +0 -7
  245. package/shared/bitran/link/languages/ru.ts +0 -7
  246. package/shared/bitran/link/renderer.ts +0 -21
  247. package/shared/bitran/link/shared.ts +0 -17
  248. package/shared/bitran/link/target.ts +0 -134
  249. package/shared/bitran/link/transpiler.ts +0 -10
  250. package/shared/bitran/location.ts +0 -166
  251. package/test/bitran/link/target.test.ts +0 -141
  252. package/test/bitran/location.test.ts +0 -143
@@ -1,230 +1,216 @@
1
- import { BlockNode, type ElementNode } from '@bitran-js/core';
2
- import type { BitranTranspiler } from '@bitran-js/transpiler';
3
- import { IncludeNode } from '@erudit-js/bitran-elements/include/shared';
4
- import {
5
- AliasesNode,
6
- tryReplaceAlias,
7
- type Aliases,
8
- } from '@erudit-js/bitran-elements/aliases/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
- import {
14
- toAbsoluteContentId,
15
- toAbsoluteContentLocation,
16
- } from '@server/content/absoluteId';
17
-
18
- import type { BitranContext } from '@erudit/shared/bitran/context';
19
- import {
20
- parseBitranLocation,
21
- parsePartialBitranLocation,
22
- stringifyBitranLocation,
23
- } from '@erudit/shared/bitran/location';
24
- import { createLinkTarget } from '@erudit/shared/bitran/link/target';
25
- import { LinkNode } from '@erudit/shared/bitran/link/shared';
26
-
27
- export type TraverseEnterFn = (payload: {
28
- _location: string;
29
- _bitranTranspiler: BitranTranspiler;
30
- _biCode: string;
31
- }) => Promise<any>;
32
-
33
- export type TraverseStepFn = (payload: {
34
- _location: string;
35
- _bitranTranspiler: BitranTranspiler;
36
- _node: ElementNode;
37
- }) => Promise<any>;
38
-
39
- export type TraverseLeaveFn = (payload: { _location: string }) => Promise<any>;
40
-
41
- /**
42
- * This operation is heavy as fuck.
43
- * It consumes a lot of memory and is slow.
44
- * Use as rarely as possible!
45
- */
46
- export async function traverseInclude(
47
- includeNode: IncludeNode,
48
- context: BitranContext,
49
- listeners: {
50
- enter?: TraverseEnterFn;
51
- step?: TraverseStepFn;
52
- leave?: TraverseLeaveFn;
53
- },
54
- ) {
55
- const entryLocation = stringifyBitranLocation(
56
- parsePartialBitranLocation(includeNode.id, context.location),
57
- );
58
-
59
- const travelMap: Record<string, string | null> = {
60
- // Not displayed when error, but needed for checking infinite loops
61
- [entryLocation]: null,
62
- };
63
-
64
- try {
65
- await _traverseStep(
66
- includeNode,
67
- entryLocation,
68
- context.aliases,
69
- listeners,
70
- travelMap,
71
- );
72
- } catch (message) {
73
- let finalMessage = `Include Traversal Error!\n\n${message}\n\n`;
74
-
75
- for (const [location, includeTarget] of Object.entries(
76
- travelMap,
77
- ).reverse()) {
78
- if (includeTarget === null) continue;
79
-
80
- finalMessage += `at "${printIncludeTarget(includeTarget)}" in "${location}"\n`;
81
- }
82
-
83
- throw new Error(finalMessage);
84
- }
85
- }
86
-
87
- async function _traverseStep(
88
- includeNode: IncludeNode,
89
- location: string,
90
- aliases: Aliases,
91
- listeners: {
92
- enter?: TraverseEnterFn;
93
- step?: TraverseStepFn;
94
- leave?: TraverseLeaveFn;
95
- },
96
- travelMap: Record<string, string | null>,
97
- ) {
98
- let includeTargetLocation: string;
99
-
100
- try {
101
- const parsedLocation = parseBitranLocation(location);
102
-
103
- includeTargetLocation = stringifyBitranLocation(
104
- parsePartialBitranLocation(
105
- tryReplaceAlias(includeNode.parseData.location, aliases),
106
- parsedLocation,
107
- ),
108
- );
109
-
110
- includeTargetLocation = toAbsoluteContentLocation(
111
- includeTargetLocation,
112
- parsedLocation.path!,
113
- );
114
- } catch (error) {
115
- travelMap[location] = includeNode.parseData.location;
116
- throw error;
117
- }
118
-
119
- if (includeTargetLocation in travelMap)
120
- throw `Include "${printIncludeTarget(includeNode.parseData.location)}" targets "${includeTargetLocation}" which creates infinite loop!`;
121
-
122
- travelMap[location] = includeNode.parseData.location;
123
-
124
- //
125
- // Loading Unique this Include is referencing to.
126
- //
127
-
128
- const dbUnique = await ERUDIT_SERVER.DB.manager.findOne(DbUnique, {
129
- where: { location: includeTargetLocation },
130
- });
131
-
132
- if (!dbUnique)
133
- throw `Include "${printIncludeTarget(includeNode.parseData.location)}" is targeting to non-existing unique "${includeTargetLocation}"!`;
134
-
135
- //
136
- // Creating Bitran core within loaded unique's location context.
137
- //
138
-
139
- const context: BitranContext = {
140
- location: parseBitranLocation(includeTargetLocation),
141
- aliases: dbUnique.context.aliases,
142
- };
143
-
144
- const bitranTranspiler = await createBitranTranspiler();
145
-
146
- listeners.enter &&
147
- (await listeners.enter({
148
- _biCode: dbUnique.content,
149
- _location: includeTargetLocation,
150
- _bitranTranspiler: bitranTranspiler,
151
- }));
152
-
153
- //
154
- // Parsing unique content and sub-traversing all includes if any.
155
- //
156
-
157
- let stepErrorMessage: string | undefined;
158
-
159
- await bitranTranspiler.parser.parse(dbUnique.content, {
160
- step: async (node) => {
161
- if (stepErrorMessage) return;
162
-
163
- // Skip Alias nodes to prevent them being injected into calling document context and possibly conflicting with other aliases, includes and links...
164
- if (node instanceof AliasesNode) return;
165
-
166
- // Replacing block ids with absolute ones to make possible to link to them
167
- if (node instanceof BlockNode)
168
- node.meta.id = Object.keys(travelMap)
169
- .concat([location])
170
- .join('__');
171
-
172
- if (node instanceof LinkNode) {
173
- const linkTarget = createLinkTarget(node.parseData.target, {
174
- location: context.location,
175
- aliases: context.aliases ?? {},
176
- });
177
-
178
- switch (linkTarget.type) {
179
- case 'unique':
180
- node.parseData.target = toAbsoluteContentLocation(
181
- linkTarget.strlocation,
182
- context.location?.path!,
183
- );
184
- break;
185
- case 'page':
186
- node.parseData.target = `page|${linkTarget.pageType}|${toAbsoluteContentId(linkTarget.path!, context.location?.path!)}`;
187
- break;
188
- }
189
- }
190
-
191
- if (!(node instanceof IncludeNode)) {
192
- listeners.step &&
193
- (await listeners.step({
194
- _location: includeTargetLocation,
195
- _node: node,
196
- _bitranTranspiler: bitranTranspiler,
197
- }));
198
-
199
- return;
200
- }
201
-
202
- try {
203
- await _traverseStep(
204
- node,
205
- includeTargetLocation,
206
- context.aliases,
207
- listeners,
208
- travelMap,
209
- );
210
- } catch (message: any) {
211
- stepErrorMessage = message;
212
- }
213
- },
214
- });
215
-
216
- if (stepErrorMessage) throw stepErrorMessage;
217
-
218
- //
219
- // Leaving from current Include
220
- //
221
-
222
- listeners.leave &&
223
- (await listeners.leave({
224
- _location: includeTargetLocation,
225
- }));
226
- }
227
-
228
- function printIncludeTarget(target: string) {
229
- return `<~ ${target}`;
230
- }
1
+ import { BlockNode, type ElementNode } from '@bitran-js/core';
2
+ import type { BitranTranspiler } from '@bitran-js/transpiler';
3
+
4
+ import {
5
+ parseBitranLocation,
6
+ parsePartialBitranLocation,
7
+ setEruditBitranRuntime,
8
+ stringifyBitranLocation,
9
+ tryReplaceAlias,
10
+ type BitranAliases,
11
+ type BitranContext,
12
+ } from '@erudit-js/cog/schema';
13
+ import { IncludeNode } from '@erudit-js/bitran-elements/include/shared';
14
+ import { AliasesNode } from '@erudit-js/bitran-elements/aliases/shared';
15
+
16
+ import { createBitranTranspiler } from '@server/bitran/transpiler';
17
+ import { ERUDIT_SERVER } from '@server/global';
18
+ import { DbUnique } from '@server/db/entities/Unique';
19
+ import { getNavBookIds } from '@server/nav/utils';
20
+
21
+ import { toAbsoluteLocation } from '@shared/bitran/contentId';
22
+
23
+ export type TraverseEnterFn = (payload: {
24
+ _location: string;
25
+ _bitranTranspiler: BitranTranspiler;
26
+ _biCode: string;
27
+ }) => Promise<any>;
28
+
29
+ export type TraverseStepFn = (payload: {
30
+ _location: string;
31
+ _bitranTranspiler: BitranTranspiler;
32
+ _node: ElementNode;
33
+ }) => Promise<any>;
34
+
35
+ export type TraverseLeaveFn = (payload: { _location: string }) => Promise<any>;
36
+
37
+ /**
38
+ * This operation is heavy as fuck.
39
+ * It consumes a lot of memory and is slow.
40
+ * Use as rarely as possible!
41
+ */
42
+ export async function traverseInclude(
43
+ includeNode: IncludeNode,
44
+ context: BitranContext,
45
+ listeners: {
46
+ enter?: TraverseEnterFn;
47
+ step?: TraverseStepFn;
48
+ leave?: TraverseLeaveFn;
49
+ },
50
+ ) {
51
+ const entryLocation = stringifyBitranLocation(
52
+ parsePartialBitranLocation(includeNode.id, context.location),
53
+ );
54
+
55
+ const travelMap: Record<string, string | null> = {
56
+ // Not displayed when error, but needed for checking infinite loops
57
+ [entryLocation]: null,
58
+ };
59
+
60
+ try {
61
+ await _traverseStep(
62
+ includeNode,
63
+ entryLocation,
64
+ context.aliases,
65
+ listeners,
66
+ travelMap,
67
+ );
68
+ } catch (message) {
69
+ let finalMessage = `Include Traversal Error!\n\n${message}\n\n`;
70
+
71
+ for (const [location, includeTarget] of Object.entries(
72
+ travelMap,
73
+ ).reverse()) {
74
+ if (includeTarget === null) continue;
75
+
76
+ finalMessage += `at "${printIncludeTarget(includeTarget)}" in "${location}"\n`;
77
+ }
78
+
79
+ throw new Error(finalMessage);
80
+ }
81
+ }
82
+
83
+ async function _traverseStep(
84
+ includeNode: IncludeNode,
85
+ location: string,
86
+ aliases: BitranAliases,
87
+ listeners: {
88
+ enter?: TraverseEnterFn;
89
+ step?: TraverseStepFn;
90
+ leave?: TraverseLeaveFn;
91
+ },
92
+ travelMap: Record<string, string | null>,
93
+ ) {
94
+ let includeTargetLocation: string;
95
+
96
+ try {
97
+ const parsedLocation = parseBitranLocation(location);
98
+
99
+ includeTargetLocation = stringifyBitranLocation(
100
+ parsePartialBitranLocation(
101
+ tryReplaceAlias(includeNode.parseData.location, aliases),
102
+ parsedLocation,
103
+ ),
104
+ );
105
+
106
+ includeTargetLocation = toAbsoluteLocation(
107
+ includeTargetLocation,
108
+ parsedLocation.path!,
109
+ getNavBookIds(),
110
+ );
111
+ } catch (error) {
112
+ travelMap[location] = includeNode.parseData.location;
113
+ throw error;
114
+ }
115
+
116
+ if (includeTargetLocation in travelMap)
117
+ throw `Include "${printIncludeTarget(includeNode.parseData.location)}" targets "${includeTargetLocation}" which creates infinite loop!`;
118
+
119
+ travelMap[location] = includeNode.parseData.location;
120
+
121
+ //
122
+ // Loading Unique this Include is referencing to.
123
+ //
124
+
125
+ const dbUnique = await ERUDIT_SERVER.DB.manager.findOne(DbUnique, {
126
+ where: { location: includeTargetLocation },
127
+ });
128
+
129
+ if (!dbUnique)
130
+ throw `Include "${printIncludeTarget(includeNode.parseData.location)}" is targeting to non-existing unique "${includeTargetLocation}"!`;
131
+
132
+ //
133
+ // Creating Bitran core within loaded unique's location context.
134
+ //
135
+
136
+ const context: BitranContext = {
137
+ location: parseBitranLocation(includeTargetLocation),
138
+ aliases: dbUnique.context.aliases,
139
+ };
140
+
141
+ const bitranTranspiler = await createBitranTranspiler();
142
+
143
+ [bitranTranspiler.parser, bitranTranspiler.stringifier].forEach((item) =>
144
+ setEruditBitranRuntime(item, {
145
+ eruditConfig: ERUDIT_SERVER.CONFIG,
146
+ context: structuredClone(context),
147
+ insideInclude: true,
148
+ }),
149
+ );
150
+
151
+ listeners.enter &&
152
+ (await listeners.enter({
153
+ _biCode: dbUnique.content,
154
+ _location: includeTargetLocation,
155
+ _bitranTranspiler: bitranTranspiler,
156
+ }));
157
+
158
+ //
159
+ // Parsing unique content and sub-traversing all includes if any.
160
+ //
161
+
162
+ let stepErrorMessage: string | undefined;
163
+
164
+ await bitranTranspiler.parser.parse(dbUnique.content, {
165
+ step: async (node) => {
166
+ if (stepErrorMessage) return;
167
+
168
+ // Skip Alias nodes to prevent them being injected into calling document context and possibly conflicting with other aliases, includes and links...
169
+ if (node instanceof AliasesNode) return;
170
+
171
+ // Replacing block ids with absolute ones to make possible to link to them
172
+ if (node instanceof BlockNode)
173
+ node.meta.id = Object.keys(travelMap)
174
+ .concat([location])
175
+ .join('__');
176
+
177
+ if (!(node instanceof IncludeNode)) {
178
+ listeners.step &&
179
+ (await listeners.step({
180
+ _location: includeTargetLocation,
181
+ _node: node,
182
+ _bitranTranspiler: bitranTranspiler,
183
+ }));
184
+
185
+ return;
186
+ }
187
+
188
+ try {
189
+ await _traverseStep(
190
+ node,
191
+ includeTargetLocation,
192
+ context.aliases,
193
+ listeners,
194
+ travelMap,
195
+ );
196
+ } catch (message: any) {
197
+ stepErrorMessage = message;
198
+ }
199
+ },
200
+ });
201
+
202
+ if (stepErrorMessage) throw stepErrorMessage;
203
+
204
+ //
205
+ // Leaving from current Include
206
+ //
207
+
208
+ listeners.leave &&
209
+ (await listeners.leave({
210
+ _location: includeTargetLocation,
211
+ }));
212
+ }
213
+
214
+ function printIncludeTarget(target: string) {
215
+ return `<~ ${target}`;
216
+ }
@@ -1,25 +1,25 @@
1
- import {
2
- decodeBitranLocation,
3
- parseBitranLocation,
4
- } from '@erudit/shared/bitran/location';
5
-
6
- export function parseUrlLocation(urlLocation: string) {
7
- urlLocation = decodeURIComponent(urlLocation);
8
- urlLocation = decodeBitranLocation(urlLocation);
9
-
10
- if (!urlLocation)
11
- throw createError({
12
- statusCode: 500,
13
- statusText: 'Empty content location router parameter!',
14
- });
15
-
16
- try {
17
- return parseBitranLocation(urlLocation);
18
- } catch (error: any) {
19
- throw createError({
20
- statusCode: 404,
21
- statusText:
22
- error?.message || `Can't parse location "${urlLocation}"!`,
23
- });
24
- }
25
- }
1
+ import {
2
+ decodeBitranLocation,
3
+ parseBitranLocation,
4
+ } from '@erudit-js/cog/schema';
5
+
6
+ export function parseUrlLocation(urlLocation: string) {
7
+ urlLocation = decodeURIComponent(urlLocation);
8
+ urlLocation = decodeBitranLocation(urlLocation);
9
+
10
+ if (!urlLocation)
11
+ throw createError({
12
+ statusCode: 500,
13
+ statusText: 'Empty content location router parameter!',
14
+ });
15
+
16
+ try {
17
+ return parseBitranLocation(urlLocation);
18
+ } catch (error: any) {
19
+ throw createError({
20
+ statusCode: 404,
21
+ statusText:
22
+ error?.message || `Can't parse location "${urlLocation}"!`,
23
+ });
24
+ }
25
+ }
@@ -1,83 +1,75 @@
1
- import { BlockErrorNode, type ElementNode } from '@bitran-js/core';
2
- import { IncludeNode } from '@erudit-js/bitran-elements/include/shared';
3
- import {
4
- headingName,
5
- HeadingNode,
6
- } from '@erudit-js/bitran-elements/heading/shared';
7
-
8
- import type { BitranLocation } from '@erudit/shared/bitran/location';
9
- import type { Toc } from '@erudit/shared/bitran/toc';
10
- import { ERUDIT_SERVER } from '@server/global';
11
- import { getRawBitranContent } from './content';
12
- import { createBitranTranspiler } from './transpiler';
13
- import { traverseInclude } from './products/include';
14
-
15
- export async function getBitranToc(location: BitranLocation) {
16
- const rawContent = await getRawBitranContent(location);
17
- const bitranCore = await createBitranTranspiler();
18
-
19
- const toc: Toc = [];
20
-
21
- await bitranCore.parser.parse(rawContent.biCode, {
22
- async step(node) {
23
- if (node instanceof IncludeNode) {
24
- await traverseInclude(node, rawContent.context, {
25
- step: async ({ _node }) => tryAddToToc(_node),
26
- });
27
- } else tryAddToToc(node);
28
- },
29
- });
30
-
31
- return toc;
32
-
33
- function tryAddToToc(node: ElementNode) {
34
- const tocItemBase = {
35
- id: node.id,
36
- productName: node.name,
37
- };
38
-
39
- // Check if node is manually excluded from TOC
40
- if (typeof node.meta?.toc === 'boolean' && !node.meta?.toc) return;
41
-
42
- if (node instanceof HeadingNode) {
43
- toc.push({
44
- ...tocItemBase,
45
- level: node.parseData.level,
46
- title: node.parseData.title,
47
- });
48
- return;
49
- }
50
-
51
- const notHeadingLevel = () => {
52
- // Toc items without heading are at top level
53
- if (toc.length === 0) return 0;
54
-
55
- const lastTocItem = toc.at(-1)!;
56
-
57
- // Going one level deep if previous item was a heading and copy deep level if not
58
- return lastTocItem.productName === headingName
59
- ? lastTocItem.level + 1
60
- : lastTocItem.level;
61
- };
62
-
63
- if (ERUDIT_SERVER.BITRAN_CONFIG?.toc?.includes(node.name)) {
64
- // Erudit Config says to add these products to TOC
65
- toc.push({
66
- ...tocItemBase,
67
- level: notHeadingLevel(),
68
- title: node.meta?.title || node.parseData?.title,
69
- });
70
- return;
71
- }
72
-
73
- if (node.meta?.toc) {
74
- // Show in Toc any product with truthy `toc` meta property
75
- toc.push({
76
- ...tocItemBase,
77
- level: notHeadingLevel(),
78
- title: node.meta?.title || node.parseData?.title,
79
- });
80
- return;
81
- }
82
- }
83
- }
1
+ import { type ElementNode } from '@bitran-js/core';
2
+ import type { BitranLocation } from '@erudit-js/cog/schema';
3
+ import {
4
+ headingName,
5
+ HeadingNode,
6
+ } from '@erudit-js/bitran-elements/heading/shared';
7
+
8
+ import type { Toc } from '@erudit/shared/bitran/toc';
9
+ import { ERUDIT_SERVER } from '@server/global';
10
+ import { getBitranContent } from './content';
11
+ import { createBitranTranspiler } from './transpiler';
12
+
13
+ export async function getBitranToc(location: BitranLocation) {
14
+ const content = await getBitranContent(location, false);
15
+ const bitranCore = await createBitranTranspiler();
16
+
17
+ const toc: Toc = [];
18
+
19
+ await bitranCore.parser.parse(content.biCode, {
20
+ async step(node) {
21
+ tryAddToToc(node as ElementNode);
22
+ },
23
+ });
24
+
25
+ return toc;
26
+
27
+ function tryAddToToc(node: ElementNode) {
28
+ const tocItemBase = {
29
+ id: node.id,
30
+ productName: node.name,
31
+ };
32
+
33
+ // Check if node is manually excluded from TOC
34
+ if (typeof node.meta?.toc === 'boolean' && !node.meta?.toc) return;
35
+
36
+ if (node instanceof HeadingNode) {
37
+ toc.push({
38
+ ...tocItemBase,
39
+ level: node.parseData.level - 1,
40
+ title: node.parseData.title,
41
+ });
42
+ return;
43
+ }
44
+
45
+ const notHeadingLevel = () => {
46
+ // If TOC is empty, we're at the root level
47
+ if (toc.length === 0) return 0;
48
+
49
+ // Find the most recent heading to determine parent level
50
+ for (let i = toc.length - 1; i >= 0; i--) {
51
+ if (toc[i].productName === headingName) {
52
+ // Found a heading, return its level + 1
53
+ return toc[i].level + 1;
54
+ }
55
+ }
56
+
57
+ // No heading found in TOC, place at root level
58
+ return 0;
59
+ };
60
+
61
+ if (
62
+ ERUDIT_SERVER.CONFIG.bitran?.toc?.includes(node.name) ||
63
+ node.meta?.toc
64
+ ) {
65
+ // Erudit Bitran config says to add these products to TOC
66
+ // Or show in TOC any product with truthy `toc` meta property
67
+ toc.push({
68
+ ...tocItemBase,
69
+ level: notHeadingLevel(),
70
+ title: node.meta?.title || node.parseData?.title,
71
+ });
72
+ return;
73
+ }
74
+ }
75
+ }