erudit 4.1.0 → 4.2.0-dev.1

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 (118) hide show
  1. package/app/assets/icons/update.svg +3 -0
  2. package/app/components/Prose.vue +7 -7
  3. package/app/components/SmartMedia.vue +4 -4
  4. package/app/components/aside/major/contentNav/PaneBookNav.vue +1 -4
  5. package/app/components/aside/minor/content/Toc.vue +24 -1
  6. package/app/components/aside/minor/content/TocItem.vue +2 -1
  7. package/app/components/aside/minor/news/AsideMinorNews.vue +1 -3
  8. package/app/components/aside/minor/news/NewsItem.vue +3 -4
  9. package/app/components/aside/minor/news/RenderNewsElement.vue +4 -11
  10. package/app/components/aside/minor/news/elements/Mix.vue +2 -3
  11. package/app/components/aside/minor/news/elements/P.vue +3 -3
  12. package/app/components/aside/minor/news/elements/Ref.vue +3 -3
  13. package/app/components/aside/minor/news/elements/Text.vue +2 -2
  14. package/app/components/main/MainContentChild.vue +3 -3
  15. package/app/components/main/{MainQuickLink.vue → MainKeyLink.vue} +11 -11
  16. package/app/components/main/{MainQuickLinks.vue → MainKeyLinks.vue} +7 -7
  17. package/app/components/main/MainQuoteLoader.vue +2 -4
  18. package/app/components/main/MainStickyHeader.vue +1 -1
  19. package/app/components/main/MainStickyHeaderPreamble.vue +6 -2
  20. package/app/components/main/MainTopicPartPage.vue +8 -3
  21. package/app/components/main/connections/DepUnique.vue +45 -0
  22. package/app/components/main/connections/Deps.vue +15 -5
  23. package/app/components/main/connections/Externals.vue +4 -4
  24. package/app/components/main/connections/MainConnections.vue +1 -0
  25. package/app/components/main/contentStats/ItemLastChanged.vue +68 -0
  26. package/app/components/main/contentStats/MainContentStats.vue +36 -28
  27. package/app/components/preview/PreviewScreen.vue +2 -2
  28. package/app/components/preview/screen/ContentPage.vue +1 -4
  29. package/app/components/preview/screen/Unique.vue +3 -5
  30. package/app/composables/appElements.ts +2 -4
  31. package/app/composables/asideMajorPane.ts +3 -3
  32. package/app/composables/fetchJson.ts +4 -0
  33. package/app/composables/lastChanged.ts +28 -0
  34. package/app/composables/mainContent.ts +1 -4
  35. package/app/composables/og.ts +43 -35
  36. package/app/composables/phrases.ts +0 -3
  37. package/app/composables/scrollUp.ts +1 -1
  38. package/app/pages/book/[...bookId].vue +5 -1
  39. package/app/pages/contributor/[contributorId].vue +3 -5
  40. package/app/pages/contributors.vue +1 -1
  41. package/app/pages/group/[...groupId].vue +5 -1
  42. package/app/pages/index.vue +1 -1
  43. package/app/pages/page/[...pageId].vue +8 -3
  44. package/app/pages/sponsors.vue +1 -1
  45. package/app/plugins/appSetup/index.ts +0 -5
  46. package/app/plugins/fetchJson.ts +11 -0
  47. package/app/plugins/prerender.server.ts +1 -1
  48. package/app/router.options.ts +1 -1
  49. package/modules/erudit/globals/prose.ts +3 -4
  50. package/modules/erudit/setup/elements/appTemplate.ts +6 -7
  51. package/modules/erudit/setup/elements/{globalTypes.ts → elementGlobalTypes.ts} +21 -21
  52. package/modules/erudit/setup/elements/globalTemplate.ts +29 -23
  53. package/modules/erudit/setup/elements/setup.ts +18 -16
  54. package/modules/erudit/setup/elements/shared.ts +2 -2
  55. package/modules/erudit/setup/elements/tagsTable.ts +1 -1
  56. package/modules/erudit/setup/runtimeConfig.ts +2 -0
  57. package/nuxt.config.ts +2 -2
  58. package/package.json +14 -13
  59. package/server/api/main/content/[...contentTypePath].ts +5 -4
  60. package/server/api/prerender/content.ts +1 -3
  61. package/server/api/preview/contentPage/[...contentTypePath].ts +1 -2
  62. package/server/api/preview/contentUnique/[...contentTypePathUnique].ts +16 -31
  63. package/server/api/problemScript/[...problemScriptPath].ts +73 -4
  64. package/server/erudit/content/global/build.ts +21 -7
  65. package/server/erudit/content/nav/build.ts +4 -4
  66. package/server/erudit/content/repository/children.ts +3 -3
  67. package/server/erudit/content/repository/deps.ts +127 -39
  68. package/server/erudit/content/repository/elementSnippets.ts +16 -16
  69. package/server/erudit/content/repository/stats.ts +30 -22
  70. package/server/erudit/content/repository/topicParts.ts +1 -1
  71. package/server/erudit/content/repository/unique.ts +14 -15
  72. package/server/erudit/content/resolve/index.ts +6 -1
  73. package/server/erudit/content/resolve/page.ts +15 -35
  74. package/server/erudit/content/resolve/topic.ts +33 -164
  75. package/server/erudit/content/resolve/utils/insertContentItem.ts +2 -2
  76. package/server/erudit/content/resolve/utils/insertContentResolved.ts +82 -31
  77. package/server/erudit/content/search.ts +5 -22
  78. package/server/erudit/contributors/build.ts +7 -8
  79. package/server/erudit/db/repository/pushFile.ts +10 -3
  80. package/server/erudit/db/repository/pushProblemScript.ts +14 -3
  81. package/server/erudit/db/schema/contentDeps.ts +3 -0
  82. package/server/erudit/db/schema/contentSnippets.ts +3 -3
  83. package/server/erudit/db/schema/contentUniques.ts +2 -2
  84. package/server/erudit/db/schema/contributors.ts +2 -2
  85. package/server/erudit/db/schema/news.ts +2 -2
  86. package/server/erudit/db/schema/pages.ts +2 -2
  87. package/server/erudit/db/schema/topics.ts +4 -4
  88. package/server/erudit/global.ts +4 -0
  89. package/server/erudit/importer.ts +16 -8
  90. package/server/erudit/index.ts +0 -3
  91. package/server/erudit/language/list/en.ts +1 -0
  92. package/server/erudit/language/list/ru.ts +1 -0
  93. package/server/erudit/news/build.ts +6 -6
  94. package/server/erudit/news/repository/batch.ts +2 -2
  95. package/server/erudit/prose/repository/finalize.ts +22 -25
  96. package/server/erudit/prose/repository/get.ts +3 -5
  97. package/server/erudit/prose/repository/rawToProse.ts +31 -0
  98. package/server/erudit/prose/storage/callout.ts +9 -7
  99. package/server/erudit/prose/storage/image.ts +8 -11
  100. package/server/erudit/prose/storage/link.ts +24 -32
  101. package/server/erudit/prose/storage/problemScript.ts +8 -14
  102. package/server/erudit/prose/storage/video.ts +9 -7
  103. package/server/erudit/repository.ts +4 -4
  104. package/server/routes/file/[...path].ts +1 -1
  105. package/shared/types/contentChildren.ts +5 -2
  106. package/shared/types/contentConnections.ts +9 -0
  107. package/shared/types/elementSnippet.ts +1 -1
  108. package/shared/types/indexPage.ts +3 -0
  109. package/shared/types/language.ts +1 -83
  110. package/shared/types/mainContent.ts +11 -5
  111. package/shared/types/news.ts +2 -2
  112. package/shared/types/preview.ts +3 -2
  113. package/shared/types/runtimeConfig.ts +1 -0
  114. package/shared/types/search.ts +2 -0
  115. package/shared/utils/pages.ts +4 -2
  116. package/shared/utils/stringColor.ts +16 -6
  117. package/server/erudit/prose/repository/resolve.ts +0 -17
  118. package/server/erudit/prose/transform/bundleProblemScript.ts +0 -6
