erudit 3.0.0-dev.11 → 3.0.0-dev.13

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 (62) hide show
  1. package/app/components/SiteMain.vue +1 -1
  2. package/app/components/aside/major/panes/nav/Nav.vue +11 -6
  3. package/app/components/aside/major/panes/nav/NavBook.vue +19 -11
  4. package/app/components/aside/major/panes/nav/fnav/FNavFlags.vue +1 -1
  5. package/app/components/aside/minor/Contribute.vue +2 -2
  6. package/app/components/aside/minor/content/AsideMinorContent.vue +1 -1
  7. package/app/components/aside/minor/topic/AsideMinorTopic.vue +1 -1
  8. package/app/components/aside/minor/topic/TopicContributors.vue +2 -2
  9. package/app/components/aside/minor/topic/TopicToc.vue +1 -6
  10. package/app/components/aside/minor/topic/TopicTocItem.vue +3 -1
  11. package/app/components/main/utils/Breadcrumb.vue +1 -1
  12. package/app/components/main/utils/ContentReferences.vue +1 -1
  13. package/app/components/main/utils/reference/ReferenceGroup.vue +1 -1
  14. package/app/components/main/utils/reference/ReferenceItem.vue +5 -3
  15. package/app/components/main/utils/reference/ReferenceSource.vue +6 -4
  16. package/app/components/preview/PreviewScreen.vue +2 -2
  17. package/app/components/preview/display/PageLink.vue +1 -1
  18. package/app/composables/bitranContent.ts +2 -3
  19. package/app/composables/contentPage.ts +8 -7
  20. package/app/composables/formatText.ts +21 -8
  21. package/app/composables/phrases.ts +0 -16
  22. package/app/plugins/prerender.server.ts +22 -0
  23. package/app/scripts/preview/build.ts +1 -5
  24. package/app/scripts/preview/data/pageLink.ts +1 -0
  25. package/app/styles/normalize.scss +0 -14
  26. package/globals/content.ts +5 -0
  27. package/module/imports.ts +1 -0
  28. package/nuxt.config.ts +10 -5
  29. package/package.json +8 -8
  30. package/server/api/aside/major/nav/bookIds.ts +2 -2
  31. package/server/api/aside/minor/path.ts +19 -11
  32. package/server/api/bitran/content/[...location].ts +4 -2
  33. package/server/api/bitran/toc/[...location].ts +4 -2
  34. package/server/api/content/data.ts +5 -2
  35. package/server/api/prerender.ts +120 -0
  36. package/server/api/preview/page/[...parts].ts +30 -4
  37. package/server/api/preview/unique/{[location].ts → [...location].ts} +4 -3
  38. package/server/plugin/bitran/content.ts +3 -16
  39. package/server/plugin/bitran/elements/include.ts +40 -36
  40. package/server/plugin/bitran/location.ts +24 -10
  41. package/server/plugin/bitran/toc.ts +7 -2
  42. package/server/plugin/bitran/transpiler.ts +10 -1
  43. package/server/plugin/build/jobs/content/generic.ts +5 -6
  44. package/server/plugin/build/jobs/content/parse.ts +5 -1
  45. package/server/plugin/build/jobs/content/type/group.ts +2 -2
  46. package/server/plugin/build/jobs/content/type/topic.ts +2 -2
  47. package/server/plugin/build/jobs/nav.ts +28 -15
  48. package/server/plugin/content/context.ts +5 -2
  49. package/server/plugin/db/entities/Content.ts +0 -4
  50. package/server/plugin/db/setup.ts +1 -1
  51. package/server/plugin/importer.ts +5 -1
  52. package/server/plugin/nav/node.ts +2 -1
  53. package/server/plugin/nav/utils.ts +66 -24
  54. package/server/plugin/repository/content.ts +26 -23
  55. package/server/plugin/repository/contentId.ts +40 -0
  56. package/server/plugin/repository/frontNav.ts +6 -9
  57. package/server/plugin/repository/topic.ts +4 -1
  58. package/shared/aside/minor.ts +2 -2
  59. package/shared/bitran/contentId.ts +12 -44
  60. package/shared/content/bookId.ts +12 -0
  61. package/shared/frontNav.ts +1 -1
  62. package/test/contentId.test.ts +10 -10
