@mintlify/common 1.0.1197 → 1.0.1199
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/lib/remark-utils.js +8 -0
- package/dist/mdx/plugins/remark/remarkExtractTableOfContents.js +46 -16
- package/dist/mdx/plugins/remark/remarkMdxRemoveUnknownJsx/index.d.ts +1 -1
- package/dist/mdx/plugins/remark/remarkValidateVisibility.js +3 -3
- package/dist/mdx/plugins/remark/remarkVisibilityForMarkdown.d.ts +18 -1
- package/dist/mdx/plugins/remark/remarkVisibilityForMarkdown.js +124 -12
- package/dist/navigation/groupAccess.js +8 -2
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/types/mdx/TableOfContentsSectionType.d.ts +2 -0
- package/package.json +3 -2
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isVisibilityElement, resolveVisibilityFor, } from '../plugins/remark/remarkVisibilityForMarkdown.js';
|
|
1
2
|
export const createMdxJsxAttribute = (key, value) => {
|
|
2
3
|
return {
|
|
3
4
|
type: 'mdxJsxAttribute',
|
|
@@ -24,6 +25,13 @@ export const getTableOfContentsTitle = (node, index = 1, children = EMPTY_CHILDR
|
|
|
24
25
|
const labelAttr = node.attributes.find((attr) => 'name' in attr && attr.name === 'label' && typeof attr.value === 'string');
|
|
25
26
|
return (_a = labelAttr === null || labelAttr === void 0 ? void 0 : labelAttr.value) !== null && _a !== void 0 ? _a : '';
|
|
26
27
|
}
|
|
28
|
+
if (isVisibilityElement(node)) {
|
|
29
|
+
const resolution = resolveVisibilityFor(node);
|
|
30
|
+
const visibleToEveryone = resolution.kind === 'dynamic' ||
|
|
31
|
+
(resolution.kind === 'audience' && resolution.audience === 'humans');
|
|
32
|
+
if (!visibleToEveryone)
|
|
33
|
+
return '';
|
|
34
|
+
}
|
|
27
35
|
const lastChild = children[index - 1];
|
|
28
36
|
const isText = node.type === 'text';
|
|
29
37
|
const isInlineCode = node.type === 'inlineCode';
|
|
@@ -3,7 +3,7 @@ import { safeCleanHeadingId, slugify } from '../../../slugify.js';
|
|
|
3
3
|
import { createMdxJsxAttribute, getTableOfContentsTitle, getTitleMarkdownText, } from '../../lib/remark-utils.js';
|
|
4
4
|
import { isMdxJsxFragment } from '../../utils.js';
|
|
5
5
|
import { AVOIDED_PAGE_MODES, HEADING_LEVELS } from './remarkComponentIds.js';
|
|
6
|
-
import { isHiddenFromHumans, isVisibilityElement, resolveVisibilityFor, } from './remarkVisibilityForMarkdown.js';
|
|
6
|
+
import { isHiddenFromHumans, isVisibilityElement, resolveVisibilityFor, toVisibilityAuthRule, } from './remarkVisibilityForMarkdown.js';
|
|
7
7
|
import { isVariationElement, resolveVariationIds } from './variation.js';
|
|
8
8
|
export const HEADING_NAMES = ['h1', 'h2', 'h3', 'h4'];
|
|
9
9
|
const COMPONENTS_TO_EXCLUDE_HEADINGS = [
|
|
@@ -20,6 +20,13 @@ function getStringAttribute(attributes, name) {
|
|
|
20
20
|
}
|
|
21
21
|
return undefined;
|
|
22
22
|
}
|
|
23
|
+
const authRuleKey = (rule) => typeof rule === 'string' ? rule : JSON.stringify([...rule.groups].sort());
|
|
24
|
+
const hasAuthRules = (childRules, parentRules) => {
|
|
25
|
+
if (parentRules === undefined)
|
|
26
|
+
return true;
|
|
27
|
+
const childKeys = new Set(childRules === null || childRules === void 0 ? void 0 : childRules.map(authRuleKey));
|
|
28
|
+
return parentRules.every((rule) => childKeys.has(authRuleKey(rule)));
|
|
29
|
+
};
|
|
23
30
|
export const remarkExtractTableOfContents = (mdxExtracts, pageMetadata) => {
|
|
24
31
|
// Unified slug deduplication: both custom IDs and auto-generated slugs
|
|
25
32
|
// share the same seen-slug state so they cannot collide.
|
|
@@ -46,6 +53,7 @@ export const remarkExtractTableOfContents = (mdxExtracts, pageMetadata) => {
|
|
|
46
53
|
const tabContentMap = new Map();
|
|
47
54
|
const viewContentMap = new Map();
|
|
48
55
|
const variationContentMap = new Map();
|
|
56
|
+
const authRulesContentMap = new Map();
|
|
49
57
|
// Maps a Step node to the titleSize inherited from its parent <Steps>.
|
|
50
58
|
// At render time <Steps titleSize> is forwarded to each child <Step> that
|
|
51
59
|
// doesn't set its own titleSize, so the TOC must honor the same fallback.
|
|
@@ -61,12 +69,26 @@ export const remarkExtractTableOfContents = (mdxExtracts, pageMetadata) => {
|
|
|
61
69
|
});
|
|
62
70
|
}
|
|
63
71
|
const visibilityNode = node;
|
|
64
|
-
if (isVisibilityElement(visibilityNode)
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
72
|
+
if (isVisibilityElement(visibilityNode)) {
|
|
73
|
+
const resolution = resolveVisibilityFor(visibilityNode);
|
|
74
|
+
const authRule = toVisibilityAuthRule(resolution);
|
|
75
|
+
if (isHiddenFromHumans(resolution)) {
|
|
76
|
+
visit(node, (childNode) => {
|
|
77
|
+
if (childNode !== node)
|
|
78
|
+
excludedNodes.add(childNode);
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
else if (authRule) {
|
|
82
|
+
visit(node, (childNode) => {
|
|
83
|
+
var _a;
|
|
84
|
+
if (childNode === node)
|
|
85
|
+
return;
|
|
86
|
+
authRulesContentMap.set(childNode, [
|
|
87
|
+
...((_a = authRulesContentMap.get(childNode)) !== null && _a !== void 0 ? _a : []),
|
|
88
|
+
authRule,
|
|
89
|
+
]);
|
|
90
|
+
});
|
|
91
|
+
}
|
|
70
92
|
}
|
|
71
93
|
if (node.type === 'mdxJsxFlowElement' && node.name === 'Steps') {
|
|
72
94
|
const stepsTitleSize = getStringAttribute(node.attributes, 'titleSize');
|
|
@@ -123,6 +145,8 @@ export const remarkExtractTableOfContents = (mdxExtracts, pageMetadata) => {
|
|
|
123
145
|
}
|
|
124
146
|
});
|
|
125
147
|
const pushEntry = (entry, level) => {
|
|
148
|
+
if (!entry.title.trim())
|
|
149
|
+
return;
|
|
126
150
|
if (level !== undefined && Number(level) <= 2) {
|
|
127
151
|
hasTopLayer = true;
|
|
128
152
|
contents.push(entry);
|
|
@@ -133,23 +157,26 @@ export const remarkExtractTableOfContents = (mdxExtracts, pageMetadata) => {
|
|
|
133
157
|
if (hasTopLayer) {
|
|
134
158
|
const lastTopLevel = contents.at(-1);
|
|
135
159
|
if (lastTopLevel &&
|
|
160
|
+
!(lastTopLevel.depth > 2 && lastTopLevel.depth >= entry.depth) &&
|
|
136
161
|
(lastTopLevel.tabId === undefined || lastTopLevel.tabId === entry.tabId) &&
|
|
137
162
|
(lastTopLevel.viewId === undefined || lastTopLevel.viewId === entry.viewId) &&
|
|
138
163
|
(lastTopLevel.variationIds === undefined ||
|
|
139
164
|
(entry.variationIds !== undefined &&
|
|
140
|
-
entry.variationIds.every((id) => { var _a; return (_a = lastTopLevel.variationIds) === null || _a === void 0 ? void 0 : _a.includes(id); })))
|
|
165
|
+
entry.variationIds.every((id) => { var _a; return (_a = lastTopLevel.variationIds) === null || _a === void 0 ? void 0 : _a.includes(id); }))) &&
|
|
166
|
+
hasAuthRules(entry.authRules, lastTopLevel.authRules)) {
|
|
141
167
|
arrToPushInto = lastTopLevel.children;
|
|
142
168
|
}
|
|
143
169
|
}
|
|
144
170
|
arrToPushInto.push(entry);
|
|
145
171
|
};
|
|
146
172
|
visit(tree, (node) => {
|
|
147
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
173
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
148
174
|
if (excludedNodes.has(node))
|
|
149
175
|
return;
|
|
150
176
|
const currentTabId = tabContentMap.get(node);
|
|
151
177
|
const currentViewId = viewContentMap.get(node);
|
|
152
178
|
const currentVariationIds = variationContentMap.get(node);
|
|
179
|
+
const currentAuthRules = authRulesContentMap.get(node);
|
|
153
180
|
if (node.type === 'mdxFlowExpression' || node.type === 'mdxTextExpression') {
|
|
154
181
|
const fragmentHeadings = (_a = node.data) === null || _a === void 0 ? void 0 : _a.tableOfContents;
|
|
155
182
|
if (!(fragmentHeadings === null || fragmentHeadings === void 0 ? void 0 : fragmentHeadings.length))
|
|
@@ -165,18 +192,20 @@ export const remarkExtractTableOfContents = (mdxExtracts, pageMetadata) => {
|
|
|
165
192
|
};
|
|
166
193
|
register(fragmentHeadings);
|
|
167
194
|
for (const heading of fragmentHeadings) {
|
|
168
|
-
pushEntry(Object.assign(Object.assign({}, heading), { tabId: currentTabId, viewId: currentViewId, variationIds: currentVariationIds
|
|
195
|
+
pushEntry(Object.assign(Object.assign({}, heading), { tabId: currentTabId, viewId: currentViewId, variationIds: currentVariationIds, authRules: currentAuthRules || heading.authRules
|
|
196
|
+
? [...(currentAuthRules !== null && currentAuthRules !== void 0 ? currentAuthRules : []), ...((_b = heading.authRules) !== null && _b !== void 0 ? _b : [])]
|
|
197
|
+
: undefined }), heading.depth);
|
|
169
198
|
}
|
|
170
199
|
return;
|
|
171
200
|
}
|
|
172
201
|
const isValidHeading = node.type === 'heading' && HEADING_LEVELS.includes(node.depth);
|
|
173
|
-
const isValidMdxHeading = node.type === 'mdxJsxFlowElement' && HEADING_NAMES.includes((
|
|
202
|
+
const isValidMdxHeading = node.type === 'mdxJsxFlowElement' && HEADING_NAMES.includes((_c = node.name) !== null && _c !== void 0 ? _c : '');
|
|
174
203
|
const isTransformedHeading = node.type === 'mdxJsxFlowElement' && node.name === 'Heading';
|
|
175
204
|
const isValidUpdate = node.type === 'mdxJsxFlowElement' &&
|
|
176
205
|
node.name === 'Update' &&
|
|
177
206
|
node.attributes.some((attr) => 'name' in attr && attr.name === 'label');
|
|
178
207
|
const stepTitleSize = node.type === 'mdxJsxFlowElement' && node.name === 'Step'
|
|
179
|
-
? ((
|
|
208
|
+
? ((_d = getStringAttribute(node.attributes, 'titleSize')) !== null && _d !== void 0 ? _d : inheritedStepTitleSizeMap.get(node))
|
|
180
209
|
: undefined;
|
|
181
210
|
const hasNoAnchor = node.type === 'mdxJsxFlowElement' &&
|
|
182
211
|
node.attributes.some((attr) => 'name' in attr &&
|
|
@@ -185,7 +214,7 @@ export const remarkExtractTableOfContents = (mdxExtracts, pageMetadata) => {
|
|
|
185
214
|
attr.value === 'true' ||
|
|
186
215
|
(typeof attr.value === 'object' && attr.value.value === 'true')));
|
|
187
216
|
const stepTitle = node.type === 'mdxJsxFlowElement' && node.name === 'Step'
|
|
188
|
-
? getTitleMarkdownText(node, (
|
|
217
|
+
? getTitleMarkdownText(node, (_e = getStringAttribute(node.attributes, 'title')) !== null && _e !== void 0 ? _e : '')
|
|
189
218
|
: undefined;
|
|
190
219
|
const isValidStep = node.type === 'mdxJsxFlowElement' &&
|
|
191
220
|
node.name === 'Step' &&
|
|
@@ -194,7 +223,7 @@ export const remarkExtractTableOfContents = (mdxExtracts, pageMetadata) => {
|
|
|
194
223
|
(stepTitle === null || stepTitle === void 0 ? void 0 : stepTitle.trim()) !== '';
|
|
195
224
|
const hasIdAttribute = node.type === 'mdxJsxFlowElement' &&
|
|
196
225
|
node.attributes.some((attr) => 'name' in attr && attr.name === 'id');
|
|
197
|
-
const isAvoidedPageMode = AVOIDED_PAGE_MODES.includes((
|
|
226
|
+
const isAvoidedPageMode = AVOIDED_PAGE_MODES.includes((_f = pageMetadata === null || pageMetadata === void 0 ? void 0 : pageMetadata.mode) !== null && _f !== void 0 ? _f : '');
|
|
198
227
|
if (!isValidHeading &&
|
|
199
228
|
!isValidMdxHeading &&
|
|
200
229
|
!isTransformedHeading &&
|
|
@@ -212,7 +241,7 @@ export const remarkExtractTableOfContents = (mdxExtracts, pageMetadata) => {
|
|
|
212
241
|
}
|
|
213
242
|
else if ('name' in node && node.name === 'Step') {
|
|
214
243
|
const titleSizeToLevel = { h2: 2, h3: 3, h4: 4 };
|
|
215
|
-
level = (
|
|
244
|
+
level = (_g = titleSizeToLevel[stepTitleSize !== null && stepTitleSize !== void 0 ? stepTitleSize : '']) !== null && _g !== void 0 ? _g : 3;
|
|
216
245
|
// @ts-expect-error we're assigning to depth despite the node not containing depth in the type
|
|
217
246
|
node.depth = level;
|
|
218
247
|
}
|
|
@@ -225,7 +254,7 @@ export const remarkExtractTableOfContents = (mdxExtracts, pageMetadata) => {
|
|
|
225
254
|
level = levelAttr.value;
|
|
226
255
|
}
|
|
227
256
|
}
|
|
228
|
-
else if ('name' in node && ((
|
|
257
|
+
else if ('name' in node && ((_h = node.name) === null || _h === void 0 ? void 0 : _h[1])) {
|
|
229
258
|
const num = Number(node.name[1]);
|
|
230
259
|
level = !isNaN(num) ? num : undefined;
|
|
231
260
|
if (level !== undefined) {
|
|
@@ -300,6 +329,7 @@ export const remarkExtractTableOfContents = (mdxExtracts, pageMetadata) => {
|
|
|
300
329
|
tabId: currentTabId,
|
|
301
330
|
viewId: currentViewId,
|
|
302
331
|
variationIds: currentVariationIds,
|
|
332
|
+
authRules: currentAuthRules,
|
|
303
333
|
}, level);
|
|
304
334
|
});
|
|
305
335
|
if (mdxExtracts) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { Root } from 'mdast';
|
|
2
2
|
export declare const remarkMdxRemoveUnknownJsx: ({ allowlist }?: {
|
|
3
3
|
allowlist?: string[];
|
|
4
|
-
}) => (tree: Root) => Root | import("mdast").
|
|
4
|
+
}) => (tree: Root) => Root | import("mdast-util-mdx-jsx").MdxJsxFlowElement | import("mdast-util-mdx-jsx").MdxJsxTextElement | import("mdast").Link | import("mdast").Delete | import("mdast").Code | import("mdast").Blockquote | import("mdast").Break | import("mdast").Definition | import("mdast").Emphasis | import("mdast").FootnoteDefinition | import("mdast").FootnoteReference | import("mdast").Heading | import("mdast").Html | import("mdast").Image | import("mdast").ImageReference | import("mdast").InlineCode | import("mdast").LinkReference | import("mdast").List | import("mdast").ListItem | import("mdast").Paragraph | import("mdast").Strong | import("mdast").Table | import("mdast").TableCell | import("mdast").TableRow | import("mdast").Text | import("mdast").ThematicBreak | import("mdast").Yaml | import("mdast-util-math").InlineMath | import("mdast-util-math").Math | import("mdast-util-mdx-expression").MdxTextExpression | import("mdast-util-mdx-expression").MdxFlowExpression | import("mdast-util-mdxjs-esm").MdxjsEsm;
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { visit } from 'unist-util-visit';
|
|
2
|
-
import { isVisibilityElement, resolveVisibilityFor } from './remarkVisibilityForMarkdown.js';
|
|
2
|
+
import { VISIBILITY_FOR_EXPECTED, isVisibilityElement, resolveVisibilityFor, } from './remarkVisibilityForMarkdown.js';
|
|
3
3
|
export const remarkValidateVisibility = () => (tree) => {
|
|
4
4
|
visit(tree, (node) => {
|
|
5
5
|
if (!isVisibilityElement(node))
|
|
6
6
|
return;
|
|
7
7
|
const resolution = resolveVisibilityFor(node);
|
|
8
8
|
if (resolution.kind === 'invalid') {
|
|
9
|
-
console.warn(`<Visibility for="${resolution.raw}"> has an unknown audience — expected
|
|
9
|
+
console.warn(`<Visibility for="${resolution.raw}"> has an unknown audience — expected ${VISIBILITY_FOR_EXPECTED}. The content will be hidden from humans.`);
|
|
10
10
|
}
|
|
11
11
|
if (resolution.kind === 'missing') {
|
|
12
|
-
console.warn(
|
|
12
|
+
console.warn(`<Visibility> is missing its "for" audience — expected ${VISIBILITY_FOR_EXPECTED}. The content will be hidden from humans.`);
|
|
13
13
|
}
|
|
14
14
|
});
|
|
15
15
|
};
|
|
@@ -5,9 +5,22 @@ export declare function isVisibilityElement(node: {
|
|
|
5
5
|
type: string;
|
|
6
6
|
name?: string | null;
|
|
7
7
|
}): node is MdxJsxElement;
|
|
8
|
+
export declare const VISIBILITY_AUDIENCES: readonly ["humans", "agents", "signed-in", "signed-out"];
|
|
9
|
+
export type VisibilityAudience = (typeof VISIBILITY_AUDIENCES)[number];
|
|
10
|
+
export declare const VISIBILITY_FOR_EXPECTED = "\"humans\", \"agents\", \"signed-in\", \"signed-out\", or { groups: [...] }";
|
|
11
|
+
export type VisibilityAuthRule = 'signed-in' | 'signed-out' | {
|
|
12
|
+
groups: string[];
|
|
13
|
+
};
|
|
14
|
+
export type VisibilityViewer = {
|
|
15
|
+
signedIn: boolean;
|
|
16
|
+
groups: readonly string[];
|
|
17
|
+
};
|
|
8
18
|
export type VisibilityResolution = {
|
|
9
19
|
kind: 'audience';
|
|
10
|
-
audience:
|
|
20
|
+
audience: VisibilityAudience;
|
|
21
|
+
} | {
|
|
22
|
+
kind: 'groups';
|
|
23
|
+
groups: string[];
|
|
11
24
|
} | {
|
|
12
25
|
kind: 'invalid';
|
|
13
26
|
raw: string;
|
|
@@ -16,6 +29,10 @@ export type VisibilityResolution = {
|
|
|
16
29
|
} | {
|
|
17
30
|
kind: 'missing';
|
|
18
31
|
};
|
|
32
|
+
export declare function isVisibilityAudience(value: unknown): value is VisibilityAudience;
|
|
19
33
|
export declare function resolveVisibilityFor(node: MdxJsxElement): VisibilityResolution;
|
|
20
34
|
export declare function isHiddenFromHumans(resolution: VisibilityResolution): boolean;
|
|
35
|
+
export declare function isHiddenFromAgents(resolution: VisibilityResolution): boolean;
|
|
36
|
+
export declare function toVisibilityAuthRule(resolution: VisibilityResolution): VisibilityAuthRule | undefined;
|
|
37
|
+
export declare function matchesVisibilityAuthRule(rule: VisibilityAuthRule, viewer: VisibilityViewer): boolean;
|
|
21
38
|
export declare const remarkVisibilityForMarkdown: () => (tree: Root) => void;
|
|
@@ -5,17 +5,88 @@ export function isVisibilityElement(node) {
|
|
|
5
5
|
function isMdxJsxElement(node) {
|
|
6
6
|
return node.type === 'mdxJsxFlowElement' || node.type === 'mdxJsxTextElement';
|
|
7
7
|
}
|
|
8
|
+
export const VISIBILITY_AUDIENCES = ['humans', 'agents', 'signed-in', 'signed-out'];
|
|
9
|
+
export const VISIBILITY_FOR_EXPECTED = '"humans", "agents", "signed-in", "signed-out", or { groups: [...] }';
|
|
10
|
+
export function isVisibilityAudience(value) {
|
|
11
|
+
return VISIBILITY_AUDIENCES.some((audience) => audience === value);
|
|
12
|
+
}
|
|
13
|
+
function expressionOf(value) {
|
|
14
|
+
var _a, _b;
|
|
15
|
+
const statement = (_b = (_a = value.data) === null || _a === void 0 ? void 0 : _a.estree) === null || _b === void 0 ? void 0 : _b.body[0];
|
|
16
|
+
return (statement === null || statement === void 0 ? void 0 : statement.type) === 'ExpressionStatement' ? statement.expression : undefined;
|
|
17
|
+
}
|
|
18
|
+
function foldString(node) {
|
|
19
|
+
var _a, _b, _c;
|
|
20
|
+
switch (node === null || node === void 0 ? void 0 : node.type) {
|
|
21
|
+
case 'Literal':
|
|
22
|
+
return typeof node.value === 'string' ? node.value : undefined;
|
|
23
|
+
case 'TemplateLiteral': {
|
|
24
|
+
let out = (_b = (_a = node.quasis[0]) === null || _a === void 0 ? void 0 : _a.value.cooked) !== null && _b !== void 0 ? _b : undefined;
|
|
25
|
+
for (const [index, expression] of node.expressions.entries()) {
|
|
26
|
+
const folded = foldString(expression);
|
|
27
|
+
const next = (_c = node.quasis[index + 1]) === null || _c === void 0 ? void 0 : _c.value.cooked;
|
|
28
|
+
if (out === undefined || folded === undefined || next == null)
|
|
29
|
+
return undefined;
|
|
30
|
+
out += folded + next;
|
|
31
|
+
}
|
|
32
|
+
return out;
|
|
33
|
+
}
|
|
34
|
+
case 'BinaryExpression': {
|
|
35
|
+
if (node.operator !== '+')
|
|
36
|
+
return undefined;
|
|
37
|
+
const left = foldString(node.left);
|
|
38
|
+
const right = foldString(node.right);
|
|
39
|
+
return left === undefined || right === undefined ? undefined : left + right;
|
|
40
|
+
}
|
|
41
|
+
default:
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function resolveGroups(value) {
|
|
46
|
+
const expression = expressionOf(value);
|
|
47
|
+
if ((expression === null || expression === void 0 ? void 0 : expression.type) !== 'ObjectExpression' || expression.properties.length !== 1)
|
|
48
|
+
return undefined;
|
|
49
|
+
const [property] = expression.properties;
|
|
50
|
+
if ((property === null || property === void 0 ? void 0 : property.type) !== 'Property' || property.computed)
|
|
51
|
+
return undefined;
|
|
52
|
+
const key = property.key.type === 'Identifier' ? property.key.name : undefined;
|
|
53
|
+
const literalKey = property.key.type === 'Literal' ? property.key.value : undefined;
|
|
54
|
+
if ((key !== null && key !== void 0 ? key : literalKey) !== 'groups' || property.value.type !== 'ArrayExpression')
|
|
55
|
+
return undefined;
|
|
56
|
+
const groups = property.value.elements.map((element) => { var _a, _b; return (_b = (_a = foldString(element)) === null || _a === void 0 ? void 0 : _a.trim()) !== null && _b !== void 0 ? _b : ''; });
|
|
57
|
+
return groups.length > 0 && groups.every(Boolean) ? [...new Set(groups)] : undefined;
|
|
58
|
+
}
|
|
59
|
+
function mayOverrideFor(attr) {
|
|
60
|
+
if (attr.type !== 'mdxJsxExpressionAttribute')
|
|
61
|
+
return false;
|
|
62
|
+
const expression = expressionOf(attr);
|
|
63
|
+
const spread = (expression === null || expression === void 0 ? void 0 : expression.type) === 'ObjectExpression' && expression.properties.length === 1
|
|
64
|
+
? expression.properties[0]
|
|
65
|
+
: undefined;
|
|
66
|
+
if ((spread === null || spread === void 0 ? void 0 : spread.type) !== 'SpreadElement' || spread.argument.type !== 'ObjectExpression')
|
|
67
|
+
return true;
|
|
68
|
+
return spread.argument.properties.some((property) => {
|
|
69
|
+
if (property.type !== 'Property' || property.computed)
|
|
70
|
+
return true;
|
|
71
|
+
const key = property.key.type === 'Identifier' ? property.key.name : undefined;
|
|
72
|
+
const literalKey = property.key.type === 'Literal' ? property.key.value : undefined;
|
|
73
|
+
return (key !== null && key !== void 0 ? key : literalKey) === 'for';
|
|
74
|
+
});
|
|
75
|
+
}
|
|
8
76
|
export function resolveVisibilityFor(node) {
|
|
9
|
-
var _a;
|
|
77
|
+
var _a, _b;
|
|
10
78
|
let invalidRaw;
|
|
11
79
|
let sawDynamic = false;
|
|
12
80
|
let sawAttribute = false;
|
|
81
|
+
const lastFor = node.attributes.findLastIndex((attr) => attr.type === 'mdxJsxAttribute' && attr.name === 'for');
|
|
82
|
+
if (node.attributes.slice(lastFor + 1).some(mayOverrideFor))
|
|
83
|
+
return { kind: 'dynamic' };
|
|
13
84
|
for (const attr of node.attributes) {
|
|
14
85
|
if (attr.type !== 'mdxJsxAttribute' || attr.name !== 'for')
|
|
15
86
|
continue;
|
|
16
87
|
sawAttribute = true;
|
|
17
88
|
if (typeof attr.value === 'string') {
|
|
18
|
-
if (attr.value
|
|
89
|
+
if (isVisibilityAudience(attr.value)) {
|
|
19
90
|
return { kind: 'audience', audience: attr.value };
|
|
20
91
|
}
|
|
21
92
|
invalidRaw !== null && invalidRaw !== void 0 ? invalidRaw : (invalidRaw = attr.value);
|
|
@@ -24,18 +95,32 @@ export function resolveVisibilityFor(node) {
|
|
|
24
95
|
if (attr.value && typeof attr.value === 'object') {
|
|
25
96
|
if ('value' in attr.value && typeof attr.value.value === 'string') {
|
|
26
97
|
const raw = attr.value.value.trim();
|
|
98
|
+
const folded = foldString(expressionOf(attr.value));
|
|
99
|
+
if (folded !== undefined) {
|
|
100
|
+
if (isVisibilityAudience(folded))
|
|
101
|
+
return { kind: 'audience', audience: folded };
|
|
102
|
+
invalidRaw !== null && invalidRaw !== void 0 ? invalidRaw : (invalidRaw = folded);
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
27
105
|
const quoted = raw.match(/^(["'`])((?:\\.|(?!\1)[^\\])*)\1$/);
|
|
28
106
|
if (quoted) {
|
|
29
107
|
const inner = (_a = quoted[2]) !== null && _a !== void 0 ? _a : '';
|
|
30
108
|
const isTemplateWithInterpolation = quoted[1] === '`' && inner.includes('${');
|
|
31
109
|
if (!isTemplateWithInterpolation) {
|
|
32
|
-
if (inner
|
|
110
|
+
if (isVisibilityAudience(inner)) {
|
|
33
111
|
return { kind: 'audience', audience: inner };
|
|
34
112
|
}
|
|
35
113
|
invalidRaw !== null && invalidRaw !== void 0 ? invalidRaw : (invalidRaw = inner);
|
|
36
114
|
continue;
|
|
37
115
|
}
|
|
38
116
|
}
|
|
117
|
+
const groups = resolveGroups(attr.value);
|
|
118
|
+
if (groups)
|
|
119
|
+
return { kind: 'groups', groups };
|
|
120
|
+
if (((_b = expressionOf(attr.value)) === null || _b === void 0 ? void 0 : _b.type) === 'ObjectExpression' || raw.startsWith('{')) {
|
|
121
|
+
invalidRaw !== null && invalidRaw !== void 0 ? invalidRaw : (invalidRaw = raw);
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
39
124
|
}
|
|
40
125
|
sawDynamic = true;
|
|
41
126
|
}
|
|
@@ -52,6 +137,8 @@ export function isHiddenFromHumans(resolution) {
|
|
|
52
137
|
switch (resolution.kind) {
|
|
53
138
|
case 'audience':
|
|
54
139
|
return resolution.audience === 'agents';
|
|
140
|
+
case 'groups':
|
|
141
|
+
return false;
|
|
55
142
|
case 'invalid':
|
|
56
143
|
case 'missing':
|
|
57
144
|
return true;
|
|
@@ -59,6 +146,34 @@ export function isHiddenFromHumans(resolution) {
|
|
|
59
146
|
return false;
|
|
60
147
|
}
|
|
61
148
|
}
|
|
149
|
+
export function isHiddenFromAgents(resolution) {
|
|
150
|
+
switch (resolution.kind) {
|
|
151
|
+
case 'audience':
|
|
152
|
+
return resolution.audience === 'humans' || resolution.audience === 'signed-in';
|
|
153
|
+
case 'groups':
|
|
154
|
+
case 'invalid':
|
|
155
|
+
case 'dynamic':
|
|
156
|
+
case 'missing':
|
|
157
|
+
return true;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
export function toVisibilityAuthRule(resolution) {
|
|
161
|
+
if (resolution.kind === 'groups')
|
|
162
|
+
return { groups: resolution.groups };
|
|
163
|
+
if (resolution.kind !== 'audience')
|
|
164
|
+
return undefined;
|
|
165
|
+
if (resolution.audience === 'signed-in' || resolution.audience === 'signed-out') {
|
|
166
|
+
return resolution.audience;
|
|
167
|
+
}
|
|
168
|
+
return undefined;
|
|
169
|
+
}
|
|
170
|
+
export function matchesVisibilityAuthRule(rule, viewer) {
|
|
171
|
+
if (rule === 'signed-in')
|
|
172
|
+
return viewer.signedIn;
|
|
173
|
+
if (rule === 'signed-out')
|
|
174
|
+
return !viewer.signedIn;
|
|
175
|
+
return viewer.signedIn && rule.groups.some((group) => viewer.groups.includes(group));
|
|
176
|
+
}
|
|
62
177
|
// `export * from` is intentionally ignored: it exposes no statically-knowable
|
|
63
178
|
// names and creates no page-local JSX bindings in MDX, so there is nothing to
|
|
64
179
|
// collect.
|
|
@@ -163,9 +278,7 @@ function collectJsxUsage(nodes, insideHumans, hiddenNames, visibleNames) {
|
|
|
163
278
|
if (isMdxJsxElement(node)) {
|
|
164
279
|
if (node.name === 'Visibility') {
|
|
165
280
|
const resolution = resolveVisibilityFor(node);
|
|
166
|
-
|
|
167
|
-
(resolution.kind === 'audience' && resolution.audience === 'humans');
|
|
168
|
-
if (isHidden)
|
|
281
|
+
if (isHiddenFromAgents(resolution))
|
|
169
282
|
childInsideHumans = true;
|
|
170
283
|
}
|
|
171
284
|
else {
|
|
@@ -206,15 +319,14 @@ function transformNode(node, esmToStrip) {
|
|
|
206
319
|
}
|
|
207
320
|
if (isMdxJsxElement(node) && node.name === 'Visibility') {
|
|
208
321
|
const resolution = resolveVisibilityFor(node);
|
|
209
|
-
if (resolution.kind === '
|
|
322
|
+
if (resolution.kind === 'invalid') {
|
|
323
|
+
console.warn(`<Visibility for="${resolution.raw}"> has an unknown audience — expected ${VISIBILITY_FOR_EXPECTED}. The content was removed from the markdown output.`);
|
|
210
324
|
return [];
|
|
211
325
|
}
|
|
212
|
-
if (resolution
|
|
213
|
-
return transformChildren(node.children, esmToStrip);
|
|
214
|
-
}
|
|
215
|
-
if (resolution.kind === 'invalid') {
|
|
216
|
-
console.warn(`<Visibility for="${resolution.raw}"> has an unknown audience — expected "humans" or "agents". The content was removed from the markdown output.`);
|
|
326
|
+
if (isHiddenFromAgents(resolution))
|
|
217
327
|
return [];
|
|
328
|
+
if (resolution.kind === 'audience') {
|
|
329
|
+
return transformChildren(node.children, esmToStrip);
|
|
218
330
|
}
|
|
219
331
|
}
|
|
220
332
|
if ('children' in node && Array.isArray(node.children)) {
|
|
@@ -1,6 +1,12 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as v from 'valibot';
|
|
2
2
|
export const WILDCARD_GROUP = '*';
|
|
3
|
-
|
|
3
|
+
const groupNameSchema = v.pipe(v.string(), v.minLength(1));
|
|
4
|
+
const groupRuleSchema = v.strictObject({
|
|
5
|
+
includes: v.optional(v.pipe(v.array(groupNameSchema), v.minLength(1))),
|
|
6
|
+
excludes: v.optional(v.pipe(v.array(groupNameSchema), v.check((excludes) => !excludes.includes(WILDCARD_GROUP)))),
|
|
7
|
+
});
|
|
8
|
+
const pageGroupsSchema = v.union([v.array(groupNameSchema), v.array(groupRuleSchema)]);
|
|
9
|
+
export const isPageGroups = (value) => v.is(pageGroupsSchema, value);
|
|
4
10
|
const isStringArray = (groups) => groups.every((entry) => typeof entry === 'string');
|
|
5
11
|
const DENY_ALL = { includes: [], excludes: [] };
|
|
6
12
|
export function normalizeGroups(groups) {
|