@readme/markdown 14.11.1 → 14.11.3

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/main.node.js CHANGED
@@ -25110,6 +25110,34 @@ function useScrollHighlight(navRef) {
25110
25110
  return scrollParent.scrollHeight > scrollParent.clientHeight
25111
25111
  && scrollParent.scrollTop + scrollParent.clientHeight >= scrollParent.scrollHeight - SCROLL_BOTTOM_TOLERANCE;
25112
25112
  };
25113
+ /**
25114
+ * Keeps the active link visible within the TOC's own scroll container —
25115
+ * the same result as `scrollIntoView({ block: 'nearest' })`, but scoped to
25116
+ * a single scroller. `scrollIntoView` adjusts *every* scrollable ancestor,
25117
+ * and starting a scroll on the page's content scroller cancels any
25118
+ * in-flight smooth scroll there — e.g. the hub's scroll-to-top reset when
25119
+ * navigating between pages (CX-3667).
25120
+ */
25121
+ const scrollTOCLinkIntoView = (link) => {
25122
+ const tocScroller = TableOfContents_getScrollParent(link);
25123
+ // Without a TOC-local scroll area, the link's nearest scrollable
25124
+ // ancestor is the window (`getScrollParent`'s fallback) or the scroller
25125
+ // holding the page content — never auto-scroll those just to reveal a
25126
+ // TOC link.
25127
+ if (!(tocScroller instanceof HTMLElement) || tocScroller.contains(headings[0]))
25128
+ return;
25129
+ const scrollerRect = tocScroller.getBoundingClientRect();
25130
+ const linkRect = link.getBoundingClientRect();
25131
+ if (linkRect.top < scrollerRect.top) {
25132
+ tocScroller.scrollTo?.({ top: tocScroller.scrollTop + (linkRect.top - scrollerRect.top), behavior: 'smooth' });
25133
+ }
25134
+ else if (linkRect.bottom > scrollerRect.bottom) {
25135
+ tocScroller.scrollTo?.({
25136
+ top: tocScroller.scrollTop + (linkRect.bottom - scrollerRect.bottom),
25137
+ behavior: 'smooth',
25138
+ });
25139
+ }
25140
+ };
25113
25141
  const activate = (id) => {
25114
25142
  if (id === activeId)
25115
25143
  return;
@@ -25126,7 +25154,7 @@ function useScrollHighlight(navRef) {
25126
25154
  const linkRect = link.getBoundingClientRect();
25127
25155
  nav.style.setProperty('--ToC-border-active-height', `${linkRect.height}px`);
25128
25156
  nav.style.setProperty('--ToC-border-active-top', `${linkRect.top - navRect.top}px`);
25129
- link.scrollIntoView?.({ block: 'nearest', behavior: 'smooth' });
25157
+ scrollTOCLinkIntoView(link);
25130
25158
  }
25131
25159
  }
25132
25160
  };
@@ -95991,6 +96019,32 @@ const applyInserts = (html, inserts) => {
95991
96019
  return { value: out + html.slice(cursor), inserts: sorted };
95992
96020
  };
95993
96021
 
96022
+ ;// ./processor/transform/mdxish/tables/escape-stray-less-than.ts
96023
+
96024
+
96025
+ // A `<` only starts a JSX/HTML construct when followed by a tag-name start
96026
+ // (letter, `_`, `$`), a closer `/`, a fragment `>`, or a comment/declaration
96027
+ // `!`. Anything else (whitespace, EOL, a digit, …) is a literal `<` that acorn
96028
+ // rejects with "before name, expected a character that can start a name".
96029
+ const STRAY_LESS_THAN_RE = /<(?![a-zA-Z_$/>!])/g;
96030
+ /**
96031
+ * Escapes stray `<` characters that don't begin a valid tag so the strict mdxjs
96032
+ * parse treats them as literal text instead of throwing (`word <`, `a <1>`).
96033
+ *
96034
+ * Runs against the masked source so `<` inside code spans, legacy `<<var>>`
96035
+ * syntax, or already-escaped `\<` are left untouched.
96036
+ */
96037
+ const escapeStrayLessThan = (html) => {
96038
+ const masked = maskNonTagRegions(html);
96039
+ const inserts = [];
96040
+ STRAY_LESS_THAN_RE.lastIndex = 0;
96041
+ let match;
96042
+ while ((match = STRAY_LESS_THAN_RE.exec(masked)) !== null) {
96043
+ inserts.push({ offset: match.index, text: '\\' });
96044
+ }
96045
+ return applyInserts(html, inserts);
96046
+ };
96047
+
95994
96048
  ;// ./processor/transform/mdxish/tables/normalize-tag-spacing.ts
