erudit 3.0.0-dev.17 → 3.0.0-dev.19

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 (250) hide show
  1. package/app/app.vue +193 -191
  2. package/app/assets/icons/graduation.svg +3 -0
  3. package/app/components/Loading.vue +23 -23
  4. package/app/components/SiteAside.vue +393 -393
  5. package/app/components/SiteMain.vue +32 -32
  6. package/app/components/aside/AsideListItem.vue +74 -74
  7. package/app/components/aside/AsideMajor.vue +56 -56
  8. package/app/components/aside/AsideMinor.vue +97 -73
  9. package/app/components/aside/major/PaneContentScroll.vue +23 -23
  10. package/app/components/aside/major/PaneSwitch.vue +54 -54
  11. package/app/components/aside/major/PaneSwitchButton.vue +63 -63
  12. package/app/components/aside/major/SiteInfo.vue +85 -85
  13. package/app/components/aside/major/panes/Language.vue +79 -79
  14. package/app/components/aside/major/panes/Pages.vue +31 -34
  15. package/app/components/aside/major/panes/Search.vue +11 -11
  16. package/app/components/aside/major/panes/nav/Nav.vue +92 -92
  17. package/app/components/aside/major/panes/nav/NavBook.vue +95 -95
  18. package/app/components/aside/major/panes/nav/NavBookLoading.vue +24 -24
  19. package/app/components/aside/major/panes/nav/NavGlobal.vue +16 -16
  20. package/app/components/aside/major/panes/nav/fnav/FNav.vue +105 -105
  21. package/app/components/aside/major/panes/nav/fnav/FNavBook.vue +32 -32
  22. package/app/components/aside/major/panes/nav/fnav/FNavFlags.vue +40 -40
  23. package/app/components/aside/major/panes/nav/fnav/FNavFolder.vue +60 -60
  24. package/app/components/aside/major/panes/nav/fnav/FNavItem.vue +34 -34
  25. package/app/components/aside/major/panes/nav/fnav/FNavSeparator.vue +80 -80
  26. package/app/components/aside/major/panes/nav/fnav/FNavTopic.vue +24 -24
  27. package/app/components/aside/major/panes/other/ItemContent.vue +29 -29
  28. package/app/components/aside/major/panes/other/ItemGenerator.vue +13 -13
  29. package/app/components/aside/major/panes/other/ItemTheme.vue +54 -54
  30. package/app/components/aside/major/panes/other/Other.vue +16 -16
  31. package/app/components/aside/minor/{Contribute.vue → AsideMinorContribute.vue} +175 -145
  32. package/app/components/aside/minor/AsideMinorNews.vue +11 -11
  33. package/app/components/aside/minor/AsideMinorPane.vue +15 -15
  34. package/app/components/aside/minor/AsideMinorTopLink.vue +67 -67
  35. package/app/components/aside/minor/content/AsideMinorContent.vue +89 -92
  36. package/app/components/aside/minor/contributor/AsideMinorContributor.vue +78 -0
  37. package/app/components/aside/minor/contributor/BookContribution.vue +64 -0
  38. package/app/components/aside/minor/topic/AsideMinorTopic.vue +29 -32
  39. package/app/components/aside/minor/topic/TopicContributors.vue +177 -177
  40. package/app/components/aside/minor/topic/TopicNav.vue +49 -49
  41. package/app/components/aside/minor/topic/TopicToc.vue +213 -214
  42. package/app/components/aside/minor/topic/TopicTocItem.vue +32 -32
  43. package/app/components/aside/utils/AsideOverlayPane.vue +40 -40
  44. package/app/components/bitran/BitranContent.vue +90 -91
  45. package/app/components/bitran/RenderWrapper.vue +10 -10
  46. package/app/components/contributor/ContributorAvatar.vue +45 -45
  47. package/app/components/contributor/ContributorListItem.vue +35 -35
  48. package/app/components/main/MainBitranContent.vue +41 -0
  49. package/app/components/main/{utils/Breadcrumb.vue → MainBreadcrumb.vue} +67 -74
  50. package/app/components/main/MainDescription.vue +24 -0
  51. package/app/components/main/{utils/ContentTitle.vue → MainTitle.vue} +72 -63
  52. package/app/components/main/content/ContentBreadcrumb.vue +28 -0
  53. package/app/components/main/{utils → content}/ContentDecoration.vue +29 -29
  54. package/app/components/main/{utils → content}/ContentPopover.vue +188 -188
  55. package/app/components/main/{utils → content}/ContentPopovers.vue +111 -111
  56. package/app/components/main/{utils → content}/ContentReferences.vue +70 -70
  57. package/app/components/main/{utils → content}/ContentSection.vue +45 -45
  58. package/app/components/main/{utils → content}/reference/ReferenceGroup.vue +38 -38
  59. package/app/components/main/{utils → content}/reference/ReferenceItem.vue +70 -70
  60. package/app/components/main/{utils → content}/reference/ReferenceSource.vue +120 -120
  61. package/app/components/main/topic/MainTopic.vue +83 -88
  62. package/app/components/main/topic/TopicPartSwitch.vue +124 -118
  63. package/app/components/preview/Preview.vue +186 -186
  64. package/app/components/preview/PreviewDisplay.vue +139 -139
  65. package/app/components/preview/PreviewFooterAction.vue +73 -73
  66. package/app/components/preview/PreviewLoading.vue +14 -14
  67. package/app/components/preview/PreviewScreen.vue +141 -141
  68. package/app/components/preview/display/Alert.vue +50 -50
  69. package/app/components/preview/display/Custom.vue +18 -18
  70. package/app/components/preview/display/GenericLink.vue +48 -48
  71. package/app/components/preview/display/PageLink.vue +22 -22
  72. package/app/components/preview/display/Unique.vue +46 -55
  73. package/app/components/transition/Fade.vue +19 -19
  74. package/app/components/tree/TreeContainer.vue +11 -11
  75. package/app/components/tree/TreeItem.vue +89 -89
  76. package/app/composables/adsAllowed.ts +11 -0
  77. package/app/composables/bitran.ts +108 -108
  78. package/app/composables/bitranLocation.ts +7 -7
  79. package/app/composables/contentData.ts +38 -38
  80. package/app/composables/contentPage.ts +168 -158
  81. package/app/composables/contentRoute.ts +45 -45
  82. package/app/composables/darkMagic.ts +24 -24
  83. package/app/composables/externalApi.ts +69 -69
  84. package/app/composables/favicon.ts +8 -8
  85. package/app/composables/formatText.ts +99 -99
  86. package/app/composables/majorPane.ts +61 -60
  87. package/app/composables/phrases.ts +77 -65
  88. package/app/composables/theme.ts +29 -29
  89. package/app/composables/url.ts +33 -33
  90. package/app/pages/_test/preview.vue +110 -110
  91. package/app/pages/article/[...articleId].vue +3 -3
  92. package/app/pages/book/[...bookId].vue +42 -47
  93. package/app/pages/contributor/[contributorId].vue +225 -0
  94. package/app/pages/contributors.vue +183 -0
  95. package/app/pages/group/[...groupId].vue +58 -66
  96. package/app/pages/index.vue +32 -32
  97. package/app/pages/practice/[...practice].vue +3 -3
  98. package/app/pages/summary/[...summaryId].vue +3 -3
  99. package/app/plugins/analytics.ts +8 -0
  100. package/app/plugins/prerender.server.ts +22 -22
  101. package/app/scripts/_immediate.js +9 -9
  102. package/app/scripts/aside/index.ts +59 -59
  103. package/app/scripts/aside/major/nav.ts +26 -26
  104. package/app/scripts/aside/minor/state.ts +37 -37
  105. package/app/scripts/aside/minor/topic.ts +3 -3
  106. package/app/scripts/flag.ts +28 -28
  107. package/app/scripts/og.ts +27 -27
  108. package/app/scripts/preview/build.ts +76 -76
  109. package/app/scripts/preview/data/alert.ts +19 -19
  110. package/app/scripts/preview/data/custom.ts +8 -8
  111. package/app/scripts/preview/data/genericLink.ts +24 -24
  112. package/app/scripts/preview/data/pageLink.ts +23 -23
  113. package/app/scripts/preview/data/unique.ts +69 -72
  114. package/app/scripts/preview/data.ts +24 -24
  115. package/app/scripts/preview/display.ts +37 -37
  116. package/app/scripts/preview/footer.ts +9 -9
  117. package/app/scripts/preview/request.ts +51 -51
  118. package/app/scripts/preview/state.ts +63 -63
  119. package/app/styles/_immediate.css +7 -7
  120. package/app/styles/_util.scss +43 -43
  121. package/app/styles/_utils.scss +44 -44
  122. package/app/styles/app.scss +91 -91
  123. package/app/styles/def/_bp.scss +27 -27
  124. package/app/styles/def/_size.scss +7 -7
  125. package/app/styles/def/_z.scss +5 -5
  126. package/app/styles/normalize.scss +49 -49
  127. package/app/styles/partials/_darkMagic.scss +5 -5
  128. package/app/styles/partials/_fnav.scss +15 -15
  129. package/app/styles/partials/_preview.scss +5 -5
  130. package/bin/erudit.mjs +2 -2
  131. package/const.ts +4 -4
  132. package/globalPath.ts +21 -21
  133. package/globals/bitran.ts +1 -1
  134. package/globals/content.ts +27 -27
  135. package/globals/contributor.ts +5 -5
  136. package/globals/erudit.ts +5 -5
  137. package/globals/register.ts +18 -18
  138. package/languages/en.ts +103 -94
  139. package/languages/ru.ts +107 -98
  140. package/module/bitran.ts +66 -66
  141. package/module/config.ts +35 -35
  142. package/module/imports.ts +67 -67
  143. package/module/index.ts +47 -47
  144. package/module/logger.ts +10 -10
  145. package/module/paths.ts +22 -22
  146. package/module/restart.ts +61 -61
  147. package/nuxt.config.ts +131 -131
  148. package/package.json +5 -5
  149. package/server/api/aside/major/nav/bookIds.ts +5 -5
  150. package/server/api/aside/major/nav/bookNav/[...bookId].ts +17 -20
  151. package/server/api/aside/major/nav/global.ts +7 -7
  152. package/server/api/aside/minor/book/[...bookId].ts +18 -0
  153. package/server/api/aside/minor/contributor/[contributorId].ts +18 -0
  154. package/server/api/aside/minor/group/[...groupId].ts +18 -0
  155. package/server/api/aside/minor/news.ts +7 -7
  156. package/server/api/aside/minor/topic.ts +36 -0
  157. package/server/api/bitran/content/[...location].ts +13 -10
  158. package/server/api/bitran/toc/[...location].ts +9 -9
  159. package/server/api/content/data.ts +75 -75
  160. package/server/api/contributor/count.ts +6 -6
  161. package/server/api/contributor/list.ts +44 -0
  162. package/server/api/contributor/page/[contributorId].ts +14 -0
  163. package/server/api/fake/content.ts +11 -11
  164. package/server/api/fake/shared/languages.ts +12 -12
  165. package/server/api/language/functions.ts +12 -12
  166. package/server/api/language/phrase/[phraseId].ts +19 -19
  167. package/server/api/language/phraseIds.ts +8 -8
  168. package/server/api/prerender.ts +19 -120
  169. package/server/api/preview/page/[...parts].ts +78 -78
  170. package/server/api/preview/unique/[...location].ts +48 -61
  171. package/server/plugin/bitran/content.ts +252 -190
  172. package/server/plugin/bitran/elements/include.ts +229 -229
  173. package/server/plugin/bitran/location.ts +43 -39
  174. package/server/plugin/bitran/toc.ts +94 -94
  175. package/server/plugin/bitran/transpiler.ts +18 -18
  176. package/server/plugin/build/close.ts +12 -12
  177. package/server/plugin/build/jobs/content/builderArgs.ts +8 -8
  178. package/server/plugin/build/jobs/content/generic.ts +191 -191
  179. package/server/plugin/build/jobs/content/parse.ts +113 -113
  180. package/server/plugin/build/jobs/content/path.ts +6 -6
  181. package/server/plugin/build/jobs/content/type/book.ts +9 -9
  182. package/server/plugin/build/jobs/content/type/group.ts +37 -37
  183. package/server/plugin/build/jobs/content/type/topic.ts +36 -36
  184. package/server/plugin/build/jobs/contributors.ts +69 -66
  185. package/server/plugin/build/jobs/language.ts +36 -36
  186. package/server/plugin/build/jobs/nav.ts +345 -345
  187. package/server/plugin/build/process.ts +32 -32
  188. package/server/plugin/build/rebuild.ts +66 -66
  189. package/server/plugin/build/setup.ts +19 -19
  190. package/server/plugin/content/context.ts +119 -119
  191. package/server/plugin/db/entities/Book.ts +7 -7
  192. package/server/plugin/db/entities/Content.ts +45 -45
  193. package/server/plugin/db/entities/Contribution.ts +10 -10
  194. package/server/plugin/db/entities/Contributor.ts +25 -16
  195. package/server/plugin/db/entities/File.ts +10 -10
  196. package/server/plugin/db/entities/Group.ts +14 -14
  197. package/server/plugin/db/entities/Hash.ts +15 -15
  198. package/server/plugin/db/entities/Topic.ts +20 -20
  199. package/server/plugin/db/entities/Unique.ts +21 -21
  200. package/server/plugin/db/reset.ts +12 -12
  201. package/server/plugin/db/setup.ts +49 -49
  202. package/server/plugin/global.ts +16 -16
  203. package/server/plugin/importer.ts +16 -16
  204. package/server/plugin/index.ts +9 -9
  205. package/server/plugin/logger.ts +23 -23
  206. package/server/plugin/nav/node.ts +27 -27
  207. package/server/plugin/nav/utils.ts +179 -175
  208. package/server/plugin/repository/asideMinor.ts +51 -0
  209. package/server/plugin/repository/book.ts +39 -21
  210. package/server/plugin/repository/content.ts +240 -240
  211. package/server/plugin/repository/contentId.ts +40 -40
  212. package/server/plugin/repository/contributor.ts +98 -8
  213. package/server/plugin/repository/file.ts +10 -10
  214. package/server/plugin/repository/frontNav.ts +145 -145
  215. package/server/plugin/repository/topic.ts +35 -35
  216. package/server/tsconfig.json +9 -9
  217. package/shared/aside/minor.ts +55 -51
  218. package/shared/asset.ts +22 -22
  219. package/shared/bitran/content.ts +9 -0
  220. package/shared/bitran/contentId.ts +56 -56
  221. package/shared/bitran/toc.ts +8 -8
  222. package/shared/breadcrumb.ts +7 -0
  223. package/shared/content/bookId.ts +12 -12
  224. package/shared/content/context.ts +9 -9
  225. package/shared/content/data/base.ts +32 -32
  226. package/shared/content/data/index.ts +5 -5
  227. package/shared/content/data/type/book.ts +5 -5
  228. package/shared/content/data/type/group.ts +6 -6
  229. package/shared/content/data/type/topic.ts +11 -11
  230. package/shared/content/previousNext.ts +9 -9
  231. package/shared/contributor.ts +33 -5
  232. package/shared/frontNav.ts +41 -41
  233. package/shared/icons.ts +38 -38
  234. package/shared/image.ts +5 -5
  235. package/shared/link.ts +28 -28
  236. package/shared/popover.ts +8 -8
  237. package/shared/types/language.ts +79 -74
  238. package/shared/utils/objectsEqual.ts +4 -4
  239. package/shared/utils/stringColor.ts +9 -9
  240. package/test/contentId.test.ts +91 -91
  241. package/tsconfig.json +8 -8
  242. package/utils/contentPath.ts +67 -67
  243. package/utils/slash.ts +11 -11
  244. package/utils/stress.ts +9 -9
  245. package/app/components/aside/minor/AsideMinorContributor.vue +0 -5
  246. package/app/components/main/utils/ContentDescription.vue +0 -19
  247. package/app/composables/bitranContent.ts +0 -92
  248. package/app/pages/members.vue +0 -6
  249. package/server/api/aside/minor/path.ts +0 -82
  250. package/shared/bitran/stringContent.ts +0 -6
