@erudit-js/prose 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 (208) hide show
  1. package/dist/app/appElement.d.ts +7 -6
  2. package/dist/app/appElement.js +1 -1
  3. package/dist/app/composables/anchor.d.ts +7 -7
  4. package/dist/app/composables/appElement.d.ts +4 -4
  5. package/dist/app/composables/appElement.js +3 -3
  6. package/dist/app/composables/context.d.ts +3 -2
  7. package/dist/app/composables/elementIcon.d.ts +2 -2
  8. package/dist/app/composables/elementIcon.js +1 -1
  9. package/dist/app/composables/language.d.ts +2 -2
  10. package/dist/app/composables/language.js +1 -1
  11. package/dist/app/composables/storage.d.ts +4 -4
  12. package/dist/app/composables/storage.js +0 -4
  13. package/dist/app/default/Mix.vue +2 -2
  14. package/dist/app/default/Text.vue +2 -2
  15. package/dist/app/shared/Prose.vue +3 -3
  16. package/dist/app/shared/Render.vue +5 -14
  17. package/dist/app/shared/block/AsideMenu.vue +2 -2
  18. package/dist/app/shared/block/AsideMenuCopyLink.vue +1 -1
  19. package/dist/app/shared/block/Block.vue +4 -4
  20. package/dist/app/shared/inliner/Inliner.vue +2 -2
  21. package/dist/coreElement.d.ts +25 -7
  22. package/dist/coreElement.js +2 -2
  23. package/dist/elements/accent/Accent.vue +4 -4
  24. package/dist/elements/accent/AccentColumnSection.vue +2 -2
  25. package/dist/elements/accent/AccentRowSections.vue +2 -2
  26. package/dist/elements/accent/app.d.ts +3 -3
  27. package/dist/elements/accent/app.js +2 -2
  28. package/dist/elements/accent/core.d.ts +61 -300
  29. package/dist/elements/accent/core.js +83 -68
  30. package/dist/elements/callout/Callout.vue +4 -4
  31. package/dist/elements/callout/app.d.ts +1 -8
  32. package/dist/elements/callout/app.js +2 -2
  33. package/dist/elements/callout/core.d.ts +21 -59
  34. package/dist/elements/callout/core.js +18 -17
  35. package/dist/elements/caption/Caption.vue +3 -3
  36. package/dist/elements/caption/app.d.ts +1 -8
  37. package/dist/elements/caption/app.js +2 -2
  38. package/dist/elements/caption/core.d.ts +21 -99
  39. package/dist/elements/caption/core.js +18 -22
  40. package/dist/elements/details/Details.vue +3 -3
  41. package/dist/elements/details/app.d.ts +1 -8
  42. package/dist/elements/details/app.js +2 -2
  43. package/dist/elements/details/core.d.ts +18 -61
  44. package/dist/elements/details/core.js +16 -11
  45. package/dist/elements/diagram/Diagram.vue +14 -11
  46. package/dist/elements/diagram/app.d.ts +1 -29
  47. package/dist/elements/diagram/app.js +2 -2
  48. package/dist/elements/diagram/core.d.ts +14 -177
  49. package/dist/elements/diagram/core.js +5 -8
  50. package/dist/elements/emphasis/Emphasis.vue +3 -3
  51. package/dist/elements/emphasis/app.d.ts +1 -8
  52. package/dist/elements/emphasis/app.js +2 -2
  53. package/dist/elements/emphasis/core.d.ts +13 -76
  54. package/dist/elements/emphasis/core.js +8 -9
  55. package/dist/elements/flex/Flex.vue +3 -3
  56. package/dist/elements/flex/app.d.ts +1 -8
  57. package/dist/elements/flex/app.js +2 -2
  58. package/dist/elements/flex/core.d.ts +16 -58
  59. package/dist/elements/flex/core.js +6 -7
  60. package/dist/elements/gallery/Gallery.vue +3 -3
  61. package/dist/elements/gallery/app.d.ts +1 -22
  62. package/dist/elements/gallery/app.js +2 -2
  63. package/dist/elements/gallery/core.d.ts +11 -132
  64. package/dist/elements/gallery/core.js +4 -5
  65. package/dist/elements/heading/Heading.vue +3 -3
  66. package/dist/elements/heading/_global.d.ts +2 -2
  67. package/dist/elements/heading/app.d.ts +1 -8
  68. package/dist/elements/heading/app.js +2 -2
  69. package/dist/elements/heading/core.d.ts +13 -97
  70. package/dist/elements/heading/core.js +8 -8
  71. package/dist/elements/horizontalLine/app.d.ts +1 -8
  72. package/dist/elements/horizontalLine/app.js +2 -2
  73. package/dist/elements/horizontalLine/core.d.ts +9 -47
  74. package/dist/elements/horizontalLine/core.js +4 -5
  75. package/dist/elements/image/Image.vue +3 -3
  76. package/dist/elements/image/ImageElement.vue +4 -4
  77. package/dist/elements/image/app.d.ts +1 -15
  78. package/dist/elements/image/app.js +2 -2
  79. package/dist/elements/image/core.d.ts +29 -108
  80. package/dist/elements/image/core.js +12 -19
  81. package/dist/elements/image/storage.d.ts +1 -1
  82. package/dist/elements/image/storage.js +6 -6
  83. package/dist/elements/lineBreak/app.d.ts +1 -8
  84. package/dist/elements/lineBreak/app.js +2 -2
  85. package/dist/elements/lineBreak/core.d.ts +9 -47
  86. package/dist/elements/lineBreak/core.js +4 -5
  87. package/dist/elements/link/BlockLink.vue +4 -6
  88. package/dist/elements/link/Link.vue +4 -4
  89. package/dist/elements/link/core.d.ts +8 -7
  90. package/dist/elements/link/core.js +5 -4
  91. package/dist/elements/link/dependency/app.d.ts +1 -15
  92. package/dist/elements/link/dependency/app.js +3 -3
  93. package/dist/elements/link/dependency/core.d.ts +30 -108
  94. package/dist/elements/link/dependency/core.js +6 -8
  95. package/dist/elements/link/hook.d.ts +12 -0
  96. package/dist/elements/link/hook.js +45 -0
  97. package/dist/elements/link/reference/app.d.ts +1 -15
  98. package/dist/elements/link/reference/app.js +3 -3
  99. package/dist/elements/link/reference/core.d.ts +24 -103
  100. package/dist/elements/link/reference/core.js +6 -8
  101. package/dist/elements/link/storage.js +1 -1
  102. package/dist/elements/list/List.vue +7 -5
  103. package/dist/elements/list/_global.d.ts +3 -3
  104. package/dist/elements/list/app.d.ts +1 -15
  105. package/dist/elements/list/app.js +2 -2
  106. package/dist/elements/list/core.d.ts +33 -155
  107. package/dist/elements/list/core.js +20 -18
  108. package/dist/elements/math/app.d.ts +1 -15
  109. package/dist/elements/math/app.js +3 -3
  110. package/dist/elements/math/block.d.ts +31 -43
  111. package/dist/elements/math/block.js +10 -9
  112. package/dist/elements/math/components/BlockMath.vue +4 -4
  113. package/dist/elements/math/components/InlinerMath.vue +4 -4
  114. package/dist/elements/math/core.d.ts +25 -53
  115. package/dist/elements/math/core.js +3 -11
  116. package/dist/elements/math/inliner.d.ts +24 -36
  117. package/dist/elements/math/inliner.js +10 -12
  118. package/dist/elements/paragraph/Paragraph.vue +3 -3
  119. package/dist/elements/paragraph/app.d.ts +1 -8
  120. package/dist/elements/paragraph/app.js +2 -2
  121. package/dist/elements/paragraph/core.d.ts +12 -53
  122. package/dist/elements/paragraph/core.js +6 -7
  123. package/dist/elements/problem/app.d.ts +1 -29
  124. package/dist/elements/problem/app.js +4 -4
  125. package/dist/elements/problem/components/Problem.vue +3 -3
  126. package/dist/elements/problem/components/ProblemContent.vue +15 -21
  127. package/dist/elements/problem/components/ProblemExpanderSection.vue +2 -2
  128. package/dist/elements/problem/components/Problems.vue +11 -7
  129. package/dist/elements/problem/components/SubProblem.vue +3 -4
  130. package/dist/elements/problem/components/expanders/Check.vue +3 -3
  131. package/dist/elements/problem/components/expanders/Checks.vue +6 -3
  132. package/dist/elements/problem/components/expanders/DefaultPlusSections.vue +3 -7
  133. package/dist/elements/problem/components/expanders/Hint.vue +3 -3
  134. package/dist/elements/problem/composables/problemScript.d.ts +2 -2
  135. package/dist/elements/problem/core.d.ts +63 -299
  136. package/dist/elements/problem/core.js +9 -11
  137. package/dist/elements/problem/hook.d.ts +1 -0
  138. package/dist/elements/problem/hook.js +14 -0
  139. package/dist/elements/problem/problem.d.ts +20 -77
  140. package/dist/elements/problem/problem.js +6 -6
  141. package/dist/elements/problem/problemCheck.d.ts +33 -83
  142. package/dist/elements/problem/problemCheck.js +16 -10
  143. package/dist/elements/problem/problemContent.d.ts +54 -401
  144. package/dist/elements/problem/problemContent.js +47 -56
  145. package/dist/elements/problem/problemScript.d.ts +18 -10
  146. package/dist/elements/problem/problemScript.js +15 -26
  147. package/dist/elements/problem/problems.d.ts +29 -188
  148. package/dist/elements/problem/problems.js +11 -15
  149. package/dist/elements/problem/storage.d.ts +1 -1
  150. package/dist/elements/problem/storage.js +2 -3
  151. package/dist/elements/table/Table.vue +3 -3
  152. package/dist/elements/table/app.d.ts +1 -29
  153. package/dist/elements/table/app.js +2 -2
  154. package/dist/elements/table/core.d.ts +28 -309
  155. package/dist/elements/table/core.js +17 -29
  156. package/dist/elements/video/Video.vue +4 -4
  157. package/dist/elements/video/app.d.ts +1 -15
  158. package/dist/elements/video/app.js +2 -2
  159. package/dist/elements/video/core.d.ts +26 -106
  160. package/dist/elements/video/core.js +11 -16
  161. package/dist/elements/video/storage.d.ts +1 -1
  162. package/dist/elements/video/storage.js +2 -3
  163. package/dist/error.d.ts +3 -0
  164. package/dist/error.js +6 -0
  165. package/dist/include.d.ts +4 -4
  166. package/dist/include.js +6 -12
  167. package/dist/index.d.ts +11 -11
  168. package/dist/index.js +11 -11
  169. package/dist/rawElement.d.ts +9 -6
  170. package/dist/rawElement.js +4 -0
  171. package/dist/rawToProse/countSchemas.d.ts +1 -0
  172. package/dist/rawToProse/countSchemas.js +11 -0
  173. package/dist/rawToProse/hook.d.ts +39 -0
  174. package/dist/rawToProse/hook.js +6 -0
  175. package/dist/rawToProse/index.d.ts +34 -0
  176. package/dist/rawToProse/index.js +92 -0
  177. package/dist/rawToProse/uniqueTitles.d.ts +1 -0
  178. package/dist/rawToProse/uniqueTitles.js +11 -0
  179. package/dist/shared/filePath.js +2 -2
  180. package/dist/shared/paragraphWrap.d.ts +3 -3
  181. package/dist/shared/paragraphWrap.js +7 -12
  182. package/dist/slugify/index.d.ts +3 -1
  183. package/dist/slugify/index.js +5 -6
  184. package/dist/slugify/languages/en.js +1 -1
  185. package/dist/slugify/languages/ru.js +1 -1
  186. package/dist/snippet.d.ts +39 -33
  187. package/dist/snippet.js +139 -73
  188. package/dist/tag.d.ts +22 -19
  189. package/dist/tag.js +19 -15
  190. package/dist/toc.d.ts +12 -18
  191. package/dist/toc.js +120 -42
  192. package/package.json +7 -6
  193. package/dist/app/default/Inliners.vue +0 -11
  194. package/dist/context.d.ts +0 -4
  195. package/dist/context.js +0 -1
  196. package/dist/elements/link/step.d.ts +0 -16
  197. package/dist/elements/link/step.js +0 -36
  198. package/dist/elements/problem/step.d.ts +0 -5
  199. package/dist/elements/problem/step.js +0 -13
  200. package/dist/resolve.d.ts +0 -21
  201. package/dist/resolve.js +0 -102
  202. package/dist/resolveStep.d.ts +0 -9
  203. package/dist/resolveStep.js +0 -3
  204. package/dist/title.d.ts +0 -8
  205. package/dist/title.js +0 -6
  206. package/dist/utils/docs.d.ts +0 -1
  207. package/dist/utils/docs.js +0 -22
  208. package/types.d.ts +0 -4