@@ -4,11 +4,11 @@ export async function getContentDependencies(fullId: string) {
4
4
  const hardDependencies: ContentHardDep[] = [];
5
5
 
6
6
  const dbHardDependencies = await ERUDIT.db.query.contentDeps.findMany({
7
- columns: { fromFullId: true, hard: true, reason: true },
7
+ columns: { toFullId: true, hard: true, reason: true },
8
8
  where: and(
9
9
  or(
10
- eq(ERUDIT.db.schema.contentDeps.toFullId, fullId),
11
- like(ERUDIT.db.schema.contentDeps.toFullId, `${fullId}/%`),
10
+ eq(ERUDIT.db.schema.contentDeps.fromFullId, fullId),
11
+ like(ERUDIT.db.schema.contentDeps.fromFullId, `${fullId}/%`),
12
12
  ),
13
13
  eq(ERUDIT.db.schema.contentDeps.hard, true),
14
14
  ),
@@ -16,18 +16,18 @@ export async function getContentDependencies(fullId: string) {
16
16
 
17
17
  const fullId2Reason = dbHardDependencies.reduce((map, dbDependency) => {
18
18
  if (dbDependency.reason) {
19
- map.set(dbDependency.fromFullId, dbDependency.reason);
19
+ map.set(dbDependency.toFullId, dbDependency.reason);
20
20
  }
21
21
  return map;
22
22
  }, new Map<string, string>());
23
23
 
24
- const hardFromFullIds = ERUDIT.contentNav.orderIds(
25
- externalFromFullIds(dbHardDependencies),
24
+ const hardToFullIds = ERUDIT.contentNav.orderIds(
25
+ externalToFullIds(dbHardDependencies),
26
26
  );
27
27
 
28
- for (const fromFullId of hardFromFullIds) {
29
- const reason = fullId2Reason.get(fromFullId)!;
30
- const hardDep = await createContentDep('hard', fromFullId, reason);
28
+ for (const toFullId of hardToFullIds) {
29
+ const reason = fullId2Reason.get(toFullId)!;
30
+ const hardDep = await createContentDep('hard', toFullId, undefined, reason);
31
31
  if (hardDep) {
32
32
  hardDependencies.push(hardDep);
33
33
  }
@@ -40,23 +40,40 @@ export async function getContentDependencies(fullId: string) {
40
40
  const autoDependencies: ContentAutoDep[] = [];
41
41
 
42
42
  const dbAutoDependencies = await ERUDIT.db.query.contentDeps.findMany({
43
- columns: { fromFullId: true, hard: true },
43
+ columns: { toFullId: true, hard: true, uniqueNames: true },
44
44
  where: and(
45
45
  or(
46
- eq(ERUDIT.db.schema.contentDeps.toFullId, fullId),
47
- like(ERUDIT.db.schema.contentDeps.toFullId, `${fullId}/%`),
46
+ eq(ERUDIT.db.schema.contentDeps.fromFullId, fullId),
47
+ like(ERUDIT.db.schema.contentDeps.fromFullId, `${fullId}/%`),
48
48
  ),
49
49
  eq(ERUDIT.db.schema.contentDeps.hard, false),
50
50
  ),
51
51
  });
52
52
 
53
+ // Merge unique names across rows that share the same toFullId
54
+ // (can happen when a topic and its children both dep on the same target).
55
+ const autoUniqueMap = new Map<string, Set<string>>();
56
+ for (const row of dbAutoDependencies) {
57
+ if (!autoUniqueMap.has(row.toFullId)) {
58
+ autoUniqueMap.set(row.toFullId, new Set());
59
+ }
60
+ if (row.uniqueNames) {
61
+ for (const name of row.uniqueNames.split(',')) {
62
+ autoUniqueMap.get(row.toFullId)!.add(name);
63
+ }
64
+ }
65
+ }
66
+
53
67
  // Skip auto-dependency if a hard dependency from the same source exists
54
- const autoFromFullIds = ERUDIT.contentNav
55
- .orderIds(externalFromFullIds(dbAutoDependencies))
56
- .filter((fromFullId) => !fullId2Reason.has(fromFullId));
68
+ const autoToFullIds = ERUDIT.contentNav
69
+ .orderIds(externalToFullIds(dbAutoDependencies))
70
+ .filter((toFullId) => !fullId2Reason.has(toFullId));
57
71
 
58
- for (const fromFullId of autoFromFullIds) {
59
- const autoDep = await createContentDep('auto', fromFullId);
72
+ for (const toFullId of autoToFullIds) {
73
+ const uniquePairs = Array.from(autoUniqueMap.get(toFullId) ?? []).map(
74
+ (uniqueName) => ({ contentFullId: toFullId, uniqueName }),
75
+ );
76
+ const autoDep = await createContentDep('auto', toFullId, uniquePairs);
60
77
  if (autoDep) {
61
78
  autoDependencies.push(autoDep);
62
79
  }
@@ -72,17 +89,17 @@ export async function getContentDependencies(fullId: string) {
72
89
  //
73
90
 
74
91
  // Skip dependency if it originates from current content item or its child
75
- function externalFromFullIds(dbDeps: { fromFullId: string }[]) {
92
+ function externalToFullIds(dbDeps: { toFullId: string }[]) {
76
93
  return dbDeps.reduce((ids, dbDep) => {
77
- const fromFullId = dbDep.fromFullId;
78
- const isFromSelf = fromFullId === fullId;
79
- const isFromChild = fromFullId.startsWith(`${fullId}/`);
94
+ const toFullId = dbDep.toFullId;
95
+ const isToSelf = toFullId === fullId;
96
+ const isToChild = toFullId.startsWith(`${fullId}/`);
80
97
 
81
- if (isFromSelf || isFromChild) {
98
+ if (isToSelf || isToChild) {
82
99
  return ids;
83
100
  }
84
101
 
85
- ids.push(fromFullId);
102
+ ids.push(toFullId);
86
103
  return ids;
87
104
  }, [] as string[]);
88
105
  }
@@ -92,32 +109,50 @@ export async function getContentDependents(
92
109
  fullId: string,
93
110
  ): Promise<ContentAutoDep[]> {
94
111
  const dbDependents = await ERUDIT.db.query.contentDeps.findMany({
95
- columns: { fromFullId: true, toFullId: true },
112
+ columns: { fromFullId: true, toFullId: true, uniqueNames: true },
96
113
  where: or(
97
- eq(ERUDIT.db.schema.contentDeps.fromFullId, fullId),
98
- like(ERUDIT.db.schema.contentDeps.fromFullId, `${fullId}/%`),
114
+ eq(ERUDIT.db.schema.contentDeps.toFullId, fullId),
115
+ like(ERUDIT.db.schema.contentDeps.toFullId, `${fullId}/%`),
99
116
  ),
100
117
  });
101
118
 
102
- // Skip dependent if it targets current content item or its child
103
- const externalTargetFullIds = dbDependents.reduce((ids, dbDependent) => {
104
- const toFullId = dbDependent.toFullId;
105
- const targetsSelf = toFullId === fullId;
106
- const targetsChild = toFullId.startsWith(`${fullId}/`);
119
+ // Group rows by fromFullId, collecting {contentFullId, uniqueName} pairs
120
+ // (toFullId can vary when a dependent references different child pages).
121
+ const fromUniquePairsMap = new Map<
122
+ string,
123
+ { contentFullId: string; uniqueName: string }[]
124
+ >();
125
+ const externalFromFullIds: string[] = [];
107
126
 
108
- if (targetsSelf || targetsChild) {
109
- return ids;
127
+ for (const row of dbDependents) {
128
+ const fromFullId = row.fromFullId;
129
+ const isFromSelf = fromFullId === fullId;
130
+ const isFromChild = fromFullId.startsWith(`${fullId}/`);
131
+
132
+ if (isFromSelf || isFromChild) continue;
133
+
134
+ if (!fromUniquePairsMap.has(fromFullId)) {
135
+ fromUniquePairsMap.set(fromFullId, []);
136
+ externalFromFullIds.push(fromFullId);
110
137
  }
111
138
 
112
- ids.push(toFullId);
113
- return ids;
114
- }, [] as string[]);
139
+ if (row.uniqueNames) {
140
+ for (const name of row.uniqueNames.split(',')) {
141
+ fromUniquePairsMap
142
+ .get(fromFullId)!
143
+ .push({ contentFullId: row.toFullId, uniqueName: name });
144
+ }
145
+ }
146
+ }
115
147
 
116
- // Order targets according to nav structure
117
- const targetFullIds = ERUDIT.contentNav.orderIds(externalTargetFullIds);
148
+ // Order sources according to nav structure
149
+ const fromFullIds = ERUDIT.contentNav.orderIds(externalFromFullIds);
118
150
 
119
151
  const dependents = await Promise.all(
120
- targetFullIds.map((targetFullId) => createContentDep('auto', targetFullId)),
152
+ fromFullIds.map((fromFullId) => {
153
+ const uniquePairs = fromUniquePairsMap.get(fromFullId) ?? [];
154
+ return createContentDep('auto', fromFullId, uniquePairs);
155
+ }),
121
156
  );
122
157
 
123
158
  return dependents.filter((dep): dep is ContentAutoDep => dep !== undefined);
@@ -126,15 +161,18 @@ export async function getContentDependents(
126
161
  async function createContentDep(
127
162
  type: 'auto',
128
163
  fullId: string,
164
+ uniquePairs: { contentFullId: string; uniqueName: string }[],
129
165
  ): Promise<ContentAutoDep | undefined>;
130
166
  async function createContentDep(
131
167
  type: 'hard',
132
168
  fullId: string,
169
+ uniquePairs: undefined,
133
170
  reason: string,
134
171
  ): Promise<ContentHardDep | undefined>;
135
172
  async function createContentDep(
136
173
  type: 'auto' | 'hard',
137
174
  fullId: string,
175
+ uniquePairs?: { contentFullId: string; uniqueName: string }[],
138
176
  reason?: string,
139
177
  ): Promise<ContentDep | undefined> {
140
178
  const navNode = ERUDIT.contentNav.getNodeOrThrow(fullId);
@@ -160,10 +198,60 @@ async function createContentDep(
160
198
  };
161
199
  }
162
200
 
201
+ const uniques =
202
+ uniquePairs && uniquePairs.length > 0
203
+ ? await resolveUniqueEntries(uniquePairs)
204
+ : undefined;
205
+
163
206
  return {
164
207
  type: 'auto',
165
208
  contentType,
166
209
  title,
167
210
  link,
211
+ ...(uniques && uniques.length > 0 ? { uniques } : {}),
168
212
  };
169
213
  }
214
+
215
+ async function resolveUniqueEntries(
216
+ pairs: { contentFullId: string; uniqueName: string }[],
217
+ ): Promise<ContentDepUnique[]> {
218
+ // Deduplicate by "contentFullId/uniqueName" to avoid showing the same
219
+ // element twice when multiple prose types reference it.
220
+ const seen = new Set<string>();
221
+ const unique: typeof pairs = [];
222
+ for (const pair of pairs) {
223
+ const key = `${pair.contentFullId}/${pair.uniqueName}`;
224
+ if (!seen.has(key)) {
225
+ seen.add(key);
226
+ unique.push(pair);
227
+ }
228
+ }
229
+
230
+ const results = await Promise.all(
231
+ unique.map(async ({ contentFullId, uniqueName }) => {
232
+ const dbUnique = await ERUDIT.db.query.contentUniques.findFirst({
233
+ columns: { title: true, prose: true },
234
+ where: and(
235
+ eq(ERUDIT.db.schema.contentUniques.contentFullId, contentFullId),
236
+ eq(ERUDIT.db.schema.contentUniques.uniqueName, uniqueName),
237
+ ),
238
+ });
239
+
240
+ if (!dbUnique) return null;
241
+
242
+ const pageLink = await ERUDIT.repository.content.link(contentFullId);
243
+ const schemaName = dbUnique.prose.schema.name;
244
+
245
+ if (!schemaName) return null;
246
+
247
+ return {
248
+ name: uniqueName,
249
+ title: dbUnique.title ?? undefined,
250
+ link: `${pageLink}?element=${dbUnique.prose.id}`,
251
+ schemaName,
252
+ } satisfies ContentDepUnique;
253
+ }),
254
+ );
255
+
256
+ return results.filter((r): r is ContentDepUnique => r !== null);
257
+ }
@@ -15,7 +15,7 @@ export async function getContentElementSnippets(
15
15
  where: and(
16
16
  eq(ERUDIT.db.schema.contentSnippets.contentFullId, fullId),
17
17
  or(
18
- eq(ERUDIT.db.schema.contentSnippets.quick, true),
18
+ eq(ERUDIT.db.schema.contentSnippets.key, true),
19
19
  eq(ERUDIT.db.schema.contentSnippets.seo, true),
20
20
  ),
21
21
  ),
@@ -45,27 +45,27 @@ export async function getContentElementSnippets(
45
45
  title: snippetData.title!,
46
46
  };
47
47
 
48
- if (snippetData.quick) {
49
- snippet.quick = {};
50
- let quickTitle: string | undefined;
51
- let quickDescription: string | undefined;
48
+ if (snippetData.key) {
49
+ snippet.key = {};
50
+ let keyTitle: string | undefined;
51
+ let keyDescription: string | undefined;
52
52
 
53
- if (typeof snippetData.quick === 'string') {
54
- quickTitle = snippetData.quick;
55
- } else if (typeof snippetData.quick === 'object') {
56
- if (snippetData.quick.title) {
57
- quickTitle = snippetData.quick.title;
53
+ if (typeof snippetData.key === 'string') {
54
+ keyTitle = snippetData.key;
55
+ } else if (typeof snippetData.key === 'object') {
56
+ if (snippetData.key.title) {
57
+ keyTitle = snippetData.key.title;
58
58
  }
59
- if (snippetData.quick.description) {
60
- quickDescription = snippetData.quick.description;
59
+ if (snippetData.key.description) {
60
+ keyDescription = snippetData.key.description;
61
61
  }
62
62
  }
63
63
 
64
- if (quickTitle) {
65
- snippet.quick.title = quickTitle;
64
+ if (keyTitle) {
65
+ snippet.key.title = keyTitle;
66
66
  }
67
- if (quickDescription) {
68
- snippet.quick.description = quickDescription;
67
+ if (keyDescription) {
68
+ snippet.key.description = keyDescription;
69
69
  }
70
70
  }
71
71
 
@@ -1,30 +1,38 @@
1
1
  import { and, eq, sql } from 'drizzle-orm';
2
2
 
3
- export async function addContentElementCount(
3
+ export async function updateContentSchemaCounts(
4
4
  fullId: string,
5
- schemaName: string,
6
- amount: number,
5
+ schemaCounts: Record<string, number>,
6
+ // schemaName: string,
7
+ // amount: number,
7
8
  ): Promise<void> {
8
- await ERUDIT.db
9
- .insert(ERUDIT.db.schema.contentElementStats)
10
- .values({
11
- fullId,
12
- schemaName,
13
- count: 0,
14
- })
15
- .onConflictDoNothing();
9
+ const schemasFilter = ERUDIT.config.countElements.flat();
10
+ const filteredSchemaCounts = Object.entries(schemaCounts).filter(
11
+ ([schemaName]) => schemasFilter.includes(schemaName),
12
+ );
16
13
 
17
- await ERUDIT.db
18
- .update(ERUDIT.db.schema.contentElementStats)
19
- .set({
20
- count: sql`${ERUDIT.db.schema.contentElementStats.count} + ${amount}`,
21
- })
22
- .where(
23
- and(
24
- eq(ERUDIT.db.schema.contentElementStats.fullId, fullId),
25
- eq(ERUDIT.db.schema.contentElementStats.schemaName, schemaName),
26
- ),
27
- );
14
+ for (const [schemaName, amount] of filteredSchemaCounts) {
15
+ await ERUDIT.db
16
+ .insert(ERUDIT.db.schema.contentElementStats)
17
+ .values({
18
+ fullId,
19
+ schemaName,
20
+ count: 0,
21
+ })
22
+ .onConflictDoNothing();
23
+
24
+ await ERUDIT.db
25
+ .update(ERUDIT.db.schema.contentElementStats)
26
+ .set({
27
+ count: sql`${ERUDIT.db.schema.contentElementStats.count} + ${amount}`,
28
+ })
29
+ .where(
30
+ and(
31
+ eq(ERUDIT.db.schema.contentElementStats.fullId, fullId),
32
+ eq(ERUDIT.db.schema.contentElementStats.schemaName, schemaName),
33
+ ),
34
+ );
35
+ }
28
36
  }
29
37
 
30
38
  export async function getContentStats(
@@ -35,5 +35,5 @@ export async function getTopicParts(fullId: string): Promise<TopicPart[]> {
35
35
 
36
36
  export async function getDefaultTopicPart(fullId: string): Promise<TopicPart> {
37
37
  const parts = await getTopicParts(fullId);
38
- return parts[0];
38
+ return parts[0]!;
39
39
  }
@@ -1,12 +1,13 @@
1
1
  import { and, eq } from 'drizzle-orm';
2
2
  import {
3
+ isProseElement,
4
+ makeProseElement,
3
5
  mixSchema,
4
- walkElements,
5
6
  WalkNoDeeper,
7
+ walkPreSync,
6
8
  WalkStop,
7
- type AnySchema,
8
9
  type ProseElement,
9
- } from '@jsprose/core';
10
+ } from 'tsprose';
10
11
  import type { ContentProseType } from '@erudit-js/core/content/prose';
11
12
  import { headingSchema } from '@erudit-js/prose/elements/heading/core';
12
13
 
@@ -36,21 +37,18 @@ export async function getContentUnique(
36
37
  export async function getContentHeadingUnique(
37
38
  fullId: string,
38
39
  proseType: ContentProseType,
39
- uniqueName: string,
40
+ uniqueId: string,
40
41
  ) {
41
42
  const contentProse = await ERUDIT.repository.prose.getContent(
42
43
  proseType,
43
44
  fullId,
44
45
  );
45
46
 
46
- const afterHeadingElements: ProseElement<AnySchema>[] = [];
47
+ const afterHeadingElements: ProseElement[] = [];
47
48
  let adding = false;
48
49
 
49
- await walkElements(contentProse, async (element) => {
50
- if (
51
- element.schemaName === headingSchema.name &&
52
- element.uniqueName === uniqueName
53
- ) {
50
+ walkPreSync(contentProse, (element) => {
51
+ if (isProseElement(element, headingSchema) && element.id === uniqueId) {
54
52
  adding = true;
55
53
  }
56
54
 
@@ -66,11 +64,12 @@ export async function getContentHeadingUnique(
66
64
  }
67
65
  });
68
66
 
69
- const mix: ProseElement<typeof mixSchema> = {
70
- __JSPROSE_element: true,
71
- schemaName: mixSchema.name,
72
- children: afterHeadingElements,
73
- } as ProseElement<typeof mixSchema>;
67
+ const mix = makeProseElement({
68
+ schema: mixSchema,
69
+ elementHandler: (proseElement) => {
70
+ proseElement.children = afterHeadingElements;
71
+ },
72
+ });
74
73
 
75
74
  return mix;
76
75
  }
@@ -232,7 +232,12 @@ export async function clearOldContentData(contentIds: string[]) {
232
232
 
233
233
  await ERUDIT.db
234
234
  .delete(ERUDIT.db.schema.contentDeps)
235
- .where(inArray(ERUDIT.db.schema.contentDeps.toFullId, contentIds));
235
+ .where(
236
+ or(
237
+ inArray(ERUDIT.db.schema.contentDeps.toFullId, contentIds),
238
+ inArray(ERUDIT.db.schema.contentDeps.fromFullId, contentIds),
239
+ ),
240
+ );
236
241
 
237
242
  await ERUDIT.db
238
243
  .delete(ERUDIT.db.schema.contentElementStats)
@@ -1,12 +1,10 @@
1
- import { isDocument, type AnyDocument } from '@jsprose/core';
1
+ import { isDocument, type Document } from 'tsprose';
2
2
  import { isContentItem } from '@erudit-js/core/content/item';
3
3
  import type { PageContentItem } from '@erudit-js/core/content/page';
4
- import { isIncludedRawElement } from '@erudit-js/prose';
5
4
 
6
5
  import type { ContentNavNode } from '../nav/types';
7
6
  import { logContentError } from './utils/contentError';
8
7
  import { insertContentItem } from './utils/insertContentItem';
9
- import { resolveEruditProse } from '../../prose/repository/resolve';
10
8
  import { insertContentResolved } from './utils/insertContentResolved';
11
9
 
12
10
  export async function resolvePage(pageNode: ContentNavNode) {
@@ -16,7 +14,7 @@ export async function resolvePage(pageNode: ContentNavNode) {
16
14
 
17
15
  try {
18
16
  const pageModule = await ERUDIT.import<{
19
- content: AnyDocument;
17
+ content: Document;
20
18
  page: PageContentItem;
21
19
  }>(ERUDIT.paths.project(`content/${pageNode.contentRelPath}/page`));
22
20
 
@@ -30,49 +28,31 @@ export async function resolvePage(pageNode: ContentNavNode) {
30
28
 
31
29
  await insertContentItem(pageNode, pageModule.page);
32
30
 
33
- const elementsCount: Record<string, number> = {};
34
-
35
31
  const proseDocument = pageModule.content;
36
- const resolveResult = await resolveEruditProse(
37
- proseDocument.content,
38
- true,
39
- async ({ rawElement }) => {
40
- // Counting elements for statistics
41
-
42
- if (isIncludedRawElement(rawElement)) {
43
- return;
44
- }
45
-
46
- if (
47
- ERUDIT.config.countElements.flat().includes(rawElement.schemaName)
48
- ) {
49
- elementsCount[rawElement.schemaName] =
50
- (elementsCount[rawElement.schemaName] || 0) + 1;
51
- }
52
- },
53
- );
32
+ const result = await ERUDIT.repository.prose.fromRaw({
33
+ rawProse: proseDocument.rawProse,
34
+ toc: { enabled: true },
35
+ snippets: { enabled: true },
36
+ });
54
37
 
55
- if (resolveResult.tocItems?.length) {
38
+ if (result.toc?.length) {
56
39
  await ERUDIT.db.insert(ERUDIT.db.schema.contentToc).values({
57
40
  fullId: pageNode.fullId,
58
- toc: resolveResult.tocItems,
41
+ toc: result.toc,
59
42
  });
60
43
  }
61
44
 
62
- for (const [schemaName, count] of Object.entries(elementsCount)) {
63
- await ERUDIT.repository.content.addElementCount(
64
- pageNode.fullId,
65
- schemaName,
66
- count,
67
- );
68
- }
45
+ await ERUDIT.repository.content.updateSchemaCounts(
46
+ pageNode.fullId,
47
+ result.schemaCounts,
48
+ );
69
49
 
70
50
  await ERUDIT.db.insert(ERUDIT.db.schema.pages).values({
71
51
  fullId: pageNode.fullId,
72
- prose: resolveResult.proseElement,
52
+ prose: result.prose,
73
53
  });
74
54
 
75
- await insertContentResolved(pageNode.fullId, 'page', resolveResult);
55
+ await insertContentResolved(pageNode.fullId, 'page', result);
76
56
  } catch (error) {
77
57
  logContentError(pageNode);
78
58
  throw error;