erudit 3.0.0-dev.11 → 3.0.0-dev.12

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 (54) 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/fnav/FNavFlags.vue +1 -1
  4. package/app/components/aside/minor/Contribute.vue +2 -2
  5. package/app/components/aside/minor/content/AsideMinorContent.vue +1 -1
  6. package/app/components/aside/minor/topic/AsideMinorTopic.vue +1 -1
  7. package/app/components/aside/minor/topic/TopicContributors.vue +2 -2
  8. package/app/components/aside/minor/topic/TopicToc.vue +1 -6
  9. package/app/components/aside/minor/topic/TopicTocItem.vue +3 -1
  10. package/app/components/main/utils/Breadcrumb.vue +1 -1
  11. package/app/components/preview/PreviewScreen.vue +2 -2
  12. package/app/components/preview/display/PageLink.vue +1 -1
  13. package/app/composables/bitranContent.ts +3 -3
  14. package/app/composables/contentPage.ts +8 -7
  15. package/app/composables/formatText.ts +21 -8
  16. package/app/composables/phrases.ts +0 -16
  17. package/app/plugins/prerender.server.ts +22 -0
  18. package/app/scripts/preview/build.ts +1 -5
  19. package/app/scripts/preview/data/pageLink.ts +1 -0
  20. package/app/styles/normalize.scss +0 -14
  21. package/globals/content.ts +5 -0
  22. package/module/imports.ts +1 -0
  23. package/nuxt.config.ts +1 -5
  24. package/package.json +8 -8
  25. package/server/api/aside/minor/path.ts +19 -11
  26. package/server/api/bitran/content/[...location].ts +4 -2
  27. package/server/api/bitran/toc/[...location].ts +4 -2
  28. package/server/api/content/data.ts +5 -2
  29. package/server/api/prerender.ts +120 -0
  30. package/server/api/preview/page/[...parts].ts +30 -4
  31. package/server/api/preview/unique/{[location].ts → [...location].ts} +4 -3
  32. package/server/plugin/bitran/content.ts +3 -16
  33. package/server/plugin/bitran/elements/include.ts +13 -16
  34. package/server/plugin/bitran/location.ts +24 -10
  35. package/server/plugin/bitran/toc.ts +7 -2
  36. package/server/plugin/bitran/transpiler.ts +10 -1
  37. package/server/plugin/build/jobs/content/generic.ts +10 -5
  38. package/server/plugin/build/jobs/content/type/group.ts +2 -2
  39. package/server/plugin/build/jobs/content/type/topic.ts +2 -2
  40. package/server/plugin/build/jobs/nav.ts +8 -11
  41. package/server/plugin/content/context.ts +4 -1
  42. package/server/plugin/db/entities/Content.ts +0 -4
  43. package/server/plugin/db/entities/ContentId.ts +11 -0
  44. package/server/plugin/db/setup.ts +3 -1
  45. package/server/plugin/importer.ts +5 -1
  46. package/server/plugin/nav/utils.ts +4 -4
  47. package/server/plugin/repository/content.ts +4 -12
  48. package/server/plugin/repository/contentId.ts +26 -0
  49. package/server/plugin/repository/frontNav.ts +4 -4
  50. package/server/plugin/repository/topic.ts +4 -1
  51. package/shared/aside/minor.ts +2 -2
  52. package/shared/bitran/contentId.ts +4 -4
  53. package/shared/content/bookId.ts +11 -0
  54. package/shared/frontNav.ts +1 -1
@@ -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,
@@ -41,7 +40,7 @@ export async function traverseInclude(
41
40
  step?: TraverseStepFn;
42
41
  leave?: TraverseLeaveFn;
43
42
  },