@@ -1,74 +1,79 @@
1
- export interface EruditPhrases {
2
- _language_title: string;
3
- _language_code: string;
4
-
5
- site_info_title: string;
6
- site_info_slogan: string;
7
- seo_index_title: string;
8
- seo_index_description: string;
9
- seo_article_description: (contentTitle: string) => string;
10
- seo_summary_description: (contentTitle: string) => string;
11
- seo_practice_description: (contentTitle: string) => string;
12
- index: string;
13
- pages: string;
14
- search: string;
15
- language: string;
16
- other: string;
17
- ads_replacer: string;
18
- theme: string;
19
- theme_system: string;
20
- theme_light: string;
21
- theme_dark: string;
22
- content: string;
23
- main_page: string;
24
- members: string;
25
- add_translation: string;
26
- empty_nav: string;
27
- flag_dev: string;
28
- flag_dev_description: string;
29
- flag_advanced: string;
30
- flag_advanced_description: string;
31
- flag_secondary: string;
32
- flag_secondary_description: string;
33
- popover_dependencies: string;
34
- popover_dependencies_description: string;
35
- to_index: string;
36
- about_book: string;
37
- close: string;
38
- back: string;
39
- goto: string;
40
- error: string;
41
- external_link: string;
42
- external_link_warn: string;
43
- internal_link: string;
44
- internal_link_warn: string;
45
- book: string;
46
- group: string;
47
- topic: string;
48
- article: string;
49
- summary: string;
50
- practice: string;
51
- contributor: string;
52
- element_id: string;
53
- preview_missing_title: string;
54
- preview_missing_explain: string;
55
- preview_missing_explain_mismatch: string;
56
- preview_hash_mismatch_title: string;
57
- preview_hash_mismatch_explain: string;
58
- current_page_hash: string;
59
- expected_page_hash: string;
60
- empty_toc: string;
61
- contributors: string;
62
- no_contributors: string;
63
- make_contribution: string;
64
- material_improvement: string;
65
- how_to_improve: string;
66
- edit_page: string;
67
- report_problem: string;
68
- references: string;
69
- reference_source_featured: string;
70
- references_description: string;
71
- }
72
-
73
- export type EruditPhraseId = keyof Partial<EruditPhrases>;
74
- export type EruditPhrase = EruditPhrases[keyof EruditPhrases];
1
+ export interface EruditPhrases {
2
+ _language_title: string;
3
+ _language_code: string;
4
+
5
+ site_info_title: string;
6
+ site_info_slogan: string;
7
+ seo_index_title: string;
8
+ seo_index_description: string;
9
+ seo_article_description: (contentTitle: string) => string;
10
+ seo_summary_description: (contentTitle: string) => string;
11
+ seo_practice_description: (contentTitle: string) => string;
12
+ index: string;
13
+ pages: string;
14
+ search: string;
15
+ language: string;
16
+ other: string;
17
+ ads_replacer: string;
18
+ theme: string;
19
+ theme_system: string;
20
+ theme_light: string;
21
+ theme_dark: string;
22
+ content: string;
23
+ main_page: string;
24
+ contributors: string;
25
+ contributors_page_description: string;
26
+ contributors_page_invite: (link: string) => string;
27
+ contributor: string;
28
+ contribution: string;
29
+ contributions_explain: (count: number) => string;
30
+ contributor_description: (name: string) => string;
31
+ editor: string;
32
+ add_translation: string;
33
+ empty_nav: string;
34
+ flag_dev: string;
35
+ flag_dev_description: string;
36
+ flag_advanced: string;
37
+ flag_advanced_description: string;
38
+ flag_secondary: string;
39
+ flag_secondary_description: string;
40
+ popover_dependencies: string;
41
+ popover_dependencies_description: string;
42
+ to_index: string;
43
+ about_book: string;
44
+ close: string;
45
+ back: string;
46
+ goto: string;
47
+ error: string;
48
+ external_link: string;
49
+ external_link_warn: string;
50
+ internal_link: string;
51
+ internal_link_warn: string;
52
+ book: string;
53
+ group: string;
54
+ topic: string;
55
+ article: string;
56
+ summary: string;
57
+ practice: string;
58
+ element_id: string;
59
+ preview_missing_title: string;
60
+ preview_missing_explain: string;
61
+ preview_missing_explain_mismatch: string;
62
+ preview_hash_mismatch_title: string;
63
+ preview_hash_mismatch_explain: string;
64
+ current_page_hash: string;
65
+ expected_page_hash: string;
66
+ empty_toc: string;
67
+ no_contributors: string;
68
+ make_contribution: string;
69
+ material_improvement: string;
70
+ how_to_improve: string;
71
+ edit_page: string;
72
+ report_problem: string;
73
+ references: string;
74
+ reference_source_featured: string;
75
+ references_description: string;
76
+ }
77
+
78
+ export type EruditPhraseId = keyof Partial<EruditPhrases>;
79
+ export type EruditPhrase = EruditPhrases[keyof EruditPhrases];
@@ -1,4 +1,4 @@
1
- export function objectsEqual(a: any, b: any) {
2
- const str = (obj: any) => JSON.stringify(obj)?.split('').sort().join('');
3
- return str(a) === str(b);
4
- }
1
+ export function objectsEqual(a: any, b: any) {
2
+ const str = (obj: any) => JSON.stringify(obj)?.split('').sort().join('');
3
+ return str(a) === str(b);
4
+ }
@@ -1,9 +1,9 @@
1
- export function stringColor(text: string) {
2
- let hash = 0;
3
-
4
- for (let i = 0; i < text.length; i++) {
5
- hash = text.charCodeAt(i) + ((hash << 5) - hash);
6
- }
7
-
8
- return `hsl(${hash % 360}, 85%, 35%)`;
9
- }
1
+ export function stringColor(text: string) {
2
+ let hash = 0;
3
+
4
+ for (let i = 0; i < text.length; i++) {
5
+ hash = text.charCodeAt(i) + ((hash << 5) - hash);
6
+ }
7
+
8
+ return `hsl(${hash % 360}, 85%, 35%)`;
9
+ }
@@ -1,91 +1,91 @@
1
- import {
2
- toAbsoluteContentPath,
3
- resolveContentPath,
4
- } from '@erudit/shared/bitran/contentId';
5
-
6
- describe('resolveContentPath', () => {
7
- it('should handle empty paths', () => {
8
- expect(resolveContentPath('')).toBe('');
9
- });
10
-
11
- it('should not change paths without special symbols', () => {
12
- expect(resolveContentPath('foo/bar/baz')).toBe('foo/bar/baz');
13
- });
14
-
15
- it('should skip empty path parts', () => {
16
- expect(resolveContentPath('/foo///bar/baz/')).toBe('foo/bar/baz');
17
- });
18
-
19
- it('should handle ".." parts', () => {
20
- const testCases = [
21
- ['foo/bar/../baz', 'foo/baz'],
22
- ['../../../foo/bar/baz', 'foo/bar/baz'],
23
- ['foo/../../../bar/baz', 'bar/baz'],
24
- ['../../..', ''],
25
- ];
26
-
27
- for (const [input, expected] of testCases) {
28
- expect(resolveContentPath(input!)).toBe(expected);
29
- }
30
- });
31
-
32
- it('should handle "." parts', () => {
33
- const testCases = [
34
- ['.', ''],
35
- ['./foo/bar/baz', 'foo/bar/baz'],
36
- ['./foo/./bar', 'foo/bar'],
37
- ['foo/./././bar', 'foo/bar'],
38
- ];
39
-
40
- for (const [input, expected] of testCases) {
41
- expect(resolveContentPath(input!)).toBe(expected);
42
- }
43
- });
44
-
45
- it('should handle paths with both "." and ".." parts', () => {
46
- const testCases = [
47
- ['./../.', ''],
48
- ['foo/./../bar', 'foo/bar'],
49
- ];
50
-
51
- for (const [input, expected] of testCases) {
52
- expect(resolveContentPath(input!)).toBe(expected);
53
- }
54
- });
55
- });
56
-
57
- describe('toAbsoluteContentPath', () => {
58
- const bookIds = ['combinatorics', 'group/book'];
59
-
60
- it('should not use context on absolute paths', () => {
61
- expect(
62
- toAbsoluteContentPath('/foo/bar/../baz', 'qux/vaz', bookIds),
63
- ).toBe('foo/baz');
64
- });
65
-
66
- it('should fallback to absolute path if not inside book', () => {
67
- expect(
68
- toAbsoluteContentPath('~/foo/bar', 'unknown-book', bookIds),
69
- ).toBe('foo/bar');
70
- });
71
-
72
- it('should correctly handle book-relative paths', () => {
73
- expect(toAbsoluteContentPath('~/foo/bar', 'group/book', bookIds)).toBe(
74
- 'group/book/foo/bar',
75
- );
76
- });
77
-
78
- it('should by default append context before given content id', () => {
79
- const testCases = [
80
- ['baz/qux', 'foo/bar', 'foo/bar/baz/qux'],
81
- ['./baz/qux', 'foo/bar', 'foo/bar/baz/qux'],
82
- ['../baz/qux', 'foo/bar', 'foo/baz/qux'],
83
- ];
84
-
85
- for (const [contentId, context, expected] of testCases) {
86
- expect(toAbsoluteContentPath(contentId!, context!, bookIds)).toBe(
87
- expected,
88
- );
89
- }
90
- });
91
- });
1
+ import {
2
+ toAbsoluteContentPath,
3
+ resolveContentPath,
4
+ } from '@erudit/shared/bitran/contentId';
5
+
6
+ describe('resolveContentPath', () => {
7
+ it('should handle empty paths', () => {
8
+ expect(resolveContentPath('')).toBe('');
9
+ });
10
+
11
+ it('should not change paths without special symbols', () => {
12
+ expect(resolveContentPath('foo/bar/baz')).toBe('foo/bar/baz');
13
+ });
14
+
15
+ it('should skip empty path parts', () => {
16
+ expect(resolveContentPath('/foo///bar/baz/')).toBe('foo/bar/baz');
17
+ });
18
+
19
+ it('should handle ".." parts', () => {
20
+ const testCases = [
21
+ ['foo/bar/../baz', 'foo/baz'],
22
+ ['../../../foo/bar/baz', 'foo/bar/baz'],
23
+ ['foo/../../../bar/baz', 'bar/baz'],
24
+ ['../../..', ''],
25
+ ];
26
+
27
+ for (const [input, expected] of testCases) {
28
+ expect(resolveContentPath(input!)).toBe(expected);
29
+ }
30
+ });
31
+
32
+ it('should handle "." parts', () => {
33
+ const testCases = [
34
+ ['.', ''],
35
+ ['./foo/bar/baz', 'foo/bar/baz'],
36
+ ['./foo/./bar', 'foo/bar'],
37
+ ['foo/./././bar', 'foo/bar'],
38
+ ];
39
+
40
+ for (const [input, expected] of testCases) {
41
+ expect(resolveContentPath(input!)).toBe(expected);
42
+ }
43
+ });
44
+
45
+ it('should handle paths with both "." and ".." parts', () => {
46
+ const testCases = [
47
+ ['./../.', ''],
48
+ ['foo/./../bar', 'foo/bar'],
49
+ ];
50
+
51
+ for (const [input, expected] of testCases) {
52
+ expect(resolveContentPath(input!)).toBe(expected);
53
+ }
54
+ });
55
+ });
56
+
57
+ describe('toAbsoluteContentPath', () => {
58
+ const bookIds = ['combinatorics', 'group/book'];
59
+
60
+ it('should not use context on absolute paths', () => {
61
+ expect(
62
+ toAbsoluteContentPath('/foo/bar/../baz', 'qux/vaz', bookIds),
63
+ ).toBe('foo/baz');
64
+ });
65
+
66
+ it('should fallback to absolute path if not inside book', () => {
67
+ expect(
68
+ toAbsoluteContentPath('~/foo/bar', 'unknown-book', bookIds),
69
+ ).toBe('foo/bar');
70
+ });
71
+
72
+ it('should correctly handle book-relative paths', () => {
73
+ expect(toAbsoluteContentPath('~/foo/bar', 'group/book', bookIds)).toBe(
74
+ 'group/book/foo/bar',
75
+ );
76
+ });
77
+
78
+ it('should by default append context before given content id', () => {
79
+ const testCases = [
80
+ ['baz/qux', 'foo/bar', 'foo/bar/baz/qux'],
81
+ ['./baz/qux', 'foo/bar', 'foo/bar/baz/qux'],
82
+ ['../baz/qux', 'foo/bar', 'foo/baz/qux'],
83
+ ];
84
+
85
+ for (const [contentId, context, expected] of testCases) {
86
+ expect(toAbsoluteContentPath(contentId!, context!, bookIds)).toBe(
87
+ expected,
88
+ );
89
+ }
90
+ });
91
+ });
package/tsconfig.json CHANGED
@@ -1,8 +1,8 @@
1
- {
2
- "extends": "../../playground/.erudit/nuxt/.nuxt/tsconfig.json",
3
- "compilerOptions": {
4
- "experimentalDecorators": true,
5
- "emitDecoratorMetadata": true,
6
- "types": ["@types/jest"]
7
- }
8
- }
1
+ {
2
+ "extends": "../../playground/.erudit/nuxt/.nuxt/tsconfig.json",
3
+ "compilerOptions": {
4
+ "experimentalDecorators": true,
5
+ "emitDecoratorMetadata": true,
6
+ "types": ["@types/jest"]
7
+ }
8
+ }
@@ -1,67 +1,67 @@
1
- import { readdirSync, statSync } from 'fs';
2
-
3
- // A directory is considered a "content directory" if it contains book, group, or topic with a file having a .js or .ts extension.
4
- // When a directory qualifies as a content directory, its name is simplified by removing any leading digits and a '+' or '-' (e.g., "29+foo" becomes "foo").
5
-
6
- const contentFileRegex = /^(book|group|topic)\.(js|ts)$/i;
7
-
8
- function normalizePath(path: string): string {
9
- return path.replace(/\\/g, '/');
10
- }
11
-
12
- export function isContentDirectory(directory: string): boolean {
13
- if (!statSync(directory).isDirectory()) {
14
- return false;
15
- }
16
-
17
- return readdirSync(directory).some((file) => {
18
- return contentFileRegex.test(file);
19
- });
20
- }
21
-
22
- export function getContentPath(path: string, cwd?: string): string {
23
- path = normalizePath(path);
24
- cwd = cwd ? normalizePath(cwd) : undefined;
25
-
26
- const unresolvedParts = path.split('/').filter(Boolean);
27
- const resolvedParts: string[] = [];
28
-
29
- let currentPath = cwd || '';
30
- while (unresolvedParts.length) {
31
- const currentPart = unresolvedParts.shift()!;
32
- currentPath += '/' + currentPart;
33
- if (isContentDirectory(currentPath)) {
34
- resolvedParts.push(currentPart.replace(/^\d+(?:\+|-)/, ''));
35
- } else {
36
- resolvedParts.push(currentPart);
37
- }
38
- }
39
-
40
- return resolvedParts.join('/');
41
- }
42
-
43
- export function scanContentPaths(directory: string): Record<string, string> {
44
- directory = normalizePath(directory);
45
-
46
- const map: Record<string, string> = {};
47
-
48
- function traverse(currentPath: string) {
49
- const files = readdirSync(currentPath);
50
-
51
- for (const file of files) {
52
- const fullPath = currentPath + '/' + file;
53
- const relativePath = fullPath.slice(directory.length + 1);
54
- const stat = statSync(fullPath);
55
-
56
- if (stat.isDirectory()) {
57
- traverse(fullPath);
58
- } else {
59
- map[getContentPath(relativePath, directory)] = relativePath;
60
- }
61
- }
62
- }
63
-
64
- traverse(directory);
65
-
66
- return map;
67
- }
1
+ import { readdirSync, statSync } from 'fs';
2
+
3
+ // A directory is considered a "content directory" if it contains book, group, or topic with a file having a .js or .ts extension.
4
+ // When a directory qualifies as a content directory, its name is simplified by removing any leading digits and a '+' or '-' (e.g., "29+foo" becomes "foo").
5
+
6
+ const contentFileRegex = /^(book|group|topic)\.(js|ts)$/i;
7
+
8
+ function normalizePath(path: string): string {
9
+ return path.replace(/\\/g, '/');
10
+ }
11
+
12
+ export function isContentDirectory(directory: string): boolean {
13
+ if (!statSync(directory).isDirectory()) {
14
+ return false;
15
+ }
16
+
17
+ return readdirSync(directory).some((file) => {
18
+ return contentFileRegex.test(file);
19
+ });
20
+ }
21
+
22
+ export function getContentPath(path: string, cwd?: string): string {
23
+ path = normalizePath(path);
24
+ cwd = cwd ? normalizePath(cwd) : undefined;
25
+
26
+ const unresolvedParts = path.split('/').filter(Boolean);
27
+ const resolvedParts: string[] = [];
28
+
29
+ let currentPath = cwd || '';
30
+ while (unresolvedParts.length) {
31
+ const currentPart = unresolvedParts.shift()!;
32
+ currentPath += '/' + currentPart;
33
+ if (isContentDirectory(currentPath)) {
34
+ resolvedParts.push(currentPart.replace(/^\d+(?:\+|-)/, ''));
35
+ } else {
36
+ resolvedParts.push(currentPart);
37
+ }
38
+ }
39
+
40
+ return resolvedParts.join('/');
41
+ }
42
+
43
+ export function scanContentPaths(directory: string): Record<string, string> {
44
+ directory = normalizePath(directory);
45
+
46
+ const map: Record<string, string> = {};
47
+
48
+ function traverse(currentPath: string) {
49
+ const files = readdirSync(currentPath);
50
+
51
+ for (const file of files) {
52
+ const fullPath = currentPath + '/' + file;
53
+ const relativePath = fullPath.slice(directory.length + 1);
54
+ const stat = statSync(fullPath);
55
+
56
+ if (stat.isDirectory()) {
57
+ traverse(fullPath);
58
+ } else {
59
+ map[getContentPath(relativePath, directory)] = relativePath;
60
+ }
61
+ }
62
+ }
63
+
64
+ traverse(directory);
65
+
66
+ return map;
67
+ }
package/utils/slash.ts CHANGED
@@ -1,11 +1,11 @@
1
- export function trailingSlash(path: string, add: boolean): string {
2
- if (path === '/') {
3
- return '/';
4
- }
5
-
6
- if (add) {
7
- return path.endsWith('/') ? path : `${path}/`;
8
- }
9
-
10
- return path.endsWith('/') ? path.slice(0, -1) : path;
11
- }
1
+ export function trailingSlash(path: string, add: boolean): string {
2
+ if (path === '/') {
3
+ return '/';
4
+ }
5
+
6
+ if (add) {
7
+ return path.endsWith('/') ? path : `${path}/`;
8
+ }
9
+
10
+ return path.endsWith('/') ? path.slice(0, -1) : path;
11
+ }
package/utils/stress.ts CHANGED
@@ -1,9 +1,9 @@
1
- import chalk, { type ChalkInstance } from 'chalk';
2
-
3
- export function stress(message: string, contentChalk?: ChalkInstance) {
4
- return (
5
- chalk.dim(`'`) +
6
- (contentChalk ? contentChalk(message) : chalk.cyanBright(message)) +
7
- chalk.dim(`'`)
8
- );
9
- }
1
+ import chalk, { type ChalkInstance } from 'chalk';
2
+
3
+ export function stress(message: string, contentChalk?: ChalkInstance) {
4
+ return (
5
+ chalk.dim(`'`) +
6
+ (contentChalk ? contentChalk(message) : chalk.cyanBright(message)) +
7
+ chalk.dim(`'`)
8
+ );
9
+ }
@@ -1,5 +0,0 @@
1
- <template>
2
- <AsideMinorPane>
3
- <div>Contributor</div>
4
- </AsideMinorPane>
5
- </template>
@@ -1,19 +0,0 @@
1
- <script lang="ts" setup>
2
- defineProps<{ description: string }>();
3
- const pretty = await useFormatText();
4
- </script>
5
-
6
- <template>
7
- <section :class="$style.contentDescription">
8
- {{ pretty(description) }}
9
- </section>
10
- </template>
11
-
12
- <style lang="scss" module>
13
- .contentDescription {
14
- padding: var(--_pMainY) var(--_pMainX);
15
- font-weight: 500;
16
- font-size: 1.1em;
17
- color: var(--text);
18
- }
19
- </style>