@readme/markdown 15.8.0 → 15.9.0

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.
@@ -38,8 +38,8 @@ const HTMLBlock = ({ children = '', html: htmlProp, runScripts, safeMode: safeMo
38
38
  const [cleanedHtml, exec] = extractScripts(html);
39
39
 
40
40
  useEffect(() => {
41
- if (typeof window !== 'undefined' && typeof runScripts === 'boolean' && runScripts) exec();
42
- }, [runScripts, exec]);
41
+ if (typeof window !== 'undefined' && typeof runScripts === 'boolean' && runScripts && !safeMode) exec();
42
+ }, [runScripts, safeMode, exec]);
43
43
 
44
44
  if (nonStringChildren) {
45
45
  // Fail soft: a non-string child (e.g. JSX that wasn't serialized back to a
package/dist/main.js CHANGED
@@ -11423,7 +11423,7 @@ module.exports = function () {
11423
11423
 
11424
11424
  /***/ },
11425
11425
 
11426
- /***/ 9607
11426
+ /***/ 9171
11427
11427
  (module, __webpack_exports__, __webpack_require__) {
11428
11428
 
11429
11429
  "use strict";
@@ -12156,9 +12156,9 @@ const HTMLBlock = ({ children = '', html: htmlProp, runScripts, safeMode: safeMo
12156
12156
  const safeMode = typeof safeModeRaw !== 'boolean' ? safeModeRaw === 'true' : safeModeRaw;
12157
12157
  const [cleanedHtml, exec] = extractScripts(html);
12158
12158
  (0,external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_.useEffect)(() => {
12159
- if (typeof window !== 'undefined' && typeof runScripts === 'boolean' && runScripts)
12159
+ if (typeof window !== 'undefined' && typeof runScripts === 'boolean' && runScripts && !safeMode)
12160
12160
  exec();
12161
- }, [runScripts, exec]);
12161
+ }, [runScripts, safeMode, exec]);
12162
12162
  if (nonStringChildren) {
12163
12163
  // Fail soft: a non-string child (e.g. JSX that wasn't serialized back to a
12164
12164
  // raw string) should never throw, so render the child nodes directly
@@ -103888,6 +103888,32 @@ const mdxComponentHandlers = {
103888
103888
  [NodeTypes.htmlBlock]: htmlBlockHandler,
103889
103889
  };
103890
103890
 
103891
+ ;// ./processor/plugin/safe-mode-html-blocks.ts
103892
+
103893
+
103894
+ /**
103895
+ * Whether a tag name renders through the `HTMLBlock` component. Mirrors the
103896
+ * separator-agnostic, case-insensitive lookup in `getComponentName` and the
103897
+ * rehype-react component map, so `html-block`, `HTMLBlock`, `HtmlBlock` and
103898
+ * `htmlblock` all match.
103899
+ */
103900
+ const isHtmlBlockTag = (tagName) => toPascalCase(tagName).toLowerCase() === 'htmlblock';
103901
+ /**
103902
+ * Forces `safeMode` on every element that renders through `HTMLBlock` so it is
103903
+ * shown as escaped text instead of injected.
103904
+ *
103905
+ * Runs last, so it sees every producer of the element — `[block:html]`,
103906
+ * `<HTMLBlock>` with a template body or an `html` attribute, and a literal
103907
+ * `<html-block>` — and it is unconditional so an author-supplied
103908
+ * `safeMode="false"` can't opt out.
103909
+ */
103910
+ const enforceSafeModeHtmlBlocks = () => tree => {
103911
+ visit(tree, 'element', node => {
103912
+ if (isHtmlBlockTag(node.tagName))
103913
+ node.properties.safeMode = 'true';
103914
+ });
103915
+ };
103916
+
103891
103917
  ;// ./processor/transform/mdxish/anchor-to-jsx.ts
103892
103918
 
103893
103919
 
@@ -106195,7 +106221,7 @@ const parseApiHeaderTitle = (text) => {
106195
106221
  * Transform a magicBlock node into final MDAST nodes.
106196
106222
  */
106197
106223
  function transformMagicBlock(blockType, data, rawValue, options = {}) {
106198
- const { compatibilityMode = false, hardBreaks = true, safeMode = false } = options;
106224
+ const { compatibilityMode = false, hardBreaks = true } = options;
106199
106225
  // Handle empty data by returning placeholder nodes for known block types
106200
106226
  // This allows the editor to show appropriate placeholder UI instead of nothing
106201
106227
  if (Object.keys(data).length < 1) {
@@ -106413,7 +106439,7 @@ function transformMagicBlock(blockType, data, rawValue, options = {}) {
106413
106439
  wrapPinnedBlocks({
106414
106440
  data: {
106415
106441
  hName: 'html-block',
106416
- hProperties: { html: htmlJson.html, runScripts: compatibilityMode, safeMode },
106442
+ hProperties: { html: htmlJson.html, runScripts: compatibilityMode },
106417
106443
  },
106418
106444
  type: 'html-block',
106419
106445
  }, data),
@@ -106673,6 +106699,80 @@ const mdxishHtmlBlocks = () => tree => {
106673
106699
  };
106674
106700
  /* harmony default export */ const mdxish_html_blocks = (mdxishHtmlBlocks);
106675
106701
 
106702
+ ;// ./processor/transform/mdxish/tables/cell-width.ts
106703
+
106704
+
106705
+ // Key must follow `{` or `,` so `minWidth`/`maxWidth` don't match on their suffix
106706
+ const STYLE_OBJECT_WIDTH_REGEX = /[{,]\s*["']?width["']?\s*:\s*(?:"([^"]*)"|'([^']*)'|([^,}]+))/i;
106707
+ // First colon only, so `url(http://…)` values stay intact
106708
+ const CSS_DECLARATION_REGEX = /:(.*)/s;
106709
+ const UNITLESS_NUMBER_REGEX = /^\d+(?:\.\d+)?$/;
106710
+ // HTML reads a `width` attribute as a leading number plus optional `%`, ignoring the rest
106711
+ const HTML_DIMENSION_REGEX = /^\s*(\d+(?:\.\d+)?)\s*(%?)/;
106712
+ /** Bare numbers are pixels. A value carrying declaration separators is not a single width. */
106713
+ const normalizeWidth = (value) => {
106714
+ if (typeof value === 'number')
106715
+ return `${value}px`;
106716
+ if (typeof value !== 'string' || !value.trim())
106717
+ return null;
106718
+ const trimmed = value.trim();
106719
+ if (/[;:{}]/.test(trimmed))
106720
+ return null;
106721
+ return UNITLESS_NUMBER_REGEX.test(trimmed) ? `${trimmed}px` : trimmed;
106722
+ };
106723
+ const widthFromAttribute = (value) => {
106724
+ if (typeof value === 'number')
106725
+ return `${value}px`;
106726
+ if (typeof value !== 'string')
106727
+ return null;
106728
+ const match = HTML_DIMENSION_REGEX.exec(value);
106729
+ return match ? `${match[1]}${match[2] || 'px'}` : null;
106730
+ };
106731
+ const cssPropertyNames = (style) => style
106732
+ .split(';')
106733
+ .map(declaration => declaration.split(CSS_DECLARATION_REGEX)[0].trim().toLowerCase())
106734
+ .filter(Boolean);
106735
+ /** Handles a CSS declaration list and a style object safe mode left as a string (`{ width: "30%" }`). */
106736
+ const widthFromStyleString = (style) => {
106737
+ const trimmed = style.trim();
106738
+ if (trimmed.startsWith('{')) {
106739
+ return STYLE_OBJECT_WIDTH_REGEX.exec(trimmed)?.slice(1).find(Boolean);
106740
+ }
106741
+ return trimmed
106742
+ .split(';')
106743
+ .map(declaration => declaration.split(CSS_DECLARATION_REGEX))
106744
+ .find(([property]) => property.trim().toLowerCase() === 'width')?.[1];
106745
+ };
106746
+ /** Accepts `style={{ width }}`, `style="width: …"` and the hand-authored `width="…"`. */
106747
+ const getCellWidth = (cell) => {
106748
+ const { style, width } = getAttrs(cell);
106749
+ let styleWidth;
106750
+ if (style_object_to_css_isPlainObject(style)) {
106751
+ styleWidth = style.width;
106752
+ }
106753
+ else if (typeof style === 'string') {
106754
+ styleWidth = widthFromStyleString(style);
106755
+ }
106756
+ return normalizeWidth(styleWidth) ?? widthFromAttribute(width);
106757
+ };
106758
+ /** True when the cell's attributes state nothing but its width, which mdast can carry. */
106759
+ const hasOnlyWidthAttributes = (cell) => {
106760
+ if (cell.attributes.length === 0)
106761
+ return false;
106762
+ const { style } = getAttrs(cell);
106763
+ return cell.attributes.every(attribute => {
106764
+ if (!('name' in attribute))
106765
+ return false;
106766
+ if (attribute.name === 'width')
106767
+ return true;
106768
+ if (attribute.name !== 'style')
106769
+ return false;
106770
+ if (style_object_to_css_isPlainObject(style))
106771
+ return Object.keys(style).every(key => key === 'width');
106772
+ return typeof style === 'string' && cssPropertyNames(style).every(property => property === 'width');
106773
+ });
106774
+ };
106775
+
106676
106776
  ;// ./processor/transform/mdxish/mdxish-jsx-to-mdast.ts
106677
106777
 
106678
106778
 
@@ -106680,6 +106780,7 @@ const mdxishHtmlBlocks = () => tree => {
106680
106780
 
106681
106781
 
106682
106782
 
106783
+
106683
106784
  function toImageAlign(value) {
106684
106785
  if (value === 'left' || value === 'center' || value === 'right') {
106685
106786
  return value;
@@ -107121,10 +107222,40 @@ const wrapBareCellsInRow = (node) => {
107121
107222
  });
107122
107223
  };
107123
107224
  /**
107124
- * Converts a JSX <Table> element to an MDAST table node with alignment.
107125
- * Returns null for header-less tables since MDAST always promotes the first row to <thead>.
107225
+ * A lowercase <table> reaches here only because `mdxishTables` kept it as JSX for its
107226
+ * attributes. Widths on first-row cells are the one attribute mdast can carry; anything
107227
+ * else stays JSX so it still renders.
107228
+ */
107229
+ const lowercaseTableIsConvertible = (jsx) => {
107230
+ if (jsx.attributes.length > 0)
107231
+ return false;
107232
+ const headerCells = new Set();
107233
+ let headerRowSeen = false;
107234
+ let convertible = true;
107235
+ visit(jsx, isMDXElement, (child) => {
107236
+ if (child.name === 'tr' && !headerRowSeen) {
107237
+ headerRowSeen = true;
107238
+ visit(child, mdxish_jsx_to_mdast_isTableCell, cell => {
107239
+ headerCells.add(cell);
107240
+ });
107241
+ }
107242
+ if (child.name === null || !tableTags.has(child.name) || child.attributes.length === 0)
107243
+ return;
107244
+ if (!headerCells.has(child) || !hasOnlyWidthAttributes(child) || getCellWidth(child) === null) {
107245
+ convertible = false;
107246
+ }
107247
+ });
107248
+ return convertible;
107249
+ };
107250
+ /**
107251
+ * Converts a JSX <Table>, or a lowercase <table> carrying only widths, to an MDAST table
107252
+ * node with alignment and widths. Returns null for header-less tables since MDAST always
107253
+ * promotes the first row to <thead>.
107126
107254
  */
107127
107255
  const transformTable = (jsx) => {
107256
+ const isLowercase = jsx.name === 'table';
107257
+ if (isLowercase && !lowercaseTableIsConvertible(jsx))
107258
+ return null;
107128
107259
  wrapBareCellsInRow(jsx);
107129
107260
  let hasThead = false;
107130
107261
  visit(jsx, isMDXElement, (child) => {
@@ -107136,6 +107267,7 @@ const transformTable = (jsx) => {
107136
107267
  const { align: alignAttr } = getAttrs(jsx);
107137
107268
  const align = Array.isArray(alignAttr) ? alignAttr : null;
107138
107269
  const rows = [];
107270
+ const widths = [];
107139
107271
  visit(jsx, isMDXElement, (child) => {
107140
107272
  if (child.name !== 'thead' && child.name !== 'tbody')
107141
107273
  return;
@@ -107143,6 +107275,7 @@ const transformTable = (jsx) => {
107143
107275
  if (row.name !== 'tr')
107144
107276
  return;
107145
107277
  const cells = [];
107278
+ const isHeaderRow = rows.length === 0;
107146
107279
  visit(row, mdxish_jsx_to_mdast_isTableCell, (cell) => {
107147
107280
  const parsedChildren = unwrapSoleParagraph(cell.children);
107148
107281
  cells.push({
@@ -107150,6 +107283,8 @@ const transformTable = (jsx) => {
107150
107283
  children: parsedChildren,
107151
107284
  position: cell.position,
107152
107285
  });
107286
+ if (isHeaderRow)
107287
+ widths.push(getCellWidth(cell));
107153
107288
  });
107154
107289
  rows.push({
107155
107290
  type: 'tableRow',
@@ -107162,11 +107297,16 @@ const transformTable = (jsx) => {
107162
107297
  const alignArray = align && columnCount > 0
107163
107298
  ? align.slice(0, columnCount).concat(Array.from({ length: Math.max(0, columnCount - align.length) }, () => null))
107164
107299
  : Array.from({ length: columnCount }, () => null);
107300
+ const data = {
107301
+ ...(isLowercase && { lowercaseTable: true }),
107302
+ ...(widths.some(Boolean) && { widths }),
107303
+ };
107165
107304
  return {
107166
107305
  type: 'table',
107167
107306
  align: alignArray,
107168
107307
  position: jsx.position,
107169
107308
  children: rows,
107309
+ ...(Object.keys(data).length > 0 && { data }),
107170
107310
  };
107171
107311
  };
107172
107312
  /**
@@ -107196,6 +107336,7 @@ const COMPONENT_MAP = {
107196
107336
  figure: transformFigure,
107197
107337
  Recipe: transformRecipe,
107198
107338
  Table: transformTable,
107339
+ table: transformTable,
107199
107340
  };
107200
107341
  /**
107201
107342
  * Transform mdxJsxFlowElement nodes, magic block nodes, and HTML figure elements
@@ -107671,6 +107812,28 @@ const restoreBooleanProperties = () => tree => {
107671
107812
  };
107672
107813
 
107673
107814
 
107815
+ ;// ./processor/transform/mdxish/tables/cell-style.ts
107816
+ /** `left` is the browser default, so it's omitted. Lowercase tables get the HTML string form. */
107817
+ const cellStyle = (align, width = null, { html = false } = {}) => {
107818
+ if (html) {
107819
+ if (!width)
107820
+ return null;
107821
+ return { type: 'mdxJsxAttribute', name: 'style', value: `width: ${width}` };
107822
+ }
107823
+ const declarations = [];
107824
+ if (align && align !== 'left')
107825
+ declarations.push(`textAlign: ${JSON.stringify(align)}`);
107826
+ if (width)
107827
+ declarations.push(`width: ${JSON.stringify(width)}`);
107828
+ if (declarations.length === 0)
107829
+ return null;
107830
+ return {
107831
+ type: 'mdxJsxAttribute',
107832
+ name: 'style',
107833
+ value: { type: 'mdxJsxAttributeValueExpression', value: `{ ${declarations.join(', ')} }` },
107834
+ };
107835
+ };
107836
+
107674
107837
  ;// ./processor/transform/mdxish/tables/gfm-cell-normalization.ts
107675
107838
  /** `<br />` is the only line break a GFM pipe cell can carry, since cells are single-line. */
107676
107839
  const createLineBreak = () => ({
@@ -107709,19 +107872,8 @@ const normalizeCellChildrenForGfm = (cell) => normalizeNodes(cell.children);
107709
107872
 
107710
107873
 
107711
107874
 
107875
+
107712
107876
  const SELF_CLOSING_JSX_REGEX = /^\s*<[A-Z][^>]*\/>\s*$/;
107713
- const mdxish_tables_to_jsx_alignToStyle = (align) => {
107714
- if (!align || align === 'left')
107715
- return null;
107716
- return {
107717
- type: 'mdxJsxAttribute',
107718
- name: 'style',
107719
- value: {
107720
- type: 'mdxJsxAttributeValueExpression',
107721
- value: `{ textAlign: "${align}" }`,
107722
- },
107723
- };
107724
- };
107725
107877
  const mdxish_tables_to_jsx_isTableCell = (node) => ['tableHead', 'tableCell'].includes(node.type);
107726
107878
  const mdxish_tables_to_jsx_isLiteral = (node) => 'value' in node;
107727
107879
  /**
@@ -107777,12 +107929,17 @@ const mdxishTablesToJsx = () => tree => {
107777
107929
  gfmCells.push([cell, normalized]);
107778
107930
  return undefined;
107779
107931
  });
107780
- const stayLowercase = table.data?.lowercaseTable === true;
107932
+ const widths = table.data?.widths ?? [];
107933
+ const hasWidths = widths.some(Boolean);
107934
+ // Lowercase cells can carry a width but not an alignment, so an aligned table becomes <Table>
107935
+ const hasAlignment = table.align.some(align => align && align !== 'left');
107936
+ const stayLowercase = table.data?.lowercaseTable === true && !hasAlignment;
107781
107937
  // We transform to GFM tables if:
107782
107938
  // 1. If it doesn't contain complex elements that the syntax can't represent
107783
- // 2. The original table is not lowercase HTML <table>, because we want to
107939
+ // 2. The original table is not lowercase HTML <table>, because we want to
107784
107940
  // preserve original tables as much as possible
107785
- if (!requiresJsxTable && !stayLowercase) {
107941
+ // 3. No column has a width, which GFM can't express
107942
+ if (!requiresJsxTable && !stayLowercase && !hasWidths) {
107786
107943
  gfmCells.forEach(([cell, children]) => {
107787
107944
  cell.children = children;
107788
107945
  });
@@ -107794,7 +107951,8 @@ const mdxishTablesToJsx = () => tree => {
107794
107951
  if (!headerRow)
107795
107952
  return;
107796
107953
  visit(table, mdxish_tables_to_jsx_isTableCell, flattenBreaksToNewlines);
107797
- const styles = table.align.map(mdxish_tables_to_jsx_alignToStyle);
107954
+ const headerStyles = table.align.map((align, i) => cellStyle(align, widths[i] ?? null, { html: stayLowercase }));
107955
+ const bodyStyles = table.align.map(align => cellStyle(align, null, { html: stayLowercase }));
107798
107956
  const head = {
107799
107957
  attributes: [],
107800
107958
  type: 'mdxJsxFlowElement',
@@ -107810,7 +107968,7 @@ const mdxishTablesToJsx = () => tree => {
107810
107968
  type: 'mdxJsxFlowElement',
107811
107969
  name: 'th',
107812
107970
  children: cell.children,
107813
- ...(styles[cellIndex] && { attributes: [styles[cellIndex]] }),
107971
+ ...(headerStyles[cellIndex] && { attributes: [headerStyles[cellIndex]] }),
107814
107972
  };
107815
107973
  }),
107816
107974
  },
@@ -107830,7 +107988,7 @@ const mdxishTablesToJsx = () => tree => {
107830
107988
  type: 'mdxJsxFlowElement',
107831
107989
  name: 'td',
107832
107990
  children: cell.children,
107833
- ...(styles[cellIndex] && { attributes: [styles[cellIndex]] }),
107991
+ ...(bodyStyles[cellIndex] && { attributes: [bodyStyles[cellIndex]] }),
107834
107992
  };
107835
107993
  }),
107836
107994
  };
@@ -108116,6 +108274,7 @@ function loadComponents() {
108116
108274
 
108117
108275
 
108118
108276
 
108277
+
108119
108278
 
108120
108279
 
108121
108280
  const defaultTransformers = [
@@ -108271,7 +108430,8 @@ function mdxish(mdContent, opts = {}) {
108271
108430
  .use(rehypeMdxishComponents, {
108272
108431
  components,
108273
108432
  processMarkdown: (markdown) => mdxish(markdown, opts),
108274
- });
108433
+ })
108434
+ .use(safeMode ? enforceSafeModeHtmlBlocks : undefined); // Force safeMode on every HTMLBlock; runs last so every producer is covered
108275
108435
  const vfile = new VFile({ value: parserReadyContent });
108276
108436
  const mdast = processor.parse(parserReadyContent);
108277
108437
  const hast = processor.runSync(mdast, vfile);
@@ -109243,7 +109403,7 @@ module.exports = /*#__PURE__*/JSON.parse('{"*":["about","acceptCharset","accessK
109243
109403
  /******/ // startup
109244
109404
  /******/ // Load entry module and return exports
109245
109405
  /******/ // This entry module used 'module' so it can't be inlined
109246
- /******/ let __webpack_exports__ = __webpack_require__(9607);
109406
+ /******/ let __webpack_exports__ = __webpack_require__(9171);
109247
109407
  /******/
109248
109408
  /******/ return __webpack_exports__;
109249
109409
  /******/ })()