44
- ) {
43
+ ): Promise<BlockNode[]> {
45
44
  const entryLocation = stringifyBitranLocation(
46
45
  parsePartialBitranLocation(includeNode.id, context.location),
47
46
  );
@@ -58,7 +57,7 @@ export async function traverseInclude(
58
57
  };
59
58
 
60
59
  try {
61
- await _traverseStep(
60
+ return await _traverseInclude(
62
61
  includeNode,
63
62
  absEntryLocation,
64
63
  context.aliases,
@@ -79,7 +78,7 @@ export async function traverseInclude(
79
78
  }
80
79
  }
81
80
 
82
- async function _traverseStep(
81
+ async function _traverseInclude(
83
82
  includeNode: IncludeNode,
84
83
  location: string,
85
84
  aliases: BitranAliases,
@@ -89,7 +88,7 @@ async function _traverseStep(
89
88
  leave?: TraverseLeaveFn;
90
89
  },
91
90
  travelMap: Record<string, string | null>,
92
- ) {
91
+ ): Promise<BlockNode[]> {
93
92
  let includeTargetLocation: string;
94
93
 
95
94
  try {
@@ -144,15 +143,11 @@ async function _traverseStep(
144
143
  aliases: dbUnique.context.aliases,
145
144
  };
146
145
 
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
- );
146
+ const bitranTranspiler = await createBitranTranspiler({
147
+ eruditConfig: ERUDIT_SERVER.CONFIG,
148
+ context: structuredClone(context),
149
+ insideInclude: true,
150
+ });
156
151
 
157
152
  if (listeners.enter) {
158
153
  await listeners.enter({
@@ -168,7 +163,7 @@ async function _traverseStep(
168
163
 
169
164
  let stepErrorMessage: string | Error | undefined;
170
165
 
171
- await bitranTranspiler.parser.parse(dbUnique.content, {
166
+ const rootNode = await bitranTranspiler.parser.parse(dbUnique.content, {
172
167
  step: async (node) => {
173
168
  if (stepErrorMessage) return;
174
169
 
@@ -193,7 +188,7 @@ async function _traverseStep(
193
188
  }
194
189
 
195
190
  try {
196
- await _traverseStep(
191
+ await _traverseInclude(
197
192
  node,
198
193
  includeTargetLocation,
199
194
  context.aliases,
@@ -218,6 +213,8 @@ async function _traverseStep(
218
213
  _location: includeTargetLocation,
219
214
  });
220
215
  }
216
+
217
+ return (rootNode.children as BlockNode[]) ?? [];
221
218
  }
222
219
 
223
220
  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
  }
@@ -23,6 +23,7 @@ import { IMPORT } from '@server/importer';
23
23
  import { contributorExists } from '@server/repository/contributor';
24
24
  import { DbContribution } from '@server/db/entities/Contribution';
25
25
  import { DbFile } from '@server/db/entities/File';
26
+ import { DbContentId } from '@server/db/entities/ContentId';
26
27
 
27
28
  import { contentAsset } from '@erudit/shared/asset';
28
29
  import type { ImageData } from '@erudit/shared/image';
@@ -83,9 +84,13 @@ async function addContentItem(navNode: NavNode) {
83
84
  `Adding ${stress(navNode.type)} content item ${stress(navNode.id)}...`,
84
85
  );
85
86
 
87
+ const dbContentId = new DbContentId();
88
+ dbContentId.fullId = navNode.fullId;
89
+ dbContentId.shortId = navNode.id;
90
+ await ERUDIT_SERVER.DB.manager.save(dbContentId);
91
+
86
92
  const dbContent = new DbContent();
87
- dbContent.contentId = navNode.id;
88
- dbContent.fullId = navNode.fullId;
93
+ dbContent.contentId = navNode.fullId;
89
94
  dbContent.type = navNode.type;
90
95
  dbContent.decoration = getDecoration(navNode);
91
96
  dbContent.ogImage = await getOgImageData(navNode);
@@ -134,7 +139,7 @@ async function addContributions(navNode: NavNode, contributors?: string[]) {
134
139
  if (!contributors || !contributors.length) {
135
140
  if (navNode.type !== 'book' && navNode.type !== 'group')
136
141
  logger.warn(
137
- `${navNode.type.at(0)!.toUpperCase() + navNode.type.slice(1)} ${stress(navNode.id)} has no contributors!`,
142
+ `${navNode.type.at(0)!.toUpperCase() + navNode.type.slice(1)} ${stress(navNode.fullId)} has no contributors!`,
138
143
  );
139
144
 
140
145
  return;
@@ -143,13 +148,13 @@ async function addContributions(navNode: NavNode, contributors?: string[]) {
143
148
  for (const contributorId of contributors) {
144
149
  if (!(await contributorExists(contributorId))) {
145
150
  logger.warn(
146
- `Skipping unknown contributor ${stress(contributorId)} when adding ${navNode.type} ${stress(navNode.id)}!`,
151
+ `Skipping unknown contributor ${stress(contributorId)} when adding ${navNode.type} ${stress(navNode.fullId)}!`,
147
152
  );
148
153
  continue;
149
154
  }
150
155
 
151
156
  const dbContribution = new DbContribution();
152
- dbContribution.contentId = navNode.id;
157
+ dbContribution.contentId = navNode.fullId;
153
158
  dbContribution.contributorId = contributorId;
154
159
  await ERUDIT_SERVER.DB.manager.save(dbContribution);
155
160
  }
@@ -12,7 +12,7 @@ export async function buildGroup({
12
12
  config,
13
13
  }: BuilderFunctionArgs<GroupConfig>) {
14
14
  const dbGroup = new DbGroup();
15
- dbGroup.contentId = navNode.id;
15
+ dbGroup.contentId = navNode.fullId;
16
16
  dbGroup.type = config?.type || 'folder';
17
17
 
18
18
  try {
@@ -26,7 +26,7 @@ export async function buildGroup({
26
26
  await parseBitranContent(
27
27
  {
28
28
  type: 'group',
29
- path: navNode.id,
29
+ path: dbGroup.contentId,
30
30
  },
31
31
  strContent,
32
32
  );
@@ -9,7 +9,7 @@ import { parseBitranContent } from '../parse';
9
9
 
10
10
  export async function buildTopic({ navNode }: BuilderFunctionArgs) {
11
11
  const dbTopic = new DbTopic();
12
- dbTopic.contentId = navNode.id;
12
+ dbTopic.contentId = navNode.fullId;
13
13
  const existingTopicParts: TopicPart[] = [];
14
14
 
15
15
  for (const topicPart of topicParts) {
@@ -25,7 +25,7 @@ export async function buildTopic({ navNode }: BuilderFunctionArgs) {
25
25
  await parseBitranContent(
26
26
  {
27
27
  type: topicPart,
28
- path: navNode.id,
28
+ path: dbTopic.contentId,
29
29
  },
30
30
  strContent,
31
31
  );
@@ -1,6 +1,5 @@
1
1
  import { globSync } from 'glob';
2
2
  import chalk from 'chalk';
3
- import { resolvePaths } from '@erudit-js/cog/kit';
4
3
  import {
5
4
  contentTypes,
6
5
  topicParts,
@@ -54,13 +53,15 @@ async function scanChildNodes(
54
53
  parent: NavNode | RootNavNode,
55
54
  insideBook: boolean,
56
55
  ): Promise<{ children: NavNode[] | undefined; newIds: Ids }> {
57
- const currentFsPath = isRootNode(parent) ? '' : parent.path;
56
+ const currentFsPath = isRootNode(parent) ? '' : parent.path + '/';
58
57
 
59
58
  const nodeFsPaths = globSync(
60
- `${PROJECT_DIR}/content/${currentFsPath}/*/{${contentTypes.join(',')}}.{ts,js}`,
61
- )
62
- .sort()
63
- .map((path) => resolvePaths(path));
59
+ `${currentFsPath}*/{${contentTypes.join(',')}}.{ts,js}`,
60
+ {
61
+ cwd: PROJECT_DIR + '/content',
62
+ posix: true,
63
+ },
64
+ ).sort();
64
65
 
65
66
  let newIds: Ids = {};
66
67
  const children: NavNode[] = [];
@@ -77,11 +78,7 @@ async function scanChildNodes(
77
78
 
78
79
  if (!pathParts) continue; // Wrong path pattern
79
80
 
80
- const nodePath = nodeFsPath
81
- .replace(PROJECT_DIR + '/content/', '')
82
- .split('/')
83
- .slice(0, -1)
84
- .join('/');
81
+ const nodePath = nodeFsPath.split('/').slice(0, -1).join('/');
85
82
 
86
83
  if (pathParts.type === 'book' && insideBook) {
87
84
  logger.warn(
@@ -9,6 +9,7 @@ import { ERUDIT_SERVER } from '@server/global';
9
9
  import { getIdsUp, isSkipId } from '@server/nav/utils';
10
10
  import { DbContent } from '@server/db/entities/Content';
11
11
  import { DbContributor } from '@server/db/entities/Contributor';
12
+ import { getFullContentId } from '@server/repository/contentId';
12
13
 
13
14
  import type { Context } from '@shared/content/context';
14
15
  import {
@@ -19,6 +20,8 @@ import {
19
20
  import { CONTENT_TYPE_ICON, ICON, TOPIC_PART_ICON } from '@erudit/shared/icons';
20
21
 
21
22
  export async function getContentContext(contentId: string): Promise<Context> {
23
+ contentId = await getFullContentId(contentId);
24
+
22
25
  const context: Context = [];
23
26
 
24
27
  for (const _contentId of (await getIdsUp(contentId)).reverse()) {
@@ -106,7 +109,7 @@ export async function getLocationContext(
106
109
 
107
110
  async function getDbContent(contentId: string): Promise<DbContent> {
108
111
  const dbContent = await ERUDIT_SERVER.DB.manager.findOne(DbContent, {
109
- select: ['type', 'title', 'fullId', 'contentId'],
112
+ select: ['type', 'title', 'contentId'],
110
113
  where: { contentId },
111
114
  });
112
115
 
@@ -13,10 +13,6 @@ export class DbContent {
13
13
  @PrimaryColumn('varchar')
14
14
  contentId!: string;
15
15
 
16
- @Column('varchar')
17
- @Index({ unique: true })
18
- fullId!: string;
19
-
20
16
  @Column('varchar')
21
17
  type!: ContentType;
22
18
 
@@ -0,0 +1,11 @@
1
+ import { Column, Entity, Index, PrimaryColumn } from 'typeorm';
2
+
3
+ @Entity('contentId')
4
+ export class DbContentId {
5
+ @PrimaryColumn('varchar')
6
+ fullId!: string;
7
+
8
+ @Column('varchar')
9
+ @Index({ unique: true })
10
+ shortId!: string;
11
+ }
@@ -3,6 +3,7 @@ import { DataSource } from 'typeorm';
3
3
 
4
4
  import { PROJECT_DIR } from '#erudit/globalPaths';
5
5
  import { ERUDIT_SERVER } from '@server/global';
6
+ import { logger } from '../logger';
6
7
 
7
8
  // Database Entities
8
9
  import { DbContributor } from './entities/Contributor';
@@ -14,7 +15,7 @@ import { DbHash } from './entities/Hash';
14
15
  import { DbTopic } from './entities/Topic';
15
16
  import { DbUnique } from './entities/Unique';
16
17
  import { DbFile } from './entities/File';
17
- import { logger } from '../logger';
18
+ import { DbContentId } from './entities/ContentId';
18
19
 
19
20
  export async function setupDatabase() {
20
21
  rmSync(PROJECT_DIR + '/.erudit/data.sqlite', { force: true });
@@ -27,6 +28,7 @@ export async function setupDatabase() {
27
28
  dropSchema: true,
28
29
  entities: [
29
30
  DbBook,
31
+ DbContentId,
30
32
  DbContent,
31
33
  DbContribution,
32
34
  DbContributor,
@@ -1,10 +1,14 @@
1
1
  import { createJiti } from 'jiti';
2
- import { ERUDIT_DIR } from '#erudit/globalPaths';
2
+ import { ERUDIT_DIR, PROJECT_DIR } from '#erudit/globalPaths';
3
3
 
4
4
  const jiti = createJiti(ERUDIT_DIR, {
5
5
  // Enable reimporting same files during process in development mode
6
6
  fsCache: !import.meta.dev,
7
7
  moduleCache: !import.meta.dev,
8
+ alias: {
9
+ '#project': PROJECT_DIR,
10
+ '#content': PROJECT_DIR + '/content',
11
+ },
8
12
  });
9
13
 
10
14
  export async function IMPORT(...args: Parameters<typeof jiti.import>) {