@@ -1,22 +1,26 @@
1
1
  import { isTopicPart, locationFromPath } from '@erudit-js/cog/schema';
2
2
 
3
3
  import type { AsideMinorContent, AsideMinorTopic } from '@shared/aside/minor';
4
- import { getBitranToc } from '@erudit/server/plugin/bitran/toc';
4
+ import { getBitranToc } from '@server/bitran/toc';
5
5
  import {
6
6
  getContentContributors,
7
- getFullContentId,
8
7
  getPreviousNext,
9
- } from '@erudit/server/plugin/repository/content';
10
- import { getTopicPartsLinks } from '@erudit/server/plugin/repository/topic';
8
+ } from '@server/repository/content';
9
+ import { getTopicPartsLinks } from '@server/repository/topic';
10
+ import {
11
+ getFullContentId,
12
+ getShortContentId,
13
+ } from '@server/repository/contentId';
11
14
 
12
15
  export default defineEventHandler(async (event) => {
13
16
  const query = getQuery<{ path: string }>(event);
14
17
 
15
- if (!query.path)
18
+ if (!query.path) {
16
19
  throw createError({
17
20
  statusCode: 400,
18
21
  statusText: 'Missing "path" query parameter!',
19
22
  });
23
+ }
20
24
 
21
25
  const path = query.path.substring(1);
22
26
  const pathStart = path.split('/')[0];
@@ -32,14 +36,18 @@ export default defineEventHandler(async (event) => {
32
36
  async function createTopicData(path: string): Promise<AsideMinorTopic> {
33
37
  const location = locationFromPath(path);
34
38
 
35
- if (!location)
39
+ if (!location) {
36
40
  throw createError({
37
41
  statusCode: 400,
38
42
  statusText: `Provided path "${path}" is not a valid topic location!`,
39
43
  });
44
+ }
45
+
46
+ if (location.path) {
47
+ location.path = await getFullContentId(location.path);
48
+ }
40
49
 
41
50
  const contentId = location.path;
42
- const fullContentId = (await getFullContentId(contentId))!;
43
51
 
44
52
  const toc = await getBitranToc(location);
45
53
  const previousNext = await getPreviousNext(contentId);
@@ -48,7 +56,7 @@ async function createTopicData(path: string): Promise<AsideMinorTopic> {
48
56
 
49
57
  return {
50
58
  type: 'topic',
51
- fullContentId,
59
+ topicId: contentId,
52
60
  location,
53
61
  toc,
54
62
  nav: {
@@ -63,14 +71,14 @@ async function createContentData(
63
71
  type: string,
64
72
  path: string,
65
73
  ): Promise<AsideMinorContent> {
66
- const contentId = path.split('/').slice(1).join('/');
67
- const fullContentId = (await getFullContentId(contentId))!;
74
+ const rawContentId = path.split('/').slice(1).join('/');
75
+ const contentId = (await getFullContentId(rawContentId))!;
68
76
  const previousNext = await getPreviousNext(contentId);
69
77
  const contributors = await getContentContributors(contentId);
70
78
 
71
79
  return {
72
80
  type: type as any,
73
- fullContentId,
81
+ contentId,
74
82
  nav: previousNext,
75
83
  contributors,
76
84
  };
@@ -1,8 +1,10 @@
1
- import { parseUrlLocation } from '@server/bitran/location';
1
+ import { parseClientBitranLocation } from '@server/bitran/location';
2
2
  import { getBitranContent } from '@server/bitran/content';
3
3
 
4
4
  export default defineEventHandler(async (event) => {
5
5
  setResponseHeader(event, 'Content-Type', 'application/json; charset=utf-8');
6
- const location = parseUrlLocation(event.context.params!.location || '');
6
+ const location = await parseClientBitranLocation(
7
+ event.context.params!.location,
8
+ );
7
9
  return await getBitranContent(location);
8
10
  });
@@ -1,7 +1,9 @@
1
- import { parseUrlLocation } from '@server/bitran/location';
1
+ import { parseClientBitranLocation } from '@server/bitran/location';
2
2
  import { getBitranToc } from '@server/bitran/toc';
3
3
 
4
4
  export default defineEventHandler(async (event) => {
5
- const location = parseUrlLocation(event.context.params!.location || '');
5
+ const location = await parseClientBitranLocation(
6
+ event.context.params!.location,
7
+ );
6
8
  return await getBitranToc(location);
7
9
  });
@@ -1,6 +1,7 @@
1
1
  import { getTopicPartsLinks } from '@server/repository/topic';
2
2
  import { getContentBookFor } from '@server/repository/book';
3
3
  import { getContentGenericData } from '@server/repository/content';
4
+ import { getFullContentId } from '@server/repository/contentId';
4
5
 
5
6
  import type { ContentGenericData } from '@shared/content/data/base';
6
7
  import type { ContentTopicData } from '@shared/content/data/type/topic';
@@ -8,13 +9,15 @@ import type { ContentGroupData } from '@shared/content/data/type/group';
8
9
  import type { ContentBookData } from '@shared/content/data/type/book';
9
10
 
10
11
  export default defineEventHandler(async (event) => {
11
- const contentId = getQuery(event)?.contentId as string;
12
+ let contentId = getQuery(event)?.contentId as string;
13
+ contentId = await getFullContentId(contentId);
12
14
 
13
- if (!contentId)
15
+ if (!contentId) {
14
16
  throw createError({
15
17
  statusCode: 400,
16
18
  statusText: 'Missing content ID!',
17
19
  });
20
+ }
18
21
 
19
22
  const generic = await getContentGenericData(contentId);
20
23
 
@@ -0,0 +1,120 @@
1
+ import {
2
+ encodeBitranLocation,
3
+ parseBitranLocation,
4
+ stringifyBitranLocation,
5
+ } from '@erudit-js/cog/schema';
6
+
7
+ import { DbUnique } from '@server/db/entities/Unique';
8
+ import { ERUDIT_SERVER } from '@server/global';
9
+ import { DbBook } from '@server/db/entities/Book';
10
+ import { DbTopic } from '@server/db/entities/Topic';
11
+ import { DbGroup } from '@server/db/entities/Group';
12
+ import { DbContributor } from '@server/db/entities/Contributor';
13
+ import { getShortContentId } from '@server/repository/contentId';
14
+
15
+ export default defineEventHandler(async () => {
16
+ const routes: string[] = [];
17
+ routes.push(...language());
18
+ routes.push(...(await previewUniques()));
19
+ routes.push(...(await previewPages()));
20
+
21
+ return routes;
22
+ });
23
+
24
+ //
25
+ //
26
+ //
27
+
28
+ function language() {
29
+ const phraseRoutes = Object.keys(ERUDIT_SERVER.LANGUAGE?.phrases || []).map(
30
+ (phraseId) => `/api/language/phrase/${phraseId}`,
31
+ );
32
+ return ['/api/language/functions', ...phraseRoutes];
33
+ }
34
+
35
+ async function previewUniques() {
36
+ const dbUniques = await ERUDIT_SERVER.DB.manager.find(DbUnique, {
37
+ select: ['location'],
38
+ });
39
+
40
+ if (!dbUniques) {
41
+ return [];
42
+ }
43
+
44
+ const routes: string[] = [];
45
+ for (const dbUnique of dbUniques) {
46
+ const location = parseBitranLocation(dbUnique.location);
47
+
48
+ if (location.path) {
49
+ location.path = await getShortContentId(location.path);
50
+ }
51
+
52
+ routes.push(
53
+ `/api/preview/unique/${encodeBitranLocation(stringifyBitranLocation(location))}`,
54
+ );
55
+ }
56
+ return routes;
57
+ }
58
+
59
+ async function previewPages() {
60
+ const pageRoutes: string[] = [];
61
+
62
+ // Books
63
+
64
+ const dbBooks = await ERUDIT_SERVER.DB.manager.find(DbBook, {
65
+ select: ['contentId'],
66
+ });
67
+
68
+ if (dbBooks) {
69
+ for (const dbBook of dbBooks) {
70
+ const bookId = await getShortContentId(dbBook.contentId);
71
+ pageRoutes.push(`/api/preview/page/book/${bookId}`);
72
+ }
73
+ }
74
+
75
+ // Topics
76
+
77
+ const dbTopics = await ERUDIT_SERVER.DB.manager.find(DbTopic, {
78
+ select: ['contentId', 'parts'],
79
+ });
80
+
81
+ if (dbTopics) {
82
+ for (const dbTopic of dbTopics) {
83
+ const topicId = await getShortContentId(dbTopic.contentId);
84
+ for (const part of dbTopic.parts) {
85
+ pageRoutes.push(`/api/preview/page/${part}/${topicId}`);
86
+ }
87
+ }
88
+ }
89
+
90
+ // Groups
91
+
92
+ const dbGroups = await ERUDIT_SERVER.DB.manager.find(DbGroup, {
93
+ select: ['contentId'],
94
+ });
95
+
96
+ if (dbGroups) {
97
+ for (const dbGroup of dbGroups) {
98
+ const groupId = await getShortContentId(dbGroup.contentId);
99
+ pageRoutes.push(`/api/preview/page/group/${groupId}`);
100
+ }
101
+ }
102
+
103
+ // Contributors
104
+
105
+ const dbContributors = await ERUDIT_SERVER.DB.manager.find(DbContributor, {
106
+ select: ['contributorId'],
107
+ });
108
+
109
+ if (dbContributors) {
110
+ for (const dbContributor of dbContributors) {
111
+ pageRoutes.push(
112
+ `/api/preview/page/contributor/${dbContributor.contributorId}`,
113
+ );
114
+ }
115
+ }
116
+
117
+ // // //
118
+
119
+ return pageRoutes;
120
+ }
@@ -1,13 +1,17 @@
1
+ import type { LinkTargetPageType } from '@erudit-js/bitran-elements/link/target';
2
+ import { isContentType } from '@erudit-js/cog/schema';
3
+
1
4
  import {
2
5
  getContentContext,
3
6
  getTopicPartContext,
4
7
  getContributorContext,
5
- } from '@erudit/server/plugin/content/context';
6
-
7
- import type { LinkTargetPageType } from '@erudit-js/bitran-elements/link/target';
8
+ } from '@server/content/context';
9
+ import { getFullContentId } from '@server/repository/contentId';
10
+ import { ERUDIT_SERVER } from '@server/global';
11
+ import { DbContent } from '@server/db/entities/Content';
8
12
 
9
- import type { PreviewDataPageLink } from '@app/scripts/preview/data/pageLink';
10
13
  import type { Context, ContextItem } from '@erudit/shared/content/context';
14
+ import type { PreviewDataPageLink } from '@app/scripts/preview/data/pageLink';
11
15
 
12
16
  export default defineEventHandler<Promise<PreviewDataPageLink>>(
13
17
  async (event) => {
@@ -37,8 +41,30 @@ export default defineEventHandler<Promise<PreviewDataPageLink>>(
37
41
  .map((c) => c.title)
38
42
  .join(' / ');
39
43
 
44
+ const description = await (async () => {
45
+ if (!isContentType(pageType)) {
46
+ return;
47
+ }
48
+
49
+ const fullContentId = await getFullContentId(contentId);
50
+ const dbContent = await ERUDIT_SERVER.DB.manager.findOne(
51
+ DbContent,
52
+ {
53
+ select: ['description'],
54
+ where: { contentId: fullContentId },
55
+ },
56
+ );
57
+
58
+ if (!dbContent) {
59
+ return;
60
+ }
61
+
62
+ return dbContent.description?.trim();
63
+ })();
64
+
40
65
  return <PreviewDataPageLink>{
41
66
  type: 'page-link',
67
+ description,
42
68
  footer: {
43
69
  secondary:
44
70
  (contextStr ? contextStr + ' • ' : '') +
@@ -2,13 +2,12 @@ import {
2
2
  stringifyBitranLocation,
3
3
  type BitranContext,
4
4
  } from '@erudit-js/cog/schema';
5
- import type { BitranContent } from '@bitran-js/renderer-vue';
6
5
 
7
- import { parseUrlLocation } from '@server/bitran/location';
8
6
  import { getLocationContext } from '@server/content/context';
9
7
  import { ERUDIT_SERVER } from '@server/global';
10
8
  import { DbUnique } from '@server/db/entities/Unique';
11
9
  import { getBitranContent } from '@server/bitran/content';
10
+ import { parseClientBitranLocation } from '@server/bitran/location';
12
11
 
13
12
  import type { Context } from '@shared/content/context';
14
13
  import type { StringBitranContent } from '@erudit/shared/bitran/stringContent';
@@ -26,7 +25,9 @@ interface ReturnType {
26
25
  export default defineEventHandler<Promise<ReturnType>>(async (event) => {
27
26
  setResponseHeader(event, 'Content-Type', 'application/json; charset=utf-8');
28
27
 
29
- const location = parseUrlLocation(getRouterParam(event, 'location') || '');
28
+ const location = await parseClientBitranLocation(
29
+ event.context.params!.location,
30
+ );
30
31
 
31
32
  const context = await getLocationContext(location);
32
33
 
@@ -1,6 +1,5 @@
1
1
  import {
2
2
  BlockErrorNode,
3
- BlockNode,
4
3
  BlocksNode,
5
4
  createRenderData,
6
5
  ElementNode,
@@ -12,7 +11,6 @@ import {
12
11
  isTopicPart,
13
12
  mergeAliases,
14
13
  NO_ALIASES,
15
- setEruditBitranRuntime,
16
14
  stringifyBitranLocation,
17
15
  type BitranContext,
18
16
  type BitranLocation,
@@ -111,17 +109,13 @@ async function createBitranContent(
111
109
  biCode: string,
112
110
  generatePrerenderData: boolean = true,
113
111
  ): Promise<StringBitranContent> {
114
- const bitranTranspiler = await createBitranTranspiler();
115
-
116
112
  const runtime: EruditBitranRuntime = {
117
113
  eruditConfig: ERUDIT_SERVER.CONFIG,
118
- context,
119
114
  insideInclude: false,
115
+ context,
120
116
  };
121
117
 
122
- [bitranTranspiler.parser, bitranTranspiler.stringifier].forEach((item) =>
123
- setEruditBitranRuntime(item, runtime),
124
- );
118
+ const bitranTranspiler = await createBitranTranspiler(runtime);
125
119
 
126
120
  const renderDataStorage: RenderDataStorage = {};
127
121
 
@@ -183,14 +177,7 @@ async function resolveInclude(
183
177
  let _blocks;
184
178
 
185
179
  try {
186
- const blocks: BlockNode[] = [];
187
-
188
- await traverseInclude(includeNode, context, {
189
- step: async ({ _node }) => {
190
- if (_node instanceof BlockNode) blocks.push(_node);
191
- },
192
- });
193
-
180
+ const blocks = await traverseInclude(includeNode, context, {});
194
181
  const blocksNode = new BlocksNode(includeNode);
195
182
  blocksNode.setNodes(blocks);
196
183
  _blocks = blocksNode;
@@ -3,7 +3,6 @@ import type { BitranTranspiler } from '@bitran-js/transpiler';
3
3
  import {
4
4
  parseBitranLocation,
5
5
  parsePartialBitranLocation,
6
- setEruditBitranRuntime,
7
6
  stringifyBitranLocation,
8
7
  tryReplaceAlias,
9
8
  type BitranAliases,
@@ -15,9 +14,10 @@ import { AliasesNode } from '@erudit-js/bitran-elements/aliases/shared';
15
14
  import { createBitranTranspiler } from '@server/bitran/transpiler';
16
15
  import { ERUDIT_SERVER } from '@server/global';
17
16
  import { DbUnique } from '@server/db/entities/Unique';
18
- import { getNavBookIds } from '@server/nav/utils';
19
-
20
- import { toAbsoluteLocation } from '@shared/bitran/contentId';
17
+ import {
18
+ resolveClientContentId,
19
+ serverAbsolutizeContentPath,
20
+ } from '@server/repository/contentId';
21
21
 
22
22
  export type TraverseEnterFn = (payload: {
23
23
  _location: string;
@@ -41,24 +41,27 @@ export async function traverseInclude(
41
41
  step?: TraverseStepFn;
42
42
  leave?: TraverseLeaveFn;
43
43
  },
44
- ) {
45
- const entryLocation = stringifyBitranLocation(
46
- parsePartialBitranLocation(includeNode.id, context.location),
44
+ ): Promise<BlockNode[]> {
45
+ const rawLocation = parsePartialBitranLocation(
46
+ includeNode.id,
47
+ context.location,
47
48
  );
48
49
 
49
- // Always use absolute locations as keys for travelMap to avoid infinite loop bugs
50
- const absEntryLocation = toAbsoluteLocation(
51
- entryLocation,
52
- context.location.path!,
53
- getNavBookIds(),
54
- );
50
+ if (rawLocation.path) {
51
+ rawLocation.path = serverAbsolutizeContentPath(
52
+ rawLocation.path,
53
+ context.location.path!,
54
+ );
55
+ }
56
+
57
+ const absEntryLocation = stringifyBitranLocation(rawLocation);
55
58
 
56
59
  const travelMap: Record<string, string | null> = {
57
60
  [absEntryLocation]: null,
58
61
  };
59
62
 
60
63
  try {
61
- await _traverseStep(
64
+ return await _traverseInclude(
62
65
  includeNode,
63
66
  absEntryLocation,
64
67
  context.aliases,
@@ -79,7 +82,7 @@ export async function traverseInclude(
79
82
  }
80
83
  }
81
84
 
82
- async function _traverseStep(
85
+ async function _traverseInclude(
83
86
  includeNode: IncludeNode,
84
87
  location: string,
85
88
  aliases: BitranAliases,
@@ -89,24 +92,27 @@ async function _traverseStep(
89
92
  leave?: TraverseLeaveFn;
90
93
  },
91
94
  travelMap: Record<string, string | null>,
92
- ) {
95
+ ): Promise<BlockNode[]> {
93
96
  let includeTargetLocation: string;
94
97
 
95
98
  try {
96
99
  const parsedLocation = parseBitranLocation(location);
97
100
 
98
- includeTargetLocation = stringifyBitranLocation(
99
- parsePartialBitranLocation(
101
+ includeTargetLocation = (() => {
102
+ const _location = parsePartialBitranLocation(
100
103
  tryReplaceAlias(includeNode.parseData.location, aliases),
101
104
  parsedLocation,
102
- ),
103
- );
105
+ );
104
106
 
105
- includeTargetLocation = toAbsoluteLocation(
106
- includeTargetLocation,
107
- parsedLocation.path!,
108
- getNavBookIds(),
109
- );
107
+ if (_location.path) {
108
+ _location.path = serverAbsolutizeContentPath(
109
+ _location.path,
110
+ parsedLocation.path!,
111
+ );
112
+ }
113
+
114
+ return stringifyBitranLocation(_location);
115
+ })();
110
116
  } catch (error) {
111
117
  travelMap[location] = includeNode.parseData.location;
112
118
  throw new Error(
@@ -144,15 +150,11 @@ async function _traverseStep(
144
150
  aliases: dbUnique.context.aliases,
145
151
  };
146
152
 
147
- const bitranTranspiler = await createBitranTranspiler();
148
-
149
- [bitranTranspiler.parser, bitranTranspiler.stringifier].forEach((item) =>
150
- setEruditBitranRuntime(item, {
151
- eruditConfig: ERUDIT_SERVER.CONFIG,
152
- context: structuredClone(context),
153
- insideInclude: true,
154
- }),
155
- );
153
+ const bitranTranspiler = await createBitranTranspiler({
154
+ eruditConfig: ERUDIT_SERVER.CONFIG,
155
+ context: structuredClone(context),
156
+ insideInclude: true,
157
+ });
156
158
 
157
159
  if (listeners.enter) {
158
160
  await listeners.enter({
@@ -168,7 +170,7 @@ async function _traverseStep(
168
170
 
169
171
  let stepErrorMessage: string | Error | undefined;
170
172
 
171
- await bitranTranspiler.parser.parse(dbUnique.content, {
173
+ const rootNode = await bitranTranspiler.parser.parse(dbUnique.content, {
172
174
  step: async (node) => {
173
175
  if (stepErrorMessage) return;
174
176
 
@@ -193,7 +195,7 @@ async function _traverseStep(
193
195
  }
194
196
 
195
197
  try {
196
- await _traverseStep(
198
+ await _traverseInclude(
197
199
  node,
198
200
  includeTargetLocation,
199
201
  context.aliases,
@@ -218,6 +220,8 @@ async function _traverseStep(
218
220
  _location: includeTargetLocation,
219
221
  });
220
222
  }
223
+
224
+ return (rootNode.children as BlockNode[]) ?? [];
221
225
  }
222
226
 
223
227
  function printIncludeTarget(target: string) {
@@ -3,23 +3,37 @@ import {
3
3
  parseBitranLocation,
4
4
  } from '@erudit-js/cog/schema';
5
5
 
6
- export function parseUrlLocation(urlLocation: string) {
7
- urlLocation = decodeURIComponent(urlLocation);
8
- urlLocation = decodeBitranLocation(urlLocation);
6
+ import { getFullContentId } from '@server/repository/contentId';
9
7
 
10
- if (!urlLocation)
8
+ export async function parseClientBitranLocation(clientLocation: string) {
9
+ clientLocation = decodeURIComponent(clientLocation);
10
+ clientLocation = decodeBitranLocation(clientLocation);
11
+
12
+ if (!clientLocation) {
11
13
  throw createError({
12
- statusCode: 500,
14
+ statusCode: 400,
13
15
  statusText: 'Empty content location router parameter!',
14
16
  });
17
+ }
15
18
 
16
19
  try {
17
- return parseBitranLocation(urlLocation);
18
- } catch (error: any) {
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
+
19
34
  throw createError({
20
- statusCode: 404,
21
- statusText:
22
- error?.message || `Can't parse location "${urlLocation}"!`,
35
+ statusCode: 400,
36
+ statusText: error,
23
37
  });
24
38
  }
25
39
  }
@@ -1,5 +1,5 @@
1
1
  import { type ElementNode } from '@bitran-js/core';
2
- import type { BitranLocation } from '@erudit-js/cog/schema';
2
+ import { NO_ALIASES, type BitranLocation } from '@erudit-js/cog/schema';
3
3
  import {
4
4
  headingName,
5
5
  HeadingNode,
@@ -16,7 +16,12 @@ import { createBitranTranspiler } from './transpiler';
16
16
 
17
17
  export async function getBitranToc(location: BitranLocation) {
18
18
  const content = await getBitranContent(location, false);
19
- const bitranCore = await createBitranTranspiler();
19
+
20
+ const bitranCore = await createBitranTranspiler({
21
+ eruditConfig: ERUDIT_SERVER.CONFIG,
22
+ insideInclude: false,
23
+ context: { aliases: NO_ALIASES(), location },
24
+ });
20
25
 
21
26
  const toc: Toc = [];
22
27
 
@@ -1,9 +1,18 @@
1
1
  import { defineBitranTranspiler } from '@bitran-js/transpiler';
2
+ import {
3
+ setEruditBitranRuntime,
4
+ type EruditBitranRuntime,
5
+ } from '@erudit-js/cog/schema';
2
6
 
3
7
  import getServerTranspilers from '#erudit/bitran/server';
4
8
 
5
- export async function createBitranTranspiler() {
9
+ export async function createBitranTranspiler(runtime: EruditBitranRuntime) {
6
10
  const serverTranspiler = await getServerTranspilers();
7
11
  const bitranTranspiler = defineBitranTranspiler(serverTranspiler);
12
+
13
+ [bitranTranspiler.parser, bitranTranspiler.stringifier].forEach((item) => {
14
+ setEruditBitranRuntime(item, runtime);
15
+ });
16
+
8
17
  return bitranTranspiler;
9
18
  }
@@ -80,12 +80,11 @@ async function scanContentFiles() {
80
80
 
81
81
  async function addContentItem(navNode: NavNode) {
82
82
  debug.start(
83
- `Adding ${stress(navNode.type)} content item ${stress(navNode.id)}...`,
83
+ `Adding ${stress(navNode.type)} content item ${stress(navNode.shortId)}...`,
84
84
  );
85
85
 
86
86
  const dbContent = new DbContent();
87
- dbContent.contentId = navNode.id;
88
- dbContent.fullId = navNode.fullId;
87
+ dbContent.contentId = navNode.fullId;
89
88
  dbContent.type = navNode.type;
90
89
  dbContent.decoration = getDecoration(navNode);
91
90
  dbContent.ogImage = await getOgImageData(navNode);
@@ -134,7 +133,7 @@ async function addContributions(navNode: NavNode, contributors?: string[]) {
134
133
  if (!contributors || !contributors.length) {
135
134
  if (navNode.type !== 'book' && navNode.type !== 'group')
136
135
  logger.warn(
137
- `${navNode.type.at(0)!.toUpperCase() + navNode.type.slice(1)} ${stress(navNode.id)} has no contributors!`,
136
+ `${navNode.type.at(0)!.toUpperCase() + navNode.type.slice(1)} ${stress(navNode.fullId)} has no contributors!`,
138
137
  );
139
138
 
140
139
  return;
@@ -143,13 +142,13 @@ async function addContributions(navNode: NavNode, contributors?: string[]) {
143
142
  for (const contributorId of contributors) {
144
143
  if (!(await contributorExists(contributorId))) {
145
144
  logger.warn(
146
- `Skipping unknown contributor ${stress(contributorId)} when adding ${navNode.type} ${stress(navNode.id)}!`,
145
+ `Skipping unknown contributor ${stress(contributorId)} when adding ${navNode.type} ${stress(navNode.fullId)}!`,
147
146
  );
148
147
  continue;
149
148
  }
150
149
 
151
150
  const dbContribution = new DbContribution();
152
- dbContribution.contentId = navNode.id;
151
+ dbContribution.contentId = navNode.fullId;
153
152
  dbContribution.contributorId = contributorId;
154
153
  await ERUDIT_SERVER.DB.manager.save(dbContribution);
155
154
  }
@@ -29,7 +29,11 @@ export async function parseBitranContent(
29
29
  context.location = location;
30
30
  context.aliases = NO_ALIASES();
31
31
 
32
- bitranTranspiler ||= await createBitranTranspiler();
32
+ bitranTranspiler ||= await createBitranTranspiler({
33
+ context,
34
+ eruditConfig: ERUDIT_SERVER.CONFIG,
35
+ insideInclude: false,
36
+ });
33
37
 
34
38
  // Tracking heading nodes to deal with them later
35
39
  const headings: HeadingNode[] = [];