package/dist/snippet.js CHANGED
@@ -1,86 +1,152 @@
1
- import { ProseError } from "@jsprose/core";
2
- import { defineResolveStep } from "./resolveStep.js";
3
- export function finalizeSnippet(processTagArgs) {
4
- const finalSnippet = {};
5
- const propsSnippet = processTagArgs.props.snippet;
6
- const builtinSnippet = processTagArgs.element.snippet;
7
- //
8
- const quick = propsSnippet?.quick ?? builtinSnippet?.quick;
9
- if (quick) {
10
- finalSnippet.quick = quick;
1
+ import { EruditProseError } from "./error.js";
2
+ import { defineRawToProseHook } from "./rawToProse/hook.js";
3
+ export const NO_SNIPPET_PREFIX = "__ERDUIT_tagNoSnippet";
4
+ export function finalizeSnippet(rawElement, snippetTagProp) {
5
+ if (snippetTagProp) {
6
+ // Explicitly add snippet using tag prop data
7
+ const normalizedSnippet = normalizeSnippet(snippetTagProp, rawElement.snippet?.title, rawElement.title);
8
+ const tagPropHadExplicitSeo = snippetTagProp.seo !== undefined;
9
+ if (rawElement.snippet) {
10
+ const normalizedInternalSnippet = normalizeSnippet(rawElement.snippet, rawElement.title);
11
+ // Merge internal snippet data as fallback for missing values in tag prop snippet
12
+ if (!normalizedSnippet.description && normalizedInternalSnippet.description) {
13
+ normalizedSnippet.description = normalizedInternalSnippet.description;
14
+ }
15
+ if (normalizedSnippet.search === undefined && normalizedInternalSnippet.search) {
16
+ normalizedSnippet.search = normalizedInternalSnippet.search;
17
+ }
18
+ if (normalizedSnippet.key === undefined && normalizedInternalSnippet.key) {
19
+ normalizedSnippet.key = normalizedInternalSnippet.key;
20
+ }
21
+ if (normalizedSnippet.seo === undefined && normalizedInternalSnippet.seo) {
22
+ normalizedSnippet.seo = normalizedInternalSnippet.seo;
23
+ }
24
+ }
25
+ // Add snippet to SEO if either search or key is enabled unless SEO was explicitly set in the tag prop
26
+ if (!tagPropHadExplicitSeo && normalizedSnippet.seo !== false && (normalizedSnippet.search || normalizedSnippet.key)) {
27
+ normalizedSnippet.seo = true;
28
+ }
29
+ // Prune snippet if it has no active features
30
+ if (!normalizedSnippet.search && !normalizedSnippet.key && !normalizedSnippet.seo) {
31
+ delete rawElement.snippet;
32
+ return;
33
+ }
34
+ rawElement.snippet = normalizedSnippet;
35
+ return;
11
36
  }
12
- //
13
- const search = propsSnippet?.search ?? builtinSnippet?.search;
14
- if (search) {
15
- finalSnippet.search = search;
37
+ if (rawElement.snippet) {
38
+ // This snippet was supposed to be used to merge data but not needed anymore because tag prop snippet is not provided
39
+ delete rawElement.snippet;
40
+ return;
41
+ }
42
+ }
43
+ export function normalizeSnippet(snippet, ...fallbackTitles) {
44
+ const title = snippet.title?.trim() || fallbackTitles.map((t) => t?.trim()).find(Boolean);
45
+ if (!title) {
46
+ throw new EruditProseError("Unable to retrieve non-empty title for snippet!");
16
47
  }
17
- //
18
- let seo = propsSnippet?.seo ?? builtinSnippet?.seo;
19
- // If none of the flags are set to true, no snippet is created
20
- if (!quick && !search && !seo) {
48
+ const description = snippet.description?.trim() || undefined;
49
+ const result = {
50
+ ...snippet,
51
+ title,
52
+ description
53
+ };
54
+ return result;
55
+ }
56
+ export function toSearchSnippet(snippet) {
57
+ if (!snippet || !snippet.search) {
21
58
  return undefined;
22
59
  }
23
- // Enable SEO if either quick or search is enabled unless SEO is explicitly disabled
24
- // Check both element defaults and props - if either explicitly disables seo, don't auto-enable
25
- const seoExplicitlyDisabled = builtinSnippet?.seo === false || propsSnippet?.seo === false;
26
- if (!seo) {
27
- if (!seoExplicitlyDisabled) {
28
- if (quick || search) {
29
- seo = true;
30
- }
31
- }
60
+ if (snippet.search === true) {
61
+ return {
62
+ title: snippet.title,
63
+ description: snippet.description
64
+ };
32
65
  }
33
- if (seo) {
34
- finalSnippet.seo = seo;
66
+ if (typeof snippet.search === "string") {
67
+ const title = snippet.search.trim() || snippet.title;
68
+ return {
69
+ title,
70
+ description: snippet.description
71
+ };
35
72
  }
36
- //
37
- const title = getGenericTitle(processTagArgs);
38
- if (title) {
39
- finalSnippet.title = title;
73
+ if (Array.isArray(snippet.search)) {
74
+ const synonyms = snippet.search.map((synonym) => synonym.trim()).filter(Boolean);
75
+ return {
76
+ title: snippet.title,
77
+ description: snippet.description,
78
+ synonyms: synonyms.length > 0 ? synonyms : undefined
79
+ };
40
80
  }
41
- const description = getGenericDescription(processTagArgs);
42
- if (description) {
43
- finalSnippet.description = description;
81
+ const title = snippet.search.title?.trim() || snippet.title;
82
+ const description = snippet.search.description?.trim() || snippet.description;
83
+ const synonyms = snippet.search.synonyms?.map((synonym) => synonym.trim()).filter(Boolean);
84
+ return {
85
+ title,
86
+ description,
87
+ synonyms: synonyms && synonyms.length > 0 ? synonyms : undefined
88
+ };
89
+ }
90
+ export function toKeySnippet(snippet) {
91
+ if (!snippet || !snippet.key) {
92
+ return undefined;
44
93
  }
45
- //
46
- if (!finalSnippet.title) {
47
- let titlessFlags = [];
48
- if (quick && typeof quick !== "string") {
49
- if (quick === true || !quick.title) {
50
- titlessFlags.push("quick");
51
- }
52
- }
53
- if (search && typeof search !== "string") {
54
- if (search === true || Array.isArray(search) || !search.title) {
55
- titlessFlags.push("search");
56
- }
57
- }
58
- if (seo && typeof seo !== "string") {
59
- if (seo === true || !seo.title) {
60
- titlessFlags.push("seo");
61
- }
62
- }
63
- throw new ProseError(`Unable to get title for snippet flags (${titlessFlags.join(", ")}) because no explicit, general inherited title was provided!`);
94
+ if (snippet.key === true) {
95
+ return {
96
+ title: snippet.title,
97
+ description: snippet.description
98
+ };
64
99
  }
65
- //
66
- processTagArgs.element.snippet = finalSnippet;
67
- return finalSnippet;
68
- }
69
- function getGenericTitle(processTagArgs) {
70
- const title = processTagArgs.props.snippet?.title?.trim() || processTagArgs.element.snippet?.title?.trim() || processTagArgs.element.title?.trim();
71
- return title;
72
- }
73
- function getGenericDescription(processTagArgs) {
74
- return processTagArgs.props.snippet?.description?.trim() || processTagArgs.element.snippet?.description?.trim();
100
+ if (typeof snippet.key === "string") {
101
+ const title = snippet.key.trim() || snippet.title;
102
+ return {
103
+ title,
104
+ description: snippet.description
105
+ };
106
+ }
107
+ const title = snippet.key.title?.trim() || snippet.title;
108
+ const description = snippet.key.description?.trim() || snippet.description;
109
+ return {
110
+ title,
111
+ description
112
+ };
75
113
  }
76
- export const snippetStep = defineResolveStep(({ rawElement, proseElement }) => {
77
- if (rawElement.snippet && proseElement.id) {
78
- const resolvedSnippet = {
79
- schemaName: rawElement.schemaName,
80
- isUnique: Boolean(rawElement.uniqueName),
81
- elementId: proseElement.id,
82
- snippetData: rawElement.snippet
114
+ export function toSeoSnippet(snippet) {
115
+ if (!snippet || !snippet.seo) {
116
+ return undefined;
117
+ }
118
+ if (snippet.seo === true) {
119
+ return {
120
+ title: snippet.title,
121
+ description: snippet.description
122
+ };
123
+ }
124
+ if (typeof snippet.seo === "string") {
125
+ const title = snippet.seo.trim() || snippet.title;
126
+ return {
127
+ title,
128
+ description: snippet.description
83
129
  };
84
- return resolvedSnippet;
85
130
  }
131
+ const title = snippet.seo.title?.trim() || snippet.title;
132
+ const description = snippet.seo.description?.trim() || snippet.description;
133
+ return {
134
+ title,
135
+ description
136
+ };
137
+ }
138
+ export const snippetHook = defineRawToProseHook(({ task: context, result }) => {
139
+ if (!context.snippets?.enabled) {
140
+ return;
141
+ }
142
+ return { step: ({ rawElement, proseElement }) => {
143
+ if (rawElement.snippet && proseElement.id) {
144
+ const resolvedSnippet = {
145
+ schemaName: rawElement.schema.name,
146
+ elementId: proseElement.id,
147
+ snippet: rawElement.snippet
148
+ };
149
+ result.snippets.push(resolvedSnippet);
150
+ }
151
+ } };
86
152
  });
package/dist/tag.d.ts CHANGED
@@ -1,22 +1,25 @@
1
- import { Registry, type AnySchema, type ConfigurableTagProps, type NormalizedChildren, type ProcessTagFunction, type TagDefinition } from '@jsprose/core';
2
- import type { EruditRawElement } from './rawElement.js';
3
- import { type ObjPropSnippet } from './snippet.js';
4
- import { type ObjPropToc } from './toc.js';
5
- declare const NoTocSymbol: unique symbol;
6
- declare const NoSnippetSymbol: unique symbol;
7
- export type NoToc = {
8
- readonly [NoTocSymbol]?: never;
9
- };
10
- export type NoSnippet = {
11
- readonly [NoSnippetSymbol]?: never;
12
- };
13
- export type EruditTagProps<TProps extends Record<string, unknown>> = (TProps extends NoToc ? {} : ObjPropToc) & (TProps extends NoSnippet ? {} : ObjPropSnippet);
14
- export type EruditProcessTagArgs = {
15
- tagName: string;
16
- element: EruditRawElement<AnySchema>;
17
- props: ConfigurableTagProps & ObjPropSnippet & ObjPropToc;
1
+ import { TAG_PREFIX, type NormalizedChildren, type Schema, type TagProps, type ValidateTagCustomProps } from 'tsprose';
2
+ import type { ToEruditRawElement } from './rawElement.js';
3
+ import { NO_SNIPPET_PREFIX, type NoSnippet, type SnippetTagProp } from './snippet.js';
4
+ import { NO_TOC_PREFIX, type NoToc, type TocTagProp } from './toc.js';
5
+ type DistributiveOmit<T, K extends PropertyKey> = T extends any ? Omit<T, K> : never;
6
+ export type ToEruditTag<TSchema extends Schema, TagName extends string, Props extends Record<string, any> = {}> = {
7
+ [TAG_PREFIX]: true;
8
+ tagName: TagName;
9
+ schema: TSchema;
10
+ } & ((props: DistributiveOmit<EruditTagProps<TSchema, TagName, Props>, typeof NO_TOC_PREFIX | typeof NO_SNIPPET_PREFIX>) => ToEruditRawElement<TSchema, TagName>);
11
+ export type EruditTag = ToEruditTag<Schema, string, any>;
12
+ export type EruditTagProps<TSchema extends Schema, TagName extends string, Props extends Record<string, any> = {}> = TagProps<TSchema, TagName, Props> & EruditTagTocSnippet<TSchema, Props>;
13
+ export type EruditTagTocSnippet<TSchema extends Schema, Props extends Record<string, any> = {}> = TSchema['linkable'] extends false ? {} : (Props extends NoToc ? {} : TocTagProp) & (Props extends NoSnippet ? {} : SnippetTagProp);
14
+ export declare function defineEruditTag<TSchema extends Schema, TagName extends string>(tagParameters: {
15
+ tagName: TagName;
16
+ schema: TSchema;
17
+ }): <const Props extends ValidateTagCustomProps<Props>>(eruditTagElementHandler: EruditTagElementHandler<TagName, TSchema, Props>) => ToEruditTag<TSchema, TagName, Props>;
18
+ export type EruditTagElementHandlerContext<TagName extends string = string, TSchema extends Schema = Schema, Props extends Record<string, any> = {}> = {
19
+ tagName: TagName;
20
+ props: EruditTagProps<TSchema, TagName, Props>;
18
21
  children: NormalizedChildren;
19
- registry: Registry;
22
+ element: ToEruditRawElement<TSchema, TagName>;
20
23
  };
21
- export declare function defineEruditTag<const TSchema extends AnySchema, const TTagDefinition extends TagDefinition<TSchema>>(definition: TTagDefinition): <const TConfigurableTagProps extends ConfigurableTagProps>(processTag: ProcessTagFunction<TTagDefinition["schema"], TTagDefinition, TConfigurableTagProps & (TTagDefinition["schema"]["linkable"] extends true ? EruditTagProps<TConfigurableTagProps> : {}), EruditRawElement<TTagDefinition["schema"], TTagDefinition["tagName"]>>) => import("@jsprose/core").Tag<TTagDefinition["tagName"], TTagDefinition["schema"], TConfigurableTagProps & (TTagDefinition["schema"]["linkable"] extends true ? EruditTagProps<TConfigurableTagProps> : {})>;
24
+ export type EruditTagElementHandler<TagName extends string, TSchema extends Schema, Props extends Record<string, any>> = (context: EruditTagElementHandlerContext<TagName, TSchema, Props>) => void;
22
25
  export {};
package/dist/tag.js CHANGED
@@ -1,18 +1,22 @@
1
- import { defineTag, Registry } from "@jsprose/core";
2
- import { finalizeSnippet } from "./snippet.js";
3
- import { finalizeToc } from "./toc.js";
4
- import { finalizeTitle } from "./title.js";
5
- export function defineEruditTag(definition) {
6
- const baseFinalizeTag = defineTag(definition);
7
- function eruditFinalizeTag(processTag) {
8
- const eruditTag = baseFinalizeTag((args) => {
9
- processTag(args);
10
- // Use every possibility to get shared title property
11
- args.element.title = finalizeTitle(args);
12
- args.element.snippet = finalizeSnippet(args);
13
- args.element.toc = finalizeToc(args);
14
- // Use every possibility to get human-readable slug whether it is set manually or taken from snippet or toc
15
- args.element.slug ||= args.element.snippet?.title || args.element.toc?.title || args.element.title;
1
+ import { defineTag, TAG_PREFIX } from "tsprose";
2
+ import { finalizeSnippet, NO_SNIPPET_PREFIX } from "./snippet.js";
3
+ import { finalizeToc, NO_TOC_PREFIX } from "./toc.js";
4
+ export function defineEruditTag(tagParameters) {
5
+ const baseFinalizeTag = defineTag(tagParameters);
6
+ function eruditFinalizeTag(eruditTagElementHandler) {
7
+ const eruditTag = baseFinalizeTag((baseContext) => {
8
+ const specificContext = baseContext;
9
+ const anyContext = baseContext;
10
+ // Allow specific tag to set title, snippet and toc properties first
11
+ // Then used it for finalization processes
12
+ eruditTagElementHandler(specificContext);
13
+ const rawElement = anyContext.element;
14
+ finalizeSnippet(rawElement, anyContext.props.snippet);
15
+ finalizeToc(rawElement, anyContext.props.toc);
16
+ // Preserve title
17
+ rawElement.title ||= anyContext.props.snippet?.title?.trim() || (typeof rawElement.toc === "string" ? rawElement.toc : undefined);
18
+ // Use every possibility to get human-readable slug
19
+ rawElement.slug ||= rawElement.title;
16
20
  });
17
21
  return eruditTag;
18
22
  }
package/dist/toc.d.ts CHANGED
@@ -1,18 +1,16 @@
1
- import { type AnySchema, type ProseElement } from '@jsprose/core';
2
- import type { EruditProcessTagArgs } from './tag.js';
3
- import type { EruditRawElement } from './rawElement.js';
4
- export type Toc = {
5
- title?: string;
6
- add?: boolean;
1
+ import { type EruditRawElement } from './rawElement.js';
2
+ export declare const NO_TOC_PREFIX = "__ERDUIT_tagNoToc";
3
+ export type NoToc = {
4
+ [NO_TOC_PREFIX]: true;
7
5
  };
8
- export type ObjPropToc = {
9
- /** Show element in the table of contents */
6
+ export interface TocTagProp {
7
+ /** Whether to include the element in the table of contents. */
10
8
  toc?: boolean | string;
11
- };
12
- export type ObjRawElementToc = {
13
- toc?: Toc;
14
- };
15
- export declare function finalizeToc(processTagArgs: EruditProcessTagArgs): Toc | undefined;
9
+ }
10
+ export interface TocRawElementProp {
11
+ toc?: string | boolean;
12
+ }
13
+ export declare function finalizeToc(rawElement: EruditRawElement, tocTagProp: TocTagProp['toc']): void;
16
14
  export type ResolvedTocHeading = {
17
15
  type: 'heading';
18
16
  level: 1 | 2 | 3;
@@ -27,8 +25,4 @@ export type ResolvedTocElement = {
27
25
  elementId: string;
28
26
  };
29
27
  export type ResolvedTocItem = ResolvedTocHeading | ResolvedTocElement;
30
- export declare const tocItemStep: ({ rawElement, proseElement }: {
31
- context: import("./context.js").EruditProseContext;
32
- rawElement: EruditRawElement<AnySchema>;
33
- proseElement: ProseElement<AnySchema>;
34
- }) => ResolvedTocHeading | ResolvedTocElement | undefined;
28
+ export declare const tocHook: import("./rawToProse/hook.js").RawToProseHook;
package/dist/toc.js CHANGED
@@ -1,52 +1,130 @@
1
- import { ProseError } from "@jsprose/core";
2
1
  import { headingSchema } from "./elements/heading/core.js";
3
- import { defineResolveStep } from "./resolveStep.js";
4
- export function finalizeToc(processTagArgs) {
5
- const propToc = processTagArgs.props.toc;
6
- if (propToc === false) {
7
- return undefined;
2
+ import { EruditProseError } from "./error.js";
3
+ import { defineRawToProseHook } from "./rawToProse/hook.js";
4
+ import { isEruditRawElement } from "./rawElement.js";
5
+ export const NO_TOC_PREFIX = "__ERDUIT_tagNoToc";
6
+ export function finalizeToc(rawElement, tocTagProp) {
7
+ if (tocTagProp === false) {
8
+ // Explicitly prohibit to add to TOC
9
+ rawElement.toc = false;
10
+ return;
8
11
  }
9
- if (propToc === true) {
10
- const title = finalizeTocTitle(processTagArgs);
11
- return { title };
12
+ if (typeof tocTagProp === "string") {
13
+ // Explicitly add to TOC with custom title
14
+ const tocString = tocTagProp.trim();
15
+ if (!tocString) {
16
+ throw new EruditProseError("Addition to TOC was requested via direct tag toc prop but it is an empty string!");
17
+ }
18
+ rawElement.toc = tocString;
19
+ return;
20
+ }
21
+ if (rawElement.toc === true) {
22
+ // Implicitly add to TOC using general title
23
+ const tocString = rawElement.title?.trim();
24
+ if (!tocString) {
25
+ throw new EruditProseError("Addition to TOC was requested via internal toc: true flag, but unable to retrieve title!");
26
+ }
27
+ rawElement.toc = tocString;
28
+ return;
12
29
  }
13
- if (typeof propToc === "string") {
14
- const manualTocTitle = finalizeTocTitle(processTagArgs);
15
- return { title: manualTocTitle };
30
+ if (rawElement.toc === false) {
31
+ // Implicitly set to not to add to TOC
32
+ return;
16
33
  }
17
- if (processTagArgs.element.toc) {
18
- if (processTagArgs.element.toc.add) {
19
- const tocTitle = finalizeTocTitle(processTagArgs);
20
- return { title: tocTitle };
34
+ if (tocTagProp === true) {
35
+ // Explicitly add to TOC using general internal toc string or general title
36
+ const tocString = rawElement.toc?.trim() || rawElement.title?.trim();
37
+ if (!tocString) {
38
+ throw new EruditProseError("Addition to TOC was manually requested via true tag toc prop, but unable to retrieve title!");
21
39
  }
40
+ rawElement.toc = tocString;
41
+ return;
22
42
  }
23
- }
24
- function finalizeTocTitle(processTagArgs) {
25
- const title = (typeof processTagArgs.props.toc === "string" ? processTagArgs.props.toc.trim() : "") || processTagArgs.element.toc?.title?.trim() || processTagArgs.element.title?.trim();
26
- if (title) {
27
- return title;
43
+ if (typeof rawElement.toc === "string") {
44
+ // Check if internal toc string is valid
45
+ const tocString = rawElement.toc?.trim();
46
+ if (!tocString) {
47
+ throw new EruditProseError("Addition to TOC was requested via internal toc string, but it is empty!");
48
+ }
49
+ rawElement.toc = tocString;
28
50
  }
29
- throw new ProseError("Unable to finalize TOC title!");
30
51
  }
31
- export const tocItemStep = defineResolveStep(({ rawElement, proseElement }) => {
32
- if (rawElement.toc?.title && proseElement.id) {
33
- if (rawElement.schemaName === headingSchema.name) {
34
- const tocItem = {
35
- type: "heading",
36
- level: rawElement.data.level,
37
- title: rawElement.toc.title,
38
- elementId: proseElement.id,
39
- children: []
40
- };
41
- return tocItem;
42
- } else {
43
- const tocItem = {
44
- type: "element",
45
- schemaName: rawElement.schemaName,
46
- title: rawElement.toc.title,
47
- elementId: proseElement.id
48
- };
49
- return tocItem;
50
- }
52
+ export const tocHook = defineRawToProseHook(({ task: context, result }) => {
53
+ if (!context.toc?.enabled) {
54
+ return;
51
55
  }
56
+ const addSchemas = context.toc?.addSchemas || [];
57
+ const headingStack = [];
58
+ return { step: ({ rawElement, proseElement }) => {
59
+ let tocItem;
60
+ if (proseElement.id) {
61
+ if (typeof rawElement.toc === "string") {
62
+ if (isEruditRawElement(rawElement, headingSchema)) {
63
+ tocItem = {
64
+ type: "heading",
65
+ level: rawElement.data.level,
66
+ title: rawElement.toc,
67
+ elementId: proseElement.id,
68
+ children: []
69
+ };
70
+ } else {
71
+ tocItem = {
72
+ type: "element",
73
+ schemaName: rawElement.schema.name,
74
+ title: rawElement.toc,
75
+ elementId: proseElement.id
76
+ };
77
+ }
78
+ }
79
+ // Try force add specified schemas
80
+ // Only attempt for elements where toc was never explicitly excluded.
81
+ if (!tocItem && rawElement.toc !== false && addSchemas.some((schema) => isEruditRawElement(rawElement, schema))) {
82
+ try {
83
+ finalizeToc(rawElement, true);
84
+ if (typeof rawElement.toc === "string") {
85
+ tocItem = {
86
+ type: "element",
87
+ schemaName: rawElement.schema.name,
88
+ title: rawElement.toc,
89
+ elementId: proseElement.id
90
+ };
91
+ }
92
+ } catch {}
93
+ }
94
+ }
95
+ if (tocItem) {
96
+ if (tocItem.type === "heading") {
97
+ // Pop headings from stack that are same level or deeper
98
+ while (headingStack.length > 0) {
99
+ const lastItem = headingStack[headingStack.length - 1];
100
+ if (lastItem.type === "heading" && lastItem.level >= tocItem.level) {
101
+ headingStack.pop();
102
+ } else {
103
+ break;
104
+ }
105
+ }
106
+ // Add to parent or root
107
+ if (headingStack.length > 0) {
108
+ const parent = headingStack[headingStack.length - 1];
109
+ if (parent.type === "heading") {
110
+ parent.children.push(tocItem);
111
+ }
112
+ } else {
113
+ result.toc.push(tocItem);
114
+ }
115
+ // Push this heading to stack
116
+ headingStack.push(tocItem);
117
+ } else {
118
+ // Non-heading item: add to most recent heading or root
119
+ if (headingStack.length > 0) {
120
+ const parent = headingStack[headingStack.length - 1];
121
+ if (parent.type === "heading") {
122
+ parent.children.push(tocItem);
123
+ }
124
+ } else {
125
+ result.toc.push(tocItem);
126
+ }
127
+ }
128
+ }
129
+ } };
52
130
  });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@erudit-js/prose",
4
- "version": "4.1.0",
4
+ "version": "4.2.0-dev.1",
5
5
  "description": "📝 JSX prose subsystem for Erudit sites",
6
6
  "main": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",
@@ -18,7 +18,7 @@
18
18
  "import": "./dist/elements/*.js",
19
19
  "types": "./dist/elements/*.d.ts"
20
20
  },
21
- "./types": "./types.d.ts"
21
+ "./raw": "./raw.d.ts"
22
22
  },
23
23
  "files": [
24
24
  "dist",
@@ -32,16 +32,17 @@
32
32
  "prepack": "bun run build"
33
33
  },
34
34
  "dependencies": {
35
- "@erudit-js/core": "4.1.0",
35
+ "@erudit-js/core": "4.2.0-dev.1",
36
36
  "@floating-ui/vue": "^1.1.10",
37
- "@jsprose/core": "^1.0.0",
37
+ "tsprose": "^1.0.0",
38
38
  "image-size": "^2.0.2",
39
39
  "katex": "^0.16.28",
40
40
  "photoswipe": "^5.4.4",
41
- "vue": "^3.5.27"
41
+ "vue": "^3.5.28"
42
42
  },
43
43
  "devDependencies": {
44
44
  "glob": "13.0.0",
45
- "oxc-transform": "0.112.0"
45
+ "oxc-transform": "0.112.0",
46
+ "ts-xor": "^1.3.0"
46
47
  }
47
48
  }
@@ -1,11 +0,0 @@
1
- <script lang="ts" setup>
2
- import type { inlinersSchema, ProseElement } from '@jsprose/core';
3
-
4
- import Render from '../shared/Render.vue';
5
-
6
- defineProps<{ element: ProseElement<typeof inlinersSchema> }>();
7
- </script>
8
-
9
- <template>
10
- <Render v-for="child of element.children" :element="child" />
11
- </template>
package/dist/context.d.ts DELETED
@@ -1,4 +0,0 @@
1
- export interface EruditProseContext {
2
- language: string;
3
- linkable?: boolean;
4
- }
package/dist/context.js DELETED
@@ -1 +0,0 @@
1
- export {};
@@ -1,16 +0,0 @@
1
- export type ContentLinkTag = 'Dep' | 'Dependency' | 'Ref' | 'Reference';
2
- export interface ContentLinkUsage {
3
- type: ContentLinkTag;
4
- label: string;
5
- }
6
- export type ContentLinks = Map<string, ContentLinkUsage[]>;
7
- export interface ContentLinkStepReturn {
8
- storageKey: string;
9
- label: string;
10
- type: ContentLinkTag;
11
- }
12
- export declare const contentLinkStep: ({ rawElement, proseElement }: {
13
- context: import("../../context.js").EruditProseContext;
14
- rawElement: import("../../rawElement.js").EruditRawElement<import("@jsprose/core").AnySchema>;
15
- proseElement: import("@jsprose/core").ProseElement<import("@jsprose/core").AnySchema>;
16
- }) => ContentLinkStepReturn | undefined;
@@ -1,36 +0,0 @@
1
- import { isRawElement } from "@jsprose/core";
2
- import { defineResolveStep } from "../../resolveStep.js";
3
- import { dependencySchema, depSchema } from "./dependency/core.js";
4
- import { referenceSchema, refSchema } from "./reference/core.js";
5
- export const contentLinkStep = defineResolveStep(({ rawElement, proseElement }) => {
6
- if (!proseElement.id || !rawElement.storageKey) {
7
- return;
8
- }
9
- const checks = [
10
- {
11
- schema: depSchema,
12
- key: "Dep"
13
- },
14
- {
15
- schema: dependencySchema,
16
- key: "Dependency"
17
- },
18
- {
19
- schema: refSchema,
20
- key: "Ref"
21
- },
22
- {
23
- schema: referenceSchema,
24
- key: "Reference"
25
- }
26
- ];
27
- for (const { schema, key } of checks) {
28
- if (isRawElement(rawElement, schema)) {
29
- return {
30
- storageKey: rawElement.storageKey,
31
- label: rawElement.data.label.trim(),
32
- type: key
33
- };
34
- }
35
- }
36
- });
@@ -1,5 +0,0 @@
1
- export declare const problemScriptStep: ({ rawElement }: {
2
- context: import("../../context.js").EruditProseContext;
3
- rawElement: import("../../rawElement.js").EruditRawElement<import("@jsprose/core").AnySchema>;
4
- proseElement: import("@jsprose/core").ProseElement<import("@jsprose/core").AnySchema>;
5
- }) => string | undefined;