@mintlify/common 1.0.1152 → 1.0.1154
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/dist/mdx/plugins/remark/remarkUserMentions.d.ts +1 -0
- package/dist/mdx/plugins/remark/remarkUserMentions.js +100 -51
- package/dist/navigation/decoratedNavTree.d.ts +11 -0
- package/dist/navigation/decoratedNavTree.js +72 -0
- package/dist/navigation/decoratedNavTree.test.d.ts +1 -0
- package/dist/navigation/decoratedNavTree.test.js +51 -0
- package/dist/navigation/index.d.ts +1 -0
- package/dist/navigation/index.js +1 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +2 -2
|
@@ -3,4 +3,5 @@ import { type UserMentionNameResolver } from '../../mentions/userMentionToken.js
|
|
|
3
3
|
export type RemarkUserMentionsOptions = {
|
|
4
4
|
resolveUserName?: UserMentionNameResolver;
|
|
5
5
|
};
|
|
6
|
+
export declare function collectUserMentionText(tree: Root): string[];
|
|
6
7
|
export declare const remarkUserMentions: ({ resolveUserName }?: RemarkUserMentionsOptions) => (tree: Root) => void;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { visit } from 'unist-util-visit';
|
|
2
|
-
import { escapeMentionNameForSource, flattenUserMentionTokens, hasUserMentionTokens, isMentionTextAttribute, isUserMentionId, } from '../../mentions/userMentionToken.js';
|
|
2
|
+
import { escapeMentionNameForSource, extractUserMentionIds, flattenUserMentionTokens, hasUserMentionTokens, isMentionTextAttribute, isUserMentionId, userMentionToken, } from '../../mentions/userMentionToken.js';
|
|
3
3
|
import { isPromptBodySourceAttribute } from './remarkPrompt.js';
|
|
4
4
|
import { TITLE_COMPONENTS } from './remarkTitleMarkdown.js';
|
|
5
5
|
const IN_TEXT = { inText: true };
|
|
6
6
|
const isMdxJsxElement = (node) => node.type === 'mdxJsxFlowElement' || node.type === 'mdxJsxTextElement';
|
|
7
7
|
const isParent = (node) => 'children' in node && Array.isArray(node.children);
|
|
8
8
|
const isRecord = (value) => typeof value === 'object' && value !== null;
|
|
9
|
-
function
|
|
9
|
+
function stringLiteralSurface(expression, { escapeNames, scan }, onSurface) {
|
|
10
10
|
var _a;
|
|
11
11
|
const program = (_a = expression.data) === null || _a === void 0 ? void 0 : _a.estree;
|
|
12
12
|
const statement = program === null || program === void 0 ? void 0 : program.body[0];
|
|
@@ -15,45 +15,63 @@ function flattenStringLiteralExpression(expression, resolve, { escapeNames, rawS
|
|
|
15
15
|
const literal = statement.expression;
|
|
16
16
|
if (!isRecord(literal) || literal.type !== 'Literal' || typeof literal.value !== 'string')
|
|
17
17
|
return;
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
18
|
+
onSurface({
|
|
19
|
+
value: literal.value,
|
|
20
|
+
scan,
|
|
21
|
+
escapeNames,
|
|
22
|
+
set: (next) => {
|
|
23
|
+
literal.value = next;
|
|
24
|
+
literal.raw = JSON.stringify(next);
|
|
25
|
+
expression.value = JSON.stringify(next);
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
28
|
}
|
|
29
|
-
function
|
|
29
|
+
function shortcutMentionId(text, reference) {
|
|
30
30
|
var _a;
|
|
31
|
+
if (text.type !== 'text' || !text.value.endsWith('@'))
|
|
32
|
+
return undefined;
|
|
33
|
+
if (reference.type !== 'linkReference' || reference.referenceType !== 'shortcut')
|
|
34
|
+
return undefined;
|
|
35
|
+
const label = (_a = reference.label) !== null && _a !== void 0 ? _a : reference.identifier;
|
|
36
|
+
if (!isUserMentionId(label))
|
|
37
|
+
return undefined;
|
|
38
|
+
const [only, ...rest] = reference.children;
|
|
39
|
+
if (rest.length > 0 || !only || only.type !== 'text' || only.value !== label)
|
|
40
|
+
return undefined;
|
|
41
|
+
return label;
|
|
42
|
+
}
|
|
43
|
+
function shortcutReferenceSurfaces(parent, onSurface) {
|
|
31
44
|
const children = parent.children;
|
|
32
45
|
for (let index = 0; index < children.length - 1; index++) {
|
|
33
46
|
const text = children[index];
|
|
34
47
|
const reference = children[index + 1];
|
|
35
|
-
if (!text || !reference || text.type !== 'text'
|
|
36
|
-
continue;
|
|
37
|
-
if (reference.type !== 'linkReference' || reference.referenceType !== 'shortcut')
|
|
38
|
-
continue;
|
|
39
|
-
const label = (_a = reference.label) !== null && _a !== void 0 ? _a : reference.identifier;
|
|
40
|
-
if (!isUserMentionId(label))
|
|
48
|
+
if (!text || !reference || text.type !== 'text')
|
|
41
49
|
continue;
|
|
42
|
-
const
|
|
43
|
-
if (
|
|
50
|
+
const label = shortcutMentionId(text, reference);
|
|
51
|
+
if (label === undefined)
|
|
44
52
|
continue;
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
+
let folded = false;
|
|
54
|
+
onSurface({
|
|
55
|
+
value: userMentionToken(label),
|
|
56
|
+
scan: undefined,
|
|
57
|
+
escapeNames: false,
|
|
58
|
+
set: (next) => {
|
|
59
|
+
text.value = text.value.slice(0, -1) + next;
|
|
60
|
+
children.splice(index + 1, 1);
|
|
61
|
+
const following = children[index + 1];
|
|
62
|
+
if ((following === null || following === void 0 ? void 0 : following.type) === 'text') {
|
|
63
|
+
text.value += following.value;
|
|
64
|
+
children.splice(index + 1, 1);
|
|
65
|
+
}
|
|
66
|
+
folded = true;
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
if (folded)
|
|
70
|
+
index--;
|
|
53
71
|
}
|
|
54
72
|
}
|
|
55
73
|
// A Prompt body is plain text on the page, so code and math inside it are text there too.
|
|
56
|
-
function
|
|
74
|
+
function promptCodeSurfaces(prompt, onSurface) {
|
|
57
75
|
visit(prompt, (child) => {
|
|
58
76
|
if (child.type !== 'inlineCode' &&
|
|
59
77
|
child.type !== 'code' &&
|
|
@@ -61,47 +79,78 @@ function flattenPromptCode(prompt, resolve) {
|
|
|
61
79
|
child.type !== 'math') {
|
|
62
80
|
return;
|
|
63
81
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
82
|
+
onSurface({
|
|
83
|
+
value: child.value,
|
|
84
|
+
scan: undefined,
|
|
85
|
+
escapeNames: false,
|
|
86
|
+
set: (next) => {
|
|
87
|
+
child.value = next;
|
|
88
|
+
},
|
|
89
|
+
});
|
|
67
90
|
});
|
|
68
91
|
}
|
|
69
|
-
|
|
70
|
-
|
|
92
|
+
// Body text and text-bearing component attributes only: image alt/title, link
|
|
93
|
+
// and definition titles are HTML attributes and stay as written.
|
|
94
|
+
function visitUserMentionSurfaces(tree, onSurface) {
|
|
71
95
|
visit(tree, (node) => {
|
|
72
96
|
if (node.type === 'text') {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
97
|
+
const text = node;
|
|
98
|
+
onSurface({
|
|
99
|
+
value: text.value,
|
|
100
|
+
scan: IN_TEXT,
|
|
101
|
+
escapeNames: false,
|
|
102
|
+
set: (next) => {
|
|
103
|
+
text.value = next;
|
|
104
|
+
},
|
|
105
|
+
});
|
|
76
106
|
return;
|
|
77
107
|
}
|
|
78
108
|
if (isMdxJsxElement(node)) {
|
|
79
109
|
if (node.name === 'Prompt')
|
|
80
|
-
|
|
110
|
+
promptCodeSurfaces(node, onSurface);
|
|
81
111
|
const titleIsMarkdown = node.name !== null && TITLE_COMPONENTS.has(node.name);
|
|
82
112
|
for (const attribute of node.attributes) {
|
|
83
113
|
if (attribute.type !== 'mdxJsxAttribute' || !isMentionTextAttribute(attribute.name)) {
|
|
84
114
|
continue;
|
|
85
115
|
}
|
|
116
|
+
const escapeNames = titleIsMarkdown && attribute.name === 'title';
|
|
86
117
|
if (typeof attribute.value === 'string') {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
118
|
+
onSurface({
|
|
119
|
+
value: attribute.value,
|
|
120
|
+
scan: IN_TEXT,
|
|
121
|
+
escapeNames,
|
|
122
|
+
set: (next) => {
|
|
123
|
+
attribute.value = next;
|
|
124
|
+
},
|
|
125
|
+
});
|
|
94
126
|
}
|
|
95
127
|
else if (attribute.value && typeof attribute.value === 'object') {
|
|
96
|
-
|
|
97
|
-
escapeNames: titleIsMarkdown && attribute.name === 'title',
|
|
98
|
-
rawSource: isPromptBodySourceAttribute(attribute),
|
|
99
|
-
});
|
|
128
|
+
stringLiteralSurface(attribute.value, { escapeNames, scan: isPromptBodySourceAttribute(attribute) ? undefined : IN_TEXT }, onSurface);
|
|
100
129
|
}
|
|
101
130
|
}
|
|
102
131
|
}
|
|
103
132
|
if (isParent(node) && node.children.some((child) => child.type === 'linkReference')) {
|
|
104
|
-
|
|
133
|
+
shortcutReferenceSurfaces(node, onSurface);
|
|
105
134
|
}
|
|
106
135
|
});
|
|
136
|
+
}
|
|
137
|
+
export function collectUserMentionText(tree) {
|
|
138
|
+
const out = [];
|
|
139
|
+
visitUserMentionSurfaces(tree, ({ value, scan }) => {
|
|
140
|
+
if (scan === IN_TEXT)
|
|
141
|
+
out.push(value);
|
|
142
|
+
else
|
|
143
|
+
out.push(...extractUserMentionIds(value).map(userMentionToken));
|
|
144
|
+
});
|
|
145
|
+
return out;
|
|
146
|
+
}
|
|
147
|
+
export const remarkUserMentions = ({ resolveUserName } = {}) => (tree) => {
|
|
148
|
+
visitUserMentionSurfaces(tree, ({ value, scan, escapeNames, set }) => {
|
|
149
|
+
if (!hasUserMentionTokens(value, scan))
|
|
150
|
+
return;
|
|
151
|
+
set(flattenUserMentionTokens(value, (userId) => {
|
|
152
|
+
const name = resolveUserName === null || resolveUserName === void 0 ? void 0 : resolveUserName(userId);
|
|
153
|
+
return name === undefined || !escapeNames ? name : escapeMentionNameForSource(name);
|
|
154
|
+
}, scan));
|
|
155
|
+
});
|
|
107
156
|
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { DecoratedDivisionConfig, DecoratedGroupConfig, DecoratedNavigationConfig, DecoratedPageConfig } from '@mintlify/validation';
|
|
2
|
+
export type DecoratedNavNode = DecoratedNavigationConfig | DecoratedDivisionConfig | DecoratedGroupConfig | DecoratedPageConfig;
|
|
3
|
+
export type DecoratedNavPageEntry = {
|
|
4
|
+
title: string;
|
|
5
|
+
mode?: string;
|
|
6
|
+
};
|
|
7
|
+
export declare function decoratedNavDivisions(node: DecoratedNavNode): DecoratedDivisionConfig[];
|
|
8
|
+
export declare function decoratedNavChildren(node: DecoratedNavNode): DecoratedNavNode[];
|
|
9
|
+
export declare const decoratedNavContains: (node: DecoratedNavNode, path: string) => boolean;
|
|
10
|
+
export declare const findDecoratedNavPage: (node: DecoratedNavNode, path: string) => DecoratedNavPageEntry | null;
|
|
11
|
+
export declare function decoratedNavSections(nav: DecoratedNavNode, path: string): DecoratedNavNode[];
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { replaceSlashIndex } from '../slug/replaceSlashIndex.js';
|
|
2
|
+
import { isPage } from './isPage.js';
|
|
3
|
+
const normalizeNavPath = (p) => replaceSlashIndex(p.replace(/^\/+/, '').replace(/\/+$/, ''));
|
|
4
|
+
const hrefOf = (node) => isPage(node) ? node.href : 'href' in node ? node.href : undefined;
|
|
5
|
+
export function decoratedNavDivisions(node) {
|
|
6
|
+
if (isPage(node))
|
|
7
|
+
return [];
|
|
8
|
+
if ('languages' in node)
|
|
9
|
+
return node.languages;
|
|
10
|
+
if ('versions' in node)
|
|
11
|
+
return node.versions;
|
|
12
|
+
if ('products' in node)
|
|
13
|
+
return node.products;
|
|
14
|
+
if ('tabs' in node)
|
|
15
|
+
return node.tabs;
|
|
16
|
+
if ('anchors' in node)
|
|
17
|
+
return node.anchors;
|
|
18
|
+
if ('dropdowns' in node)
|
|
19
|
+
return node.dropdowns;
|
|
20
|
+
return [];
|
|
21
|
+
}
|
|
22
|
+
export function decoratedNavChildren(node) {
|
|
23
|
+
if (isPage(node))
|
|
24
|
+
return [];
|
|
25
|
+
if ('group' in node)
|
|
26
|
+
return node.root ? [node.root, ...node.pages] : node.pages;
|
|
27
|
+
if ('pages' in node)
|
|
28
|
+
return node.pages;
|
|
29
|
+
if ('groups' in node)
|
|
30
|
+
return node.groups;
|
|
31
|
+
if ('menu' in node)
|
|
32
|
+
return node.menu;
|
|
33
|
+
return [];
|
|
34
|
+
}
|
|
35
|
+
const matches = (node, path) => {
|
|
36
|
+
const href = hrefOf(node);
|
|
37
|
+
return href !== undefined && normalizeNavPath(href) === path;
|
|
38
|
+
};
|
|
39
|
+
function contains(node, path) {
|
|
40
|
+
if (matches(node, path))
|
|
41
|
+
return true;
|
|
42
|
+
return (decoratedNavChildren(node).some((c) => contains(c, path)) ||
|
|
43
|
+
decoratedNavDivisions(node).some((c) => contains(c, path)));
|
|
44
|
+
}
|
|
45
|
+
function findPage(node, path) {
|
|
46
|
+
if (isPage(node))
|
|
47
|
+
return matches(node, path) ? { title: node.title, mode: node.mode } : null;
|
|
48
|
+
for (const child of [...decoratedNavChildren(node), ...decoratedNavDivisions(node)]) {
|
|
49
|
+
const found = findPage(child, path);
|
|
50
|
+
if (found)
|
|
51
|
+
return found;
|
|
52
|
+
}
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
export const decoratedNavContains = (node, path) => contains(node, normalizeNavPath(path));
|
|
56
|
+
export const findDecoratedNavPage = (node, path) => findPage(node, normalizeNavPath(path));
|
|
57
|
+
// the nodes whose own pages (not a nested division's) hold the path: the
|
|
58
|
+
// root for a flat nav, else the innermost division chain down to the page
|
|
59
|
+
export function decoratedNavSections(nav, path) {
|
|
60
|
+
const target = normalizeNavPath(path);
|
|
61
|
+
const out = [];
|
|
62
|
+
const walk = (node) => {
|
|
63
|
+
for (const division of decoratedNavDivisions(node)) {
|
|
64
|
+
if (contains(division, target))
|
|
65
|
+
walk(division);
|
|
66
|
+
}
|
|
67
|
+
if (decoratedNavChildren(node).some((c) => contains(c, target)))
|
|
68
|
+
out.push(node);
|
|
69
|
+
};
|
|
70
|
+
walk(nav);
|
|
71
|
+
return out;
|
|
72
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { decoratedNavContains, decoratedNavSections, findDecoratedNavPage, } from './decoratedNavTree.js';
|
|
2
|
+
const nav = {
|
|
3
|
+
tabs: [
|
|
4
|
+
{
|
|
5
|
+
tab: 'Guides',
|
|
6
|
+
groups: [
|
|
7
|
+
{ group: 'Start', pages: [{ href: '/guides/intro', title: 'Intro' }] },
|
|
8
|
+
{ group: 'More', pages: [{ href: '/guides/deploy', title: 'Deploy', mode: 'custom' }] },
|
|
9
|
+
],
|
|
10
|
+
},
|
|
11
|
+
{ tab: 'API', pages: [{ href: '/api/overview', title: 'Overview' }] },
|
|
12
|
+
],
|
|
13
|
+
};
|
|
14
|
+
describe('decoratedNavContains', () => {
|
|
15
|
+
it('finds pages through divisions and groups, ignoring slashes and /index', () => {
|
|
16
|
+
expect(decoratedNavContains(nav, '/guides/deploy')).toBe(true);
|
|
17
|
+
expect(decoratedNavContains(nav, 'guides/deploy/')).toBe(true);
|
|
18
|
+
expect(decoratedNavContains(nav, '/api/overview/index')).toBe(true);
|
|
19
|
+
expect(decoratedNavContains(nav, '/nowhere')).toBe(false);
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
describe('findDecoratedNavPage', () => {
|
|
23
|
+
it('returns the page title and mode', () => {
|
|
24
|
+
expect(findDecoratedNavPage(nav, '/guides/deploy')).toEqual({
|
|
25
|
+
title: 'Deploy',
|
|
26
|
+
mode: 'custom',
|
|
27
|
+
});
|
|
28
|
+
expect(findDecoratedNavPage(nav, '/api/overview')).toEqual({
|
|
29
|
+
title: 'Overview',
|
|
30
|
+
mode: undefined,
|
|
31
|
+
});
|
|
32
|
+
expect(findDecoratedNavPage(nav, '/nowhere')).toBeNull();
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
describe('decoratedNavSections', () => {
|
|
36
|
+
it('returns the division whose own pages hold the path', () => {
|
|
37
|
+
const sections = decoratedNavSections(nav, '/guides/intro');
|
|
38
|
+
expect(sections).toHaveLength(1);
|
|
39
|
+
expect(sections[0]).toBe(nav.tabs[0]);
|
|
40
|
+
expect(decoratedNavSections(nav, '/nowhere')).toEqual([]);
|
|
41
|
+
});
|
|
42
|
+
it('returns the root for a flat nav', () => {
|
|
43
|
+
const flat = {
|
|
44
|
+
pages: [
|
|
45
|
+
{ href: '/a', title: 'A' },
|
|
46
|
+
{ href: '/b', title: 'B' },
|
|
47
|
+
],
|
|
48
|
+
};
|
|
49
|
+
expect(decoratedNavSections(flat, '/a')).toEqual([flat]);
|
|
50
|
+
});
|
|
51
|
+
});
|
|
@@ -4,6 +4,7 @@ export * from './generatePathToBreadcrumbsMap.js';
|
|
|
4
4
|
export * from './getFirstPageFromNavigation.js';
|
|
5
5
|
export * from './generatePathToBreadcrumbsMapForDocsConfig.js';
|
|
6
6
|
export * from './getAllPathsInDocsNav.js';
|
|
7
|
+
export * from './decoratedNavTree.js';
|
|
7
8
|
export * from './getAllPathsInDecoratedNav.js';
|
|
8
9
|
export * from './checkNavAccess.js';
|
|
9
10
|
export * from './filterDivisions.js';
|
package/dist/navigation/index.js
CHANGED
|
@@ -4,6 +4,7 @@ export * from './generatePathToBreadcrumbsMap.js';
|
|
|
4
4
|
export * from './getFirstPageFromNavigation.js';
|
|
5
5
|
export * from './generatePathToBreadcrumbsMapForDocsConfig.js';
|
|
6
6
|
export * from './getAllPathsInDocsNav.js';
|
|
7
|
+
export * from './decoratedNavTree.js';
|
|
7
8
|
export * from './getAllPathsInDecoratedNav.js';
|
|
8
9
|
export * from './checkNavAccess.js';
|
|
9
10
|
export * from './filterDivisions.js';
|