@mintlify/common 1.0.1279 → 1.0.1280

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.
@@ -23,6 +23,7 @@ export interface PreprocessCustomHeadingIdsOptions {
23
23
  * Without this the `{#id}` would reach the expression parser as a JSX expression and fail.
24
24
  */
25
25
  export declare function preprocessCustomHeadingIds(content: string, options?: PreprocessCustomHeadingIdsOptions): string;
26
+ export declare function customHeadingIdSourceLines(content: string, options?: PreprocessCustomHeadingIdsOptions): number[];
26
27
  export declare function parseOpeningFence(stripped: string): {
27
28
  char: string;
28
29
  count: number;
@@ -39,20 +39,30 @@ function normalizeCustomId(raw) {
39
39
  * Without this the `{#id}` would reach the expression parser as a JSX expression and fail.
40
40
  */
41
41
  export function preprocessCustomHeadingIds(content, options) {
42
+ return rewriteCustomHeadingIds(content, options).content;
43
+ }
44
+ export function customHeadingIdSourceLines(content, options) {
45
+ return rewriteCustomHeadingIds(content, options).sourceLines;
46
+ }
47
+ function rewriteCustomHeadingIds(content, options) {
42
48
  var _a, _b, _c, _d, _e;
43
49
  const lines = content.split('\n');
44
50
  const result = [];
51
+ const sourceLines = [];
52
+ let sourceLine = 0;
45
53
  let fenceChar;
46
54
  let fenceCount = 0;
47
55
  let mdxDepth = 0;
48
56
  let inComment = false;
49
57
  for (const line of lines) {
58
+ sourceLine += 1;
50
59
  const stripped = line.trimStart();
51
60
  if (fenceChar !== undefined) {
52
61
  if (isClosingFence(stripped, fenceChar, fenceCount)) {
53
62
  fenceChar = undefined;
54
63
  }
55
64
  result.push(line);
65
+ sourceLines.push(sourceLine);
56
66
  continue;
57
67
  }
58
68
  const fence = !inComment && parseOpeningFence(stripped);
@@ -60,6 +70,7 @@ export function preprocessCustomHeadingIds(content, options) {
60
70
  fenceChar = fence.char;
61
71
  fenceCount = fence.count;
62
72
  result.push(line);
73
+ sourceLines.push(sourceLine);
63
74
  continue;
64
75
  }
65
76
  const { visible, inComment: endsInComment } = scanComments(line, inComment);
@@ -74,14 +85,16 @@ export function preprocessCustomHeadingIds(content, options) {
74
85
  ? sanitizeHtmlAttr(heading[4])
75
86
  : normalizeCustomId(heading[4]);
76
87
  result.push(`${indent}<h${level} id="${sanitizedId}">`, `${indent}${heading[3]}`, `${indent}</h${level}>`);
88
+ sourceLines.push(sourceLine, sourceLine, sourceLine);
77
89
  continue;
78
90
  }
79
91
  mdxDepth = Math.max(0, mdxDepth +
80
92
  ((_c = (_b = visible.match(MDX_OPEN_RE)) === null || _b === void 0 ? void 0 : _b.length) !== null && _c !== void 0 ? _c : 0) -
81
93
  ((_e = (_d = visible.match(MDX_CLOSE_RE)) === null || _d === void 0 ? void 0 : _d.length) !== null && _e !== void 0 ? _e : 0));
82
94
  result.push(line);
95
+ sourceLines.push(sourceLine);
83
96
  }
84
- return result.join('\n');
97
+ return { content: result.join('\n'), sourceLines };
85
98
  }
86
99
  function scanComments(line, inComment) {
87
100
  const masked = line.replace(COMMENT_MASK_RE, (span) => ' '.repeat(span.length));
@@ -1,5 +1,5 @@
1
1
  import { describe, expect, it } from 'vitest';
2
- import { preprocessCustomHeadingIds } from './preprocessCustomHeadingIds.js';
2
+ import { customHeadingIdSourceLines, preprocessCustomHeadingIds, } from './preprocessCustomHeadingIds.js';
3
3
  describe('preprocessCustomHeadingIds', () => {
4
4
  it('converts top-level headings with custom ids', () => {
5
5
  expect(preprocessCustomHeadingIds('## Heading {#custom-id}')).toBe('<h2 id="custom-id">\nHeading\n</h2>');
@@ -165,3 +165,18 @@ x = 1
165
165
  expect(preprocessCustomHeadingIds(' ## Heading {#my_id}', { preserveOriginal: true })).toBe(' <h2 id="my_id">\n Heading\n </h2>');
166
166
  });
167
167
  });
168
+ describe('customHeadingIdSourceLines', () => {
169
+ it('maps each output line to the source line it came from', () => {
170
+ const content = [
171
+ '# Title {#title}',
172
+ 'Body',
173
+ '```',
174
+ '## Code {#code}',
175
+ '```',
176
+ '## End {#end}',
177
+ ].join('\n');
178
+ const sourceLines = customHeadingIdSourceLines(content);
179
+ expect(sourceLines).toEqual([1, 1, 1, 2, 3, 4, 5, 6, 6, 6]);
180
+ expect(sourceLines).toHaveLength(preprocessCustomHeadingIds(content).split('\n').length);
181
+ });
182
+ });
@@ -1,4 +1,5 @@
1
1
  import type { RootContent } from 'mdast';
2
2
  import type { UpdateMDXComponent } from './index.js';
3
- export declare const getDateForNode: (node: RootContent, lineBlame: Record<number, string>) => string;
3
+ export declare const newestBlameDate: (lineBlame: Record<number, string>) => string | undefined;
4
+ export declare const getDateForNode: (node: RootContent, lineBlame: Record<number, string>, fallbackDate: string) => string;
4
5
  export declare const getMostRepresentativeDate: (updateComponent: UpdateMDXComponent, lineBlame: Record<number, string>, defaultDate: string) => string;
package/dist/rss/dates.js CHANGED
@@ -1,25 +1,29 @@
1
- export const getDateForNode = (node, lineBlame) => {
2
- if (!node.position) {
3
- return new Date().toISOString();
4
- }
5
- const startLine = node.position.start.line;
6
- const blameDate = lineBlame[startLine];
7
- if (blameDate) {
8
- const parsedDate = new Date(blameDate);
9
- if (!isNaN(parsedDate.getTime())) {
10
- return parsedDate.toISOString();
11
- }
1
+ const blameDateForNode = (node, lineBlame) => {
2
+ if (!node.position)
3
+ return undefined;
4
+ const blameDate = lineBlame[node.position.start.line];
5
+ if (!blameDate)
6
+ return undefined;
7
+ const parsedDate = new Date(blameDate);
8
+ return isNaN(parsedDate.getTime()) ? undefined : parsedDate.toISOString();
9
+ };
10
+ export const newestBlameDate = (lineBlame) => {
11
+ let newest;
12
+ for (const blameDate of Object.values(lineBlame)) {
13
+ const time = new Date(blameDate).getTime();
14
+ if (!isNaN(time) && (newest === undefined || time > newest))
15
+ newest = time;
12
16
  }
13
- return new Date().toISOString();
17
+ return newest === undefined ? undefined : new Date(newest).toISOString();
14
18
  };
19
+ export const getDateForNode = (node, lineBlame, fallbackDate) => { var _a; return (_a = blameDateForNode(node, lineBlame)) !== null && _a !== void 0 ? _a : fallbackDate; };
15
20
  export const getMostRepresentativeDate = (updateComponent, lineBlame, defaultDate) => {
16
21
  const dates = [];
17
22
  const collectDates = (nodes) => {
18
23
  for (const node of nodes) {
19
- if (node.type !== 'heading' && node.position) {
20
- const nodeDate = getDateForNode(node, lineBlame);
24
+ const nodeDate = node.type === 'heading' ? undefined : blameDateForNode(node, lineBlame);
25
+ if (nodeDate !== undefined)
21
26
  dates.push(nodeDate);
22
- }
23
27
  if ('children' in node && Array.isArray(node.children) && node.children.length > 0) {
24
28
  collectDates(node.children);
25
29
  }
@@ -8,9 +8,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  });
9
9
  };
10
10
  import { remarkUserMentions } from '../mdx/plugins/remark/remarkUserMentions.js';
11
+ import { customHeadingIdSourceLines } from '../mdx/preprocessCustomHeadingIds.js';
12
+ import { preprocessMdxFragmentCode } from '../mdx/preprocessMdxFragmentCode.js';
11
13
  import { getAST } from '../mdx/remark.js';
12
14
  import { UPDATE_MAX } from './constants.js';
13
- import { getDateForNode, getMostRepresentativeDate } from './dates.js';
15
+ import { getDateForNode, getMostRepresentativeDate, newestBlameDate } from './dates.js';
14
16
  import { enhanceSnippetsWithImportNames } from './enhanceSnippetsWithImportNames.js';
15
17
  import { isUpdate } from './index.js';
16
18
  import { processUpdateNode } from './processUpdateNode.js';
@@ -38,6 +40,16 @@ export const getV4FeedUpdates = (rssFile) => __awaiter(void 0, void 0, void 0, f
38
40
  catch (error) {
39
41
  return [];
40
42
  }
43
+ const astLineBlame = {};
44
+ customHeadingIdSourceLines(preprocessMdxFragmentCode(content)).forEach((sourceLine, index) => {
45
+ const blameDate = lineBlame[sourceLine];
46
+ if (blameDate !== undefined)
47
+ astLineBlame[index + 1] = blameDate;
48
+ });
49
+ const fallbackDate = newestBlameDate(lineBlame);
50
+ if (fallbackDate === undefined) {
51
+ return [];
52
+ }
41
53
  if (snippets && snippets.length > 0) {
42
54
  try {
43
55
  const enhancedSnippets = yield enhanceSnippetsWithImportNames(ast, snippets);
@@ -58,8 +70,8 @@ export const getV4FeedUpdates = (rssFile) => __awaiter(void 0, void 0, void 0, f
58
70
  }
59
71
  const allUpdates = [];
60
72
  for (const updateComponent of updateComponents) {
61
- const componentDate = getDateForNode(updateComponent, lineBlame);
62
- const representativeDate = getMostRepresentativeDate(updateComponent, lineBlame, componentDate);
73
+ const componentDate = getDateForNode(updateComponent, astLineBlame, fallbackDate);
74
+ const representativeDate = getMostRepresentativeDate(updateComponent, astLineBlame, componentDate);
63
75
  const updates = processUpdateNode({
64
76
  updateNode: updateComponent,
65
77
  date: representativeDate,