erudit 3.0.0-dev.6 → 3.0.0-dev.7
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.
- package/app/components/SiteMain.vue +2 -3
- package/app/components/aside/minor/topic/TopicToc.vue +1 -1
- package/app/components/bitran/BitranContent.vue +10 -3
- package/app/components/main/topic/MainTopic.vue +1 -2
- package/app/components/main/utils/Breadcrumb.vue +1 -6
- package/app/components/main/utils/ContentPopovers.vue +11 -5
- package/app/components/preview/display/Unique.vue +7 -1
- package/app/composables/bitran.ts +37 -33
- package/app/composables/bitranContent.ts +16 -4
- package/app/composables/bitranLocation.ts +1 -1
- package/app/pages/group/[...groupId].vue +3 -4
- package/app/scripts/preview/data/unique.ts +6 -5
- package/bin/erudit.mjs +2 -0
- package/module/index.ts +4 -5
- package/package.json +11 -7
- package/server/api/aside/major/nav/global.ts +1 -1
- package/server/api/aside/minor/path.ts +1 -2
- package/server/api/preview/page/[...parts].ts +3 -2
- package/server/api/preview/unique/[location].ts +6 -3
- package/server/plugin/bitran/content.ts +49 -42
- package/server/plugin/bitran/location.ts +1 -1
- package/server/plugin/bitran/products/include.ts +13 -15
- package/server/plugin/bitran/products/link.ts +12 -12
- package/server/plugin/bitran/toc.ts +21 -29
- package/server/plugin/bitran/transpiler.ts +15 -19
- package/server/plugin/build/jobs/content/parse.ts +19 -10
- package/server/plugin/build/setup.ts +1 -0
- package/server/plugin/content/absoluteId.ts +1 -1
- package/server/plugin/content/context.ts +1 -1
- package/shared/aside/minor.ts +2 -1
- package/shared/bitran/stringContent.ts +6 -0
- package/shared/icons.ts +1 -1
- package/shared/link.ts +5 -2
- package/tsconfig.json +1 -1
- package/shared/bitran/context.ts +0 -8
- package/shared/bitran/default.ts +0 -46
- package/shared/bitran/link/Link.vue +0 -166
- package/shared/bitran/link/factory.ts +0 -24
- package/shared/bitran/link/icon.svg +0 -3
- package/shared/bitran/link/languages/en.ts +0 -7
- package/shared/bitran/link/languages/ru.ts +0 -7
- package/shared/bitran/link/renderer.ts +0 -21
- package/shared/bitran/link/shared.ts +0 -17
- package/shared/bitran/link/target.ts +0 -134
- package/shared/bitran/link/transpiler.ts +0 -10
- package/shared/bitran/location.ts +0 -166
- package/test/bitran/link/target.test.ts +0 -141
- package/test/bitran/location.test.ts +0 -143
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
defineElementVueRenderer,
|
|
3
|
-
defineComponent,
|
|
4
|
-
defineIcon,
|
|
5
|
-
defineLanguages,
|
|
6
|
-
} from '@bitran-js/renderer-vue';
|
|
7
|
-
|
|
8
|
-
import { LinkNode, type LinkSchema } from './shared';
|
|
9
|
-
|
|
10
|
-
export const linkRenderer = defineElementVueRenderer<LinkSchema>({
|
|
11
|
-
Node: LinkNode,
|
|
12
|
-
component: defineComponent(() => import('./Link.vue')),
|
|
13
|
-
icon: defineIcon(() => import('./icon.svg?raw')),
|
|
14
|
-
languages: defineLanguages({
|
|
15
|
-
en: () => import('./languages/en'),
|
|
16
|
-
ru: () => import('./languages/ru'),
|
|
17
|
-
}),
|
|
18
|
-
createRenderData: async () => {
|
|
19
|
-
throw Error('Render data for Links must be built only on server side!');
|
|
20
|
-
},
|
|
21
|
-
});
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { InlinerNode, type DefineElementSchema } from '@bitran-js/core';
|
|
2
|
-
|
|
3
|
-
import type { LinkTarget } from './target';
|
|
4
|
-
|
|
5
|
-
export const linkName = 'link';
|
|
6
|
-
|
|
7
|
-
export interface LinkParseData {
|
|
8
|
-
target: string;
|
|
9
|
-
label: string;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export type LinkSchema = DefineElementSchema<{
|
|
13
|
-
ParseData: LinkParseData;
|
|
14
|
-
RenderData: LinkTarget;
|
|
15
|
-
}>;
|
|
16
|
-
|
|
17
|
-
export class LinkNode extends InlinerNode<LinkSchema> {}
|
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
import { isTopicPart } from '@erudit-js/cog/schema';
|
|
2
|
-
import { tryReplaceAlias } from '@erudit-js/bitran-elements/aliases/shared';
|
|
3
|
-
|
|
4
|
-
import type { BitranContext } from '@shared/bitran/context';
|
|
5
|
-
import {
|
|
6
|
-
bitranLocationTypes,
|
|
7
|
-
parsePartialBitranLocation,
|
|
8
|
-
stringifyBitranLocation,
|
|
9
|
-
} from '@shared/bitran/location';
|
|
10
|
-
|
|
11
|
-
export type LinkTargetType = 'unique' | 'page' | 'absolute' | 'external';
|
|
12
|
-
|
|
13
|
-
interface LinkTargetBase {
|
|
14
|
-
type: LinkTargetType;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export interface UniqueLinkTarget extends LinkTargetBase {
|
|
18
|
-
type: 'unique';
|
|
19
|
-
strlocation: string;
|
|
20
|
-
_productName?: string;
|
|
21
|
-
_absoluteStrLocation?: string;
|
|
22
|
-
_href?: string;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export const linkTargetPageTypes = {
|
|
26
|
-
...bitranLocationTypes,
|
|
27
|
-
// Custom page types, that does not have Bitran content
|
|
28
|
-
book: true,
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
export type LinkTargetPageType = keyof typeof linkTargetPageTypes;
|
|
32
|
-
|
|
33
|
-
export function isLinkTargetPageType(
|
|
34
|
-
pageType: any,
|
|
35
|
-
): pageType is LinkTargetPageType {
|
|
36
|
-
return pageType in linkTargetPageTypes;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
function pageTypeRequiresPath(type: LinkTargetPageType) {
|
|
40
|
-
return linkTargetPageTypes[type];
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export interface PageLinkTarget extends LinkTargetBase {
|
|
44
|
-
type: 'page';
|
|
45
|
-
pageType: LinkTargetPageType;
|
|
46
|
-
path?: string;
|
|
47
|
-
_href?: string;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export interface AbsoluteLinkTarget extends LinkTargetBase {
|
|
51
|
-
type: 'absolute';
|
|
52
|
-
href: string;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export interface ExternalLinkTarget extends LinkTargetBase {
|
|
56
|
-
type: 'external';
|
|
57
|
-
href: string;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
export type LinkTarget =
|
|
61
|
-
| UniqueLinkTarget
|
|
62
|
-
| PageLinkTarget
|
|
63
|
-
| AbsoluteLinkTarget
|
|
64
|
-
| ExternalLinkTarget;
|
|
65
|
-
|
|
66
|
-
export function createLinkTarget(
|
|
67
|
-
target: string,
|
|
68
|
-
context: BitranContext,
|
|
69
|
-
): LinkTarget {
|
|
70
|
-
target = tryReplaceAlias(target, context.aliases);
|
|
71
|
-
|
|
72
|
-
if (target.startsWith('/'))
|
|
73
|
-
return {
|
|
74
|
-
type: 'absolute',
|
|
75
|
-
href: target,
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
try {
|
|
79
|
-
new URL(target);
|
|
80
|
-
return {
|
|
81
|
-
type: 'external',
|
|
82
|
-
href: target,
|
|
83
|
-
};
|
|
84
|
-
} catch {}
|
|
85
|
-
|
|
86
|
-
if (target.startsWith('page|')) {
|
|
87
|
-
let [, pageType, path] = target.split('|');
|
|
88
|
-
|
|
89
|
-
if (!isLinkTargetPageType(pageType))
|
|
90
|
-
throw new Error(
|
|
91
|
-
`Unknown page type "${pageType}" in link "${target}"!`,
|
|
92
|
-
);
|
|
93
|
-
|
|
94
|
-
if (!path) {
|
|
95
|
-
if (isTopicPart(pageType)) {
|
|
96
|
-
if (!isTopicPart(context.location.type))
|
|
97
|
-
throw new Error(
|
|
98
|
-
`Page link "${target}" is referencing topic part "${pageType}" without path in non-topic context!`,
|
|
99
|
-
);
|
|
100
|
-
|
|
101
|
-
path = context.location.path;
|
|
102
|
-
} else {
|
|
103
|
-
if (pageTypeRequiresPath(pageType))
|
|
104
|
-
throw new Error(
|
|
105
|
-
`Page link "${target}" does not have a path!`,
|
|
106
|
-
);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
return {
|
|
111
|
-
type: 'page',
|
|
112
|
-
pageType,
|
|
113
|
-
path,
|
|
114
|
-
};
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
const location = parsePartialBitranLocation(target, context.location);
|
|
118
|
-
|
|
119
|
-
if (
|
|
120
|
-
!location.unique &&
|
|
121
|
-
isLinkTargetPageType(location.type) &&
|
|
122
|
-
!isTopicPart(location.type)
|
|
123
|
-
)
|
|
124
|
-
return {
|
|
125
|
-
type: 'page',
|
|
126
|
-
pageType: location.type,
|
|
127
|
-
path: location.path,
|
|
128
|
-
};
|
|
129
|
-
|
|
130
|
-
return {
|
|
131
|
-
type: 'unique',
|
|
132
|
-
strlocation: stringifyBitranLocation(location),
|
|
133
|
-
};
|
|
134
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { defineElementTranspiler } from '@bitran-js/transpiler';
|
|
2
|
-
|
|
3
|
-
import { LinkNode, type LinkSchema } from './shared';
|
|
4
|
-
import { LinkParser, LinkStringifier } from './factory';
|
|
5
|
-
|
|
6
|
-
export const linkTranspiler = defineElementTranspiler<LinkSchema>({
|
|
7
|
-
Node: LinkNode,
|
|
8
|
-
Parsers: [LinkParser],
|
|
9
|
-
Stringifier: LinkStringifier,
|
|
10
|
-
});
|
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
import { isTopicPart } from '@erudit-js/cog/schema';
|
|
2
|
-
|
|
3
|
-
export const bitranLocationTypes = {
|
|
4
|
-
article: true,
|
|
5
|
-
summary: true,
|
|
6
|
-
practice: true,
|
|
7
|
-
group: true,
|
|
8
|
-
contributor: true,
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
export type BitranLocationType = keyof typeof bitranLocationTypes;
|
|
12
|
-
|
|
13
|
-
export function isBitranLocationType(type: any): type is BitranLocationType {
|
|
14
|
-
return type in bitranLocationTypes;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function typeRequiresPath(type: BitranLocationType) {
|
|
18
|
-
return bitranLocationTypes[type];
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export interface BitranLocation {
|
|
22
|
-
type: BitranLocationType;
|
|
23
|
-
path?: string;
|
|
24
|
-
unique?: string;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export function stringifyBitranLocation(location: BitranLocation): string {
|
|
28
|
-
try {
|
|
29
|
-
if (!isBitranLocationType(location.type))
|
|
30
|
-
throw `Unknown Bitran location type "${location.type}"!`;
|
|
31
|
-
|
|
32
|
-
if (!location.path && typeRequiresPath(location.type))
|
|
33
|
-
throw 'Missing Bitran location path!';
|
|
34
|
-
|
|
35
|
-
if (location.unique === '')
|
|
36
|
-
throw 'Bitran location unique cannot be empty string!';
|
|
37
|
-
} catch (reason) {
|
|
38
|
-
let message = `${reason}\n\n` + JSON.stringify(location, null, 4);
|
|
39
|
-
throw new Error(message);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
return (
|
|
43
|
-
location.type +
|
|
44
|
-
'|' +
|
|
45
|
-
(location.path || '') +
|
|
46
|
-
(location.unique ? '|' + location.unique : '')
|
|
47
|
-
);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export function parseBitranLocation(strLocation: string): BitranLocation {
|
|
51
|
-
const [strType, strPath, strUnique] = strLocation.split('|');
|
|
52
|
-
|
|
53
|
-
if (!isBitranLocationType(strType))
|
|
54
|
-
throw new Error(`Unknown Bitran location type "${strType}"!`);
|
|
55
|
-
|
|
56
|
-
const location: BitranLocation = { type: strType };
|
|
57
|
-
|
|
58
|
-
if (!strPath) {
|
|
59
|
-
if (typeRequiresPath(location.type))
|
|
60
|
-
throw new Error(
|
|
61
|
-
`Missing Bitran location path for type "${strType}"!`,
|
|
62
|
-
);
|
|
63
|
-
} else location.path = strPath;
|
|
64
|
-
|
|
65
|
-
if (strUnique === '')
|
|
66
|
-
throw `Bitran location "${strLocation}" unique cannot be empty string!`;
|
|
67
|
-
else if (strUnique) location.unique = strUnique;
|
|
68
|
-
|
|
69
|
-
return location;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
export function parsePartialBitranLocation(
|
|
73
|
-
strLocation: string,
|
|
74
|
-
contextLocation: BitranLocation,
|
|
75
|
-
): BitranLocation {
|
|
76
|
-
const parts = strLocation.split('|');
|
|
77
|
-
|
|
78
|
-
// Only unique provided. Restoring type + path
|
|
79
|
-
// function -> article|foo/bar|function
|
|
80
|
-
if (parts.length === 1)
|
|
81
|
-
return {
|
|
82
|
-
type: contextLocation.type,
|
|
83
|
-
path: contextLocation.path,
|
|
84
|
-
unique: parts[0],
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
if (parts.length === 2) {
|
|
88
|
-
//
|
|
89
|
-
// If there are two parts, the result depends on location type
|
|
90
|
-
//
|
|
91
|
-
|
|
92
|
-
// In topics we can reference topic parts without specifying content path
|
|
93
|
-
// practice|function -> practice|foo/bar|function
|
|
94
|
-
if (isTopicPart(parts[0])) {
|
|
95
|
-
const [type, unique] = parts as [BitranLocationType, string];
|
|
96
|
-
|
|
97
|
-
if (!isTopicPart(contextLocation.type))
|
|
98
|
-
throw new Error(
|
|
99
|
-
`String Bitran location "${strLocation}" referencing topic part "${type}" in non-topic context!`,
|
|
100
|
-
);
|
|
101
|
-
|
|
102
|
-
return {
|
|
103
|
-
type,
|
|
104
|
-
path: contextLocation.path,
|
|
105
|
-
unique,
|
|
106
|
-
};
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
return parseBitranLocation(strLocation);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
export const { encodeBitranLocation, decodeBitranLocation } = (() => {
|
|
114
|
-
const encodeSymbols = {
|
|
115
|
-
'|': '┃',
|
|
116
|
-
'/': '╱',
|
|
117
|
-
':': '﹕',
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
const decodeSymbols = Object.entries(encodeSymbols).reduce(
|
|
121
|
-
(map, [key, value]) => ((map[value] = key), map),
|
|
122
|
-
{} as Record<string, string>,
|
|
123
|
-
);
|
|
124
|
-
|
|
125
|
-
const replaceSymbols = (text: string, symbols: Record<string, string>) => {
|
|
126
|
-
for (const [find, replace] of Object.entries(symbols))
|
|
127
|
-
text = text.replaceAll(find, replace);
|
|
128
|
-
|
|
129
|
-
return text;
|
|
130
|
-
};
|
|
131
|
-
|
|
132
|
-
return {
|
|
133
|
-
encodeBitranLocation: (strLocation: string) =>
|
|
134
|
-
replaceSymbols(strLocation, encodeSymbols),
|
|
135
|
-
|
|
136
|
-
decodeBitranLocation: (strLocation: string) =>
|
|
137
|
-
replaceSymbols(strLocation, decodeSymbols),
|
|
138
|
-
};
|
|
139
|
-
})();
|
|
140
|
-
|
|
141
|
-
export function locationFromPath(routePath: string) {
|
|
142
|
-
const pathParts = (
|
|
143
|
-
routePath.startsWith('/') ? routePath.substring(1) : routePath
|
|
144
|
-
).split('/');
|
|
145
|
-
const firstPart = pathParts.shift() as any;
|
|
146
|
-
const locationPath = pathParts.join('/');
|
|
147
|
-
|
|
148
|
-
if (!locationPath) return undefined;
|
|
149
|
-
|
|
150
|
-
if (isTopicPart(firstPart))
|
|
151
|
-
return {
|
|
152
|
-
type: firstPart,
|
|
153
|
-
path: locationPath,
|
|
154
|
-
};
|
|
155
|
-
|
|
156
|
-
switch (firstPart) {
|
|
157
|
-
case 'group':
|
|
158
|
-
case 'contributor':
|
|
159
|
-
return {
|
|
160
|
-
type: firstPart,
|
|
161
|
-
path: locationPath,
|
|
162
|
-
};
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
return undefined;
|
|
166
|
-
}
|
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
import { NO_ALIASES } from '@erudit-js/bitran-elements/aliases/shared';
|
|
2
|
-
|
|
3
|
-
console.log(NO_ALIASES());
|
|
4
|
-
|
|
5
|
-
import type { BitranContext } from '@erudit/shared/bitran/context';
|
|
6
|
-
import {
|
|
7
|
-
createLinkTarget,
|
|
8
|
-
type AbsoluteLinkTarget,
|
|
9
|
-
type ExternalLinkTarget,
|
|
10
|
-
type LinkTargetType,
|
|
11
|
-
type PageLinkTarget,
|
|
12
|
-
type UniqueLinkTarget,
|
|
13
|
-
} from '@erudit/shared/bitran/link/target';
|
|
14
|
-
|
|
15
|
-
const articleContext: BitranContext = {
|
|
16
|
-
location: {
|
|
17
|
-
type: 'article',
|
|
18
|
-
path: 'a/b/c',
|
|
19
|
-
},
|
|
20
|
-
aliases: {
|
|
21
|
-
a1: 'alias1',
|
|
22
|
-
},
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
const contributorContext: BitranContext = {
|
|
26
|
-
location: {
|
|
27
|
-
type: 'contributor',
|
|
28
|
-
path: 'john',
|
|
29
|
-
},
|
|
30
|
-
aliases: NO_ALIASES(),
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
//
|
|
34
|
-
//
|
|
35
|
-
//
|
|
36
|
-
|
|
37
|
-
const absoluteTargets = ['/', '/foo/bar/baz'];
|
|
38
|
-
|
|
39
|
-
const externalTargets = [
|
|
40
|
-
'http://www.google.com',
|
|
41
|
-
'http://www.google.com/',
|
|
42
|
-
'https://www.google.com/foo/bar/baz',
|
|
43
|
-
'https://www.google.com/foo/bar/baz?a=1&b=2#anchor',
|
|
44
|
-
];
|
|
45
|
-
|
|
46
|
-
const validPageTargets: [string, Pick<PageLinkTarget, 'pageType' | 'path'>][] =
|
|
47
|
-
[
|
|
48
|
-
// With "page|" prefix
|
|
49
|
-
['page|contributor|john', { pageType: 'contributor', path: 'john' }],
|
|
50
|
-
['page|article|foo/bar', { pageType: 'article', path: 'foo/bar' }],
|
|
51
|
-
[
|
|
52
|
-
'page|book|combinatorics',
|
|
53
|
-
{ pageType: 'book', path: 'combinatorics' },
|
|
54
|
-
],
|
|
55
|
-
[
|
|
56
|
-
'page|summary',
|
|
57
|
-
{ pageType: 'summary', path: articleContext.location.path },
|
|
58
|
-
],
|
|
59
|
-
// Without "page|" prefix for non-topic parts
|
|
60
|
-
['contributor|john', { pageType: 'contributor', path: 'john' }],
|
|
61
|
-
];
|
|
62
|
-
|
|
63
|
-
const invalidPageTargets = [
|
|
64
|
-
// Reference topic part in non-topic context
|
|
65
|
-
'page|article',
|
|
66
|
-
// Unknown page type
|
|
67
|
-
'page|foo|a/b/c',
|
|
68
|
-
// Unkown Bitran location type
|
|
69
|
-
'book|combinatorics',
|
|
70
|
-
];
|
|
71
|
-
|
|
72
|
-
const validUniqueTargets: [string, string][] = [
|
|
73
|
-
['definition', 'article|a/b/c|definition'],
|
|
74
|
-
['practice|term', 'practice|a/b/c|term'],
|
|
75
|
-
['contributor|john|theorem', 'contributor|john|theorem'],
|
|
76
|
-
];
|
|
77
|
-
|
|
78
|
-
//
|
|
79
|
-
//
|
|
80
|
-
//
|
|
81
|
-
|
|
82
|
-
describe('createLinkTarget', () => {
|
|
83
|
-
it.each(absoluteTargets)(
|
|
84
|
-
'should create absolute link target for %p',
|
|
85
|
-
(absoluteTarget) => {
|
|
86
|
-
const target = createLinkTarget(
|
|
87
|
-
absoluteTarget,
|
|
88
|
-
articleContext,
|
|
89
|
-
) as AbsoluteLinkTarget;
|
|
90
|
-
|
|
91
|
-
expect(target.type).toBe<LinkTargetType>('absolute');
|
|
92
|
-
expect(target.href).toBe(absoluteTarget);
|
|
93
|
-
},
|
|
94
|
-
);
|
|
95
|
-
|
|
96
|
-
it.each(externalTargets)(
|
|
97
|
-
'should create external link target for %p',
|
|
98
|
-
(externalTarget) => {
|
|
99
|
-
const target = createLinkTarget(
|
|
100
|
-
externalTarget,
|
|
101
|
-
articleContext,
|
|
102
|
-
) as ExternalLinkTarget;
|
|
103
|
-
|
|
104
|
-
expect(target.type).toBe<LinkTargetType>('external');
|
|
105
|
-
expect(target.href).toBe(externalTarget);
|
|
106
|
-
},
|
|
107
|
-
);
|
|
108
|
-
|
|
109
|
-
for (const [pageTarget, expected] of validPageTargets) {
|
|
110
|
-
it(`should create page link target for "${pageTarget}"`, () => {
|
|
111
|
-
const target = createLinkTarget(
|
|
112
|
-
pageTarget,
|
|
113
|
-
articleContext,
|
|
114
|
-
) as PageLinkTarget;
|
|
115
|
-
|
|
116
|
-
expect(target.type).toBe<LinkTargetType>('page');
|
|
117
|
-
expect(target.pageType).toBe(expected.pageType);
|
|
118
|
-
expect(target.path).toBe(expected.path);
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
for (const invalidPageTarget of invalidPageTargets) {
|
|
123
|
-
it(`should throw on page link target "${invalidPageTarget}"`, () => {
|
|
124
|
-
expect(() =>
|
|
125
|
-
createLinkTarget(invalidPageTarget, contributorContext),
|
|
126
|
-
).toThrow();
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
for (const [uniqueTarget, expected] of validUniqueTargets) {
|
|
131
|
-
it(`should create unique link target for "${uniqueTarget}"`, () => {
|
|
132
|
-
const target = createLinkTarget(
|
|
133
|
-
uniqueTarget,
|
|
134
|
-
articleContext,
|
|
135
|
-
) as UniqueLinkTarget;
|
|
136
|
-
|
|
137
|
-
expect(target.type).toBe<LinkTargetType>('unique');
|
|
138
|
-
expect(target.strlocation).toBe(expected);
|
|
139
|
-
});
|
|
140
|
-
}
|
|
141
|
-
});
|
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
decodeBitranLocation,
|
|
3
|
-
encodeBitranLocation,
|
|
4
|
-
parseBitranLocation,
|
|
5
|
-
parsePartialBitranLocation,
|
|
6
|
-
stringifyBitranLocation,
|
|
7
|
-
type BitranLocation,
|
|
8
|
-
} from '@erudit/shared/bitran/location';
|
|
9
|
-
|
|
10
|
-
const locations: [BitranLocation, string][] = [
|
|
11
|
-
// Full locations
|
|
12
|
-
[{ type: 'article', path: 'foo', unique: 'bar' }, 'article|foo|bar'],
|
|
13
|
-
[{ type: 'group', path: 'foo', unique: 'bar' }, 'group|foo|bar'],
|
|
14
|
-
// Type + path
|
|
15
|
-
[{ type: 'article', path: 'foo' }, 'article|foo'],
|
|
16
|
-
[{ type: 'group', path: 'foo' }, 'group|foo'],
|
|
17
|
-
];
|
|
18
|
-
|
|
19
|
-
const partialLocations: [string, BitranLocation, BitranLocation][] = [
|
|
20
|
-
// Full string location
|
|
21
|
-
[
|
|
22
|
-
'article|foo/bar|baz',
|
|
23
|
-
{ type: 'group', path: 'qux' },
|
|
24
|
-
{ type: 'article', path: 'foo/bar', unique: 'baz' },
|
|
25
|
-
],
|
|
26
|
-
// Only unique
|
|
27
|
-
[
|
|
28
|
-
'baz',
|
|
29
|
-
{ type: 'summary', path: 'foo/bar' },
|
|
30
|
-
{ type: 'summary', path: 'foo/bar', unique: 'baz' },
|
|
31
|
-
],
|
|
32
|
-
[
|
|
33
|
-
'baz',
|
|
34
|
-
{ type: 'contributor', path: 'John' },
|
|
35
|
-
{ type: 'contributor', path: 'John', unique: 'baz' },
|
|
36
|
-
],
|
|
37
|
-
// Topic context
|
|
38
|
-
[
|
|
39
|
-
'article|baz',
|
|
40
|
-
{ type: 'practice', path: 'foo/bar' },
|
|
41
|
-
{ type: 'article', path: 'foo/bar', unique: 'baz' },
|
|
42
|
-
],
|
|
43
|
-
];
|
|
44
|
-
|
|
45
|
-
const invalidPartialLocations: [string, BitranLocation][] = [
|
|
46
|
-
// Referencing topic part in non-topic context
|
|
47
|
-
['article|bar', { type: 'contributor', path: 'foo' }],
|
|
48
|
-
];
|
|
49
|
-
|
|
50
|
-
const invalidLocations = [
|
|
51
|
-
// Too few parts
|
|
52
|
-
{ type: 'article' },
|
|
53
|
-
{ path: 'foo' },
|
|
54
|
-
{ unique: 'foo' },
|
|
55
|
-
// Unknown type
|
|
56
|
-
{ type: 'foo' },
|
|
57
|
-
{ type: 'foo', path: 'bar', unique: 'baz' },
|
|
58
|
-
// Locations that require path
|
|
59
|
-
{ type: 'article', unique: 'foo' },
|
|
60
|
-
{ type: 'summary', unique: 'foo' },
|
|
61
|
-
{ type: 'practice', unique: 'foo' },
|
|
62
|
-
{ type: 'group', unique: 'foo' },
|
|
63
|
-
{ type: 'contributor', unique: 'foo' },
|
|
64
|
-
];
|
|
65
|
-
|
|
66
|
-
const invalidStrLocations = [
|
|
67
|
-
// Too few parts
|
|
68
|
-
'article',
|
|
69
|
-
'group',
|
|
70
|
-
// Unknown type
|
|
71
|
-
'foo',
|
|
72
|
-
'foo|bar',
|
|
73
|
-
'foo|bar|baz',
|
|
74
|
-
// Empty string unique
|
|
75
|
-
'article|foo/bar|',
|
|
76
|
-
];
|
|
77
|
-
|
|
78
|
-
//
|
|
79
|
-
//
|
|
80
|
-
//
|
|
81
|
-
|
|
82
|
-
describe('stringifyBitranLocation', () => {
|
|
83
|
-
for (const [location, expected] of locations) {
|
|
84
|
-
it(`should produce "${expected}"`, () => {
|
|
85
|
-
expect(stringifyBitranLocation(location)).toBe(expected);
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
for (const invalidLocation of invalidLocations) {
|
|
90
|
-
it(`should throw on location ${JSON.stringify(invalidLocation)}`, () => {
|
|
91
|
-
expect(() =>
|
|
92
|
-
stringifyBitranLocation(invalidLocation as BitranLocation),
|
|
93
|
-
).toThrow();
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
describe('parseBitranLocation', () => {
|
|
99
|
-
for (const [location, expected] of locations) {
|
|
100
|
-
it(`should produce ${JSON.stringify(expected)}`, () => {
|
|
101
|
-
expect(parseBitranLocation(expected)).toEqual(location);
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
for (const invalidStrLocation of invalidStrLocations) {
|
|
106
|
-
it(`should throw on location "${invalidStrLocation}"`, () => {
|
|
107
|
-
expect(() => parseBitranLocation(invalidStrLocation)).toThrow();
|
|
108
|
-
});
|
|
109
|
-
}
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
describe('parsePartialBitranLocation', () => {
|
|
113
|
-
for (const [locationStr, context, expected] of partialLocations) {
|
|
114
|
-
it(`should produce ${JSON.stringify(expected)}`, () => {
|
|
115
|
-
expect(parsePartialBitranLocation(locationStr, context)).toEqual(
|
|
116
|
-
expected,
|
|
117
|
-
);
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
for (const [locationStr, context] of invalidPartialLocations) {
|
|
122
|
-
it(`should throw on location "${locationStr}"`, () => {
|
|
123
|
-
expect(() =>
|
|
124
|
-
parsePartialBitranLocation(locationStr, context),
|
|
125
|
-
).toThrow();
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
describe('decode/encodeBitranLocation', () => {
|
|
131
|
-
it.each([
|
|
132
|
-
'',
|
|
133
|
-
'foo',
|
|
134
|
-
'foo|bar',
|
|
135
|
-
'foo|bar|baz',
|
|
136
|
-
'foo|bar/baz|qux',
|
|
137
|
-
'foo|bar/baz/qux|corge:grault:waldo',
|
|
138
|
-
])('should not change string location %p', (testCase) =>
|
|
139
|
-
expect(decodeBitranLocation(encodeBitranLocation(testCase))).toBe(
|
|
140
|
-
testCase,
|
|
141
|
-
),
|
|
142
|
-
);
|
|
143
|
-
});
|