95995
96049
 
95996
96050
 
@@ -96490,6 +96544,7 @@ const repairUnclosedTags = (html) => {
96490
96544
 
96491
96545
 
96492
96546
 
96547
+
96493
96548
 
96494
96549
 
96495
96550
  const isTableCell = (node) => isMDXElement(node) && ['th', 'td'].includes(node.name);
@@ -96776,11 +96831,14 @@ const mdxishTables = () => tree => {
96776
96831
  // - normalizeTagSpacing: a line mixing text and an opening tag
96777
96832
  // (e.g. `text <div> \n <div> text`)
96778
96833
  // - repairExpressionEscapes: backslash escapes inside a `{…}` expression
96834
+ // - escapeStrayLessThan: a `<` that doesn't begin a valid tag
96835
+ // (e.g. `word <`, `a <1>`)
96779
96836
  // These repairs are created after seeing real customer content that has failed to parse
96780
96837
  const repairs = [
96781
96838
  repairUnclosedTags,
96782
96839
  normalizeTagSpacing,
96783
96840
  repairExpressionEscapes,
96841
+ escapeStrayLessThan,
96784
96842
  ];
96785
96843
  // Stops at the first repair that yields a parseable tree
96786
96844
  repairs.some(repair => {
@@ -118939,6 +118997,21 @@ function isActualHtmlTag(tagName, originalExcerpt) {
118939
118997
  return true;
118940
118998
  return false;
118941
118999
  }
119000
+ /**
119001
+ * Re-parsing a component's text child treats it as a standalone document, so
119002
+ * content that happens to start with the literal word `export`/`import`
119003
+ * (e.g. link text like "export Lorem Ipsum") sits at true column 1 and
119004
+ * gets mistaken for an MDX ESM statement, which then fails to parse as JS.
119005
+ * Fall back to `undefined` rather than letting one such child crash the page.
119006
+ */
119007
+ function tryProcessMarkdown(processMarkdown, content) {
119008
+ try {
119009
+ return processMarkdown(content);
119010
+ }
119011
+ catch {
119012
+ return undefined;
119013
+ }
119014
+ }
118942
119015
  /** Parse and replace text children with processed markdown */
118943
119016
  function parseTextChildren(node, processMarkdown, components) {
118944
119017
  if (!node.children?.length)
@@ -118953,7 +119026,9 @@ function parseTextChildren(node, processMarkdown, components) {
118953
119026
  node.properties = { ...node.properties, children: child.value };
118954
119027
  return [];
118955
119028
  }
118956
- const hast = processMarkdown(child.value.trim());
119029
+ const hast = tryProcessMarkdown(processMarkdown, child.value.trim());
119030
+ if (!hast)
119031
+ return [child];
118957
119032
  const children = (hast.children ?? []).filter(isElementContentNode);
118958
119033
  // For inline components, preserve plain text instead of wrapping in <p>
118959
119034
  if (INLINE_COMPONENT_TAGS_LOWER.has(node.tagName.toLowerCase()) && isSingleParagraphTextNode(children)) {
@@ -119027,8 +119102,9 @@ const rehypeMdxishComponents = ({ components, processMarkdown }) => {
119027
119102
  // rehypeRaw strips children from <img> (void element), so we must
119028
119103
  // re-process the caption here, after rehypeRaw.
119029
119104
  if (node.tagName === 'img' && typeof node.properties?.caption === 'string' && !node.children?.length) {
119030
- const captionHast = processMarkdown(node.properties.caption);
119031
- node.children = (captionHast.children ?? []).filter(isElementContentNode);
119105
+ const caption = node.properties.caption;
119106
+ const captionHast = tryProcessMarkdown(processMarkdown, caption);
119107
+ node.children = captionHast ? (captionHast.children ?? []).filter(isElementContentNode) : [{ type: 'text', value: caption }];
119032
119108
  }
119033
119109
  // Skip runtime components and standard HTML tags
119034
119110
  if (RUNTIME_COMPONENT_TAGS.has(node.tagName))
@@ -126579,6 +126655,332 @@ const mdxishTags_tags = (doc) => {
126579
126655
  };
126580
126656
  /* harmony default export */ const mdxishTags = (mdxishTags_tags);
126581
126657
 
126658
+ ;// ./lib/mdast-util/html-block-component/index.ts
126659
+ const html_block_component_contextMap = new WeakMap();
126660
+ function findHtmlBlockComponentToken() {
126661
+ const events = this.tokenStack;
126662
+ for (let i = events.length - 1; i >= 0; i -= 1) {
126663
+ if (events[i][0].type === 'htmlBlockComponent')
126664
+ return events[i][0];
126665
+ }
126666
+ return undefined;
126667
+ }
126668
+ function enterHtmlBlockComponent(token) {
126669
+ html_block_component_contextMap.set(token, { chunks: [], lastEndLine: token.start.line });
126670
+ this.enter({ type: 'html', value: '' }, token);
126671
+ }
126672
+ function exitHtmlBlockComponentData(token) {
126673
+ const componentToken = findHtmlBlockComponentToken.call(this);
126674
+ if (!componentToken)
126675
+ return;
126676
+ const ctx = html_block_component_contextMap.get(componentToken);
126677
+ if (ctx) {
126678
+ const gap = token.start.line - ctx.lastEndLine;
126679
+ if (ctx.chunks.length > 0 && gap > 0) {
126680
+ ctx.chunks.push('\n'.repeat(gap));
126681
+ }
126682
+ ctx.chunks.push(this.sliceSerialize(token));
126683
+ ctx.lastEndLine = token.end.line;
126684
+ }
126685
+ }
126686
+ function exitHtmlBlockComponent(token) {
126687
+ const ctx = html_block_component_contextMap.get(token);
126688
+ const node = this.stack[this.stack.length - 1];
126689
+ if (ctx) {
126690
+ node.value = ctx.chunks.join('');
126691
+ html_block_component_contextMap.delete(token);
126692
+ }
126693
+ this.exit(token);
126694
+ }
126695
+ function htmlBlockComponentFromMarkdown() {
126696
+ return {
126697
+ enter: {
126698
+ htmlBlockComponent: enterHtmlBlockComponent,
126699
+ },
126700
+ exit: {
126701
+ htmlBlockComponentData: exitHtmlBlockComponentData,
126702
+ htmlBlockComponent: exitHtmlBlockComponent,
126703
+ },
126704
+ };
126705
+ }
126706
+
126707
+ ;// ./lib/micromark/html-block-component/syntax.ts
126708
+
126709
+
126710
+ const TAG_SUFFIX = [
126711
+ codes.uppercaseT,
126712
+ codes.uppercaseM,
126713
+ codes.uppercaseL,
126714
+ codes.uppercaseB,
126715
+ codes.lowercaseL,
126716
+ codes.lowercaseO,
126717
+ codes.lowercaseC,
126718
+ codes.lowercaseK,
126719
+ ];
126720
+ // ---------------------------------------------------------------------------
126721
+ // Shared tokenizer factory
126722
+ // ---------------------------------------------------------------------------
126723
+ /**
126724
+ * Creates a tokenize function for `<HTMLBlock>...</HTMLBlock>`.
126725
+ *
126726
+ * - **flow** (block-level): supports multiline content via line continuations,
126727
+ * consumes trailing whitespace after the closing tag.
126728
+ * - **text** (inline): single-line only, exits immediately after the closing tag.
126729
+ */
126730
+ function syntax_createTokenize(mode) {
126731
+ return function tokenize(effects, ok, nok) {
126732
+ let depth = 1;
126733
+ function matchChars(chars, onMatch, onFail) {
126734
+ if (chars.length === 0)
126735
+ return onMatch;
126736
+ const next = (code) => {
126737
+ if (code === chars[0]) {
126738
+ effects.consume(code);
126739
+ return matchChars(chars.slice(1), onMatch, onFail);
126740
+ }
126741
+ return onFail(code);
126742
+ };
126743
+ return next;
126744
+ }
126745
+ function matchTagName(onMatch, onFail) {
126746
+ const next = (code) => {
126747
+ if (code === codes.uppercaseH) {
126748
+ effects.consume(code);
126749
+ return matchChars(TAG_SUFFIX, onMatch, onFail);
126750
+ }
126751
+ return onFail(code);
126752
+ };
126753
+ return next;
126754
+ }
126755
+ return start;
126756
+ function start(code) {
126757
+ if (code !== codes.lessThan)
126758
+ return nok(code);
126759
+ effects.enter('htmlBlockComponent');
126760
+ effects.enter('htmlBlockComponentData');
126761
+ effects.consume(code);
126762
+ return matchTagName(afterTagName, nok);
126763
+ }
126764
+ function afterTagName(code) {
126765
+ if (code === codes.greaterThan) {
126766
+ effects.consume(code);
126767
+ return body;
126768
+ }
126769
+ if (code === codes.space || code === codes.horizontalTab) {
126770
+ effects.consume(code);
126771
+ return inAttributes;
126772
+ }
126773
+ if (mode === 'flow' && markdownLineEnding(code)) {
126774
+ effects.exit('htmlBlockComponentData');
126775
+ return attributeContinuationStart(code);
126776
+ }
126777
+ if (code === codes.slash) {
126778
+ effects.consume(code);
126779
+ return selfClose;
126780
+ }
126781
+ return nok(code);
126782
+ }
126783
+ function inAttributes(code) {
126784
+ if (code === codes.greaterThan) {
126785
+ effects.consume(code);
126786
+ return body;
126787
+ }
126788
+ if (code === null) {
126789
+ return nok(code);
126790
+ }
126791
+ if (markdownLineEnding(code)) {
126792
+ if (mode === 'text')
126793
+ return nok(code);
126794
+ effects.exit('htmlBlockComponentData');
126795
+ return attributeContinuationStart(code);
126796
+ }
126797
+ effects.consume(code);
126798
+ return inAttributes;
126799
+ }
126800
+ function attributeContinuationStart(code) {
126801
+ return effects.check(html_block_component_syntax_nonLazyContinuationStart, attributeContinuationNonLazy, continuationAfter)(code);
126802
+ }
126803
+ function attributeContinuationNonLazy(code) {
126804
+ effects.enter(types_types.lineEnding);
126805
+ effects.consume(code);
126806
+ effects.exit(types_types.lineEnding);
126807
+ return attributeContinuationBefore;
126808
+ }
126809
+ function attributeContinuationBefore(code) {
126810
+ if (code === null || markdownLineEnding(code)) {
126811
+ return attributeContinuationStart(code);
126812
+ }
126813
+ effects.enter('htmlBlockComponentData');
126814
+ return inAttributes(code);
126815
+ }
126816
+ function selfClose(code) {
126817
+ if (code === codes.greaterThan) {
126818
+ effects.consume(code);
126819
+ return mode === 'flow' ? afterClose : done(code);
126820
+ }
126821
+ return nok(code);
126822
+ }
126823
+ function body(code) {
126824
+ if (code === null)
126825
+ return nok(code);
126826
+ if (markdownLineEnding(code)) {
126827
+ if (mode === 'text') {
126828
+ // Text constructs operate on paragraph content which spans lines
126829
+ effects.consume(code);
126830
+ return body;
126831
+ }
126832
+ effects.exit('htmlBlockComponentData');
126833
+ return continuationStart(code);
126834
+ }
126835
+ if (code === codes.lessThan) {
126836
+ effects.consume(code);
126837
+ return closeSlash;
126838
+ }
126839
+ effects.consume(code);
126840
+ return body;
126841
+ }
126842
+ function closeSlash(code) {
126843
+ if (code === codes.slash) {
126844
+ effects.consume(code);
126845
+ return matchTagName(closeGt, body);
126846
+ }
126847
+ return matchTagName(openAfterTagName, body)(code);
126848
+ }
126849
+ function openAfterTagName(code) {
126850
+ if (code === codes.greaterThan || code === codes.space || code === codes.horizontalTab) {
126851
+ depth += 1;
126852
+ effects.consume(code);
126853
+ return body;
126854
+ }
126855
+ return body(code);
126856
+ }
126857
+ function closeGt(code) {
126858
+ if (code === codes.greaterThan) {
126859
+ depth -= 1;
126860
+ effects.consume(code);
126861
+ if (depth === 0) {
126862
+ return mode === 'flow' ? afterClose : done(code);
126863
+ }
126864
+ return body;
126865
+ }
126866
+ return body(code);
126867
+ }
126868
+ // -- flow-only states ---------------------------------------------------
126869
+ function afterClose(code) {
126870
+ if (code === null || markdownLineEnding(code)) {
126871
+ return done(code);
126872
+ }
126873
+ if (code === codes.space || code === codes.horizontalTab) {
126874
+ effects.consume(code);
126875
+ return afterClose;
126876
+ }
126877
+ // Reject so the block re-parses as a paragraph, deferring to the
126878
+ // text tokenizer which preserves trailing content in the same line.
126879
+ return nok(code);
126880
+ }
126881
+ // -- flow-only: line continuation ---------------------------------------
126882
+ function continuationStart(code) {
126883
+ return effects.check(html_block_component_syntax_nonLazyContinuationStart, continuationStartNonLazy, continuationAfter)(code);
126884
+ }
126885
+ function continuationStartNonLazy(code) {
126886
+ effects.enter(types_types.lineEnding);
126887
+ effects.consume(code);
126888
+ effects.exit(types_types.lineEnding);
126889
+ return continuationBefore;
126890
+ }
126891
+ function continuationBefore(code) {
126892
+ if (code === null || markdownLineEnding(code)) {
126893
+ return continuationStart(code);
126894
+ }
126895
+ effects.enter('htmlBlockComponentData');
126896
+ return body(code);
126897
+ }
126898
+ function continuationAfter(code) {
126899
+ if (code === null)
126900
+ return nok(code);
126901
+ effects.exit('htmlBlockComponent');
126902
+ return ok(code);
126903
+ }
126904
+ // -- shared exit --------------------------------------------------------
126905
+ function done(_code) {
126906
+ effects.exit('htmlBlockComponentData');
126907
+ effects.exit('htmlBlockComponent');
126908
+ return ok(_code);
126909
+ }
126910
+ };
126911
+ }
126912
+ // ---------------------------------------------------------------------------
126913
+ // Flow construct (block-level)
126914
+ // ---------------------------------------------------------------------------
126915
+ const html_block_component_syntax_nonLazyContinuationStart = {
126916
+ tokenize: html_block_component_syntax_tokenizeNonLazyContinuationStart,
126917
+ partial: true,
126918
+ };
126919
+ function resolveToHtmlBlockComponent(events) {
126920
+ let index = events.length;
126921
+ while (index > 0) {
126922
+ index -= 1;
126923
+ if (events[index][0] === 'enter' && events[index][1].type === 'htmlBlockComponent') {
126924
+ break;
126925
+ }
126926
+ }
126927
+ if (index > 1 && events[index - 2][1].type === types_types.linePrefix) {
126928
+ events[index][1].start = events[index - 2][1].start;
126929
+ events[index + 1][1].start = events[index - 2][1].start;
126930
+ events.splice(index - 2, 2);
126931
+ }
126932
+ return events;
126933
+ }
126934
+ const htmlBlockComponentFlowConstruct = {
126935
+ name: 'htmlBlockComponent',
126936
+ tokenize: syntax_createTokenize('flow'),
126937
+ resolveTo: resolveToHtmlBlockComponent,
126938
+ concrete: true,
126939
+ };
126940
+ function html_block_component_syntax_tokenizeNonLazyContinuationStart(effects, ok, nok) {
126941
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
126942
+ const self = this;
126943
+ return start;
126944
+ function start(code) {
126945
+ if (markdownLineEnding(code)) {
126946
+ effects.enter(types_types.lineEnding);
126947
+ effects.consume(code);
126948
+ effects.exit(types_types.lineEnding);
126949
+ return after;
126950
+ }
126951
+ return nok(code);
126952
+ }
126953
+ function after(code) {
126954
+ if (self.parser.lazy[self.now().line]) {
126955
+ return nok(code);
126956
+ }
126957
+ return ok(code);
126958
+ }
126959
+ }
126960
+ // ---------------------------------------------------------------------------
126961
+ // Text construct (inline)
126962
+ // ---------------------------------------------------------------------------
126963
+ const htmlBlockComponentTextConstruct = {
126964
+ name: 'htmlBlockComponent',
126965
+ tokenize: syntax_createTokenize('text'),
126966
+ };
126967
+ // ---------------------------------------------------------------------------
126968
+ // Extension
126969
+ // ---------------------------------------------------------------------------
126970
+ function htmlBlockComponent() {
126971
+ return {
126972
+ flow: {
126973
+ [codes.lessThan]: [htmlBlockComponentFlowConstruct],
126974
+ },
126975
+ text: {
126976
+ [codes.lessThan]: [htmlBlockComponentTextConstruct],
126977
+ },
126978
+ };
126979
+ }
126980
+
126981
+ ;// ./lib/micromark/html-block-component/index.ts
126982
+
126983
+
126582
126984
  ;// ./lib/utils/extractMagicBlocks.ts
126583
126985
  /**
126584
126986
  * The content matching in this regex captures everything between `[block:TYPE]`
@@ -126645,19 +127047,22 @@ function restoreMagicBlocks(replaced, blocks) {
126645
127047
 
126646
127048
 
126647
127049
 
127050
+
127051
+
126648
127052
  /**
126649
127053
  * Removes Markdown and MDX comments.
126650
127054
  */
126651
127055
  async function stripComments(doc, { mdx, mdxish } = {}) {
126652
127056
  const { replaced, blocks } = extractMagicBlocks(doc);
126653
127057
  const processor = unified();
126654
- // we still require these two extensions because:
127058
+ // we still require these extensions because:
126655
127059
  // 1. we can rely on remarkMdx to parse MDXish
126656
127060
  // 2. we need to parse JSX comments into mdxTextExpression nodes so that the transformers can pick them up
127061
+ // 3. we need to claim <HTMLBlock> before htmlFlow intercepts its inner HTML tags
126657
127062
  if (mdxish) {
126658
127063
  processor
126659
- .data('micromarkExtensions', [jsxTable(), mdxExpression({ allowEmpty: true })])
126660
- .data('fromMarkdownExtensions', [jsxTableFromMarkdown(), mdxExpressionFromMarkdown()])
127064
+ .data('micromarkExtensions', [htmlBlockComponent(), jsxTable(), mdxExpression({ allowEmpty: true })])
127065
+ .data('fromMarkdownExtensions', [htmlBlockComponentFromMarkdown(), jsxTableFromMarkdown(), mdxExpressionFromMarkdown()])
126661
127066
  .data('toMarkdownExtensions', [mdxExpressionToMarkdown()]);
126662
127067
  }
126663
127068
  processor