@wdprlib/render 1.0.1 → 1.1.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.
package/dist/index.cjs CHANGED
@@ -44,10 +44,15 @@ var __export = (target, all) => {
44
44
  var exports_src = {};
45
45
  __export(exports_src, {
46
46
  renderToHtml: () => renderToHtml,
47
+ createSettings: () => import_ast3.createSettings,
48
+ DEFAULT_SETTINGS: () => import_ast3.DEFAULT_SETTINGS,
47
49
  DEFAULT_EMBED_ALLOWLIST: () => DEFAULT_EMBED_ALLOWLIST
48
50
  });
49
51
  module.exports = __toCommonJS(exports_src);
50
52
 
53
+ // packages/render/src/context.ts
54
+ var import_ast = require("@wdprlib/ast");
55
+
51
56
  // packages/render/src/escape.ts
52
57
  function escapeHtml(text) {
53
58
  return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
@@ -418,6 +423,8 @@ class RenderContext {
418
423
  _equationIndex = 0;
419
424
  _htmlBlockIndex = 0;
420
425
  _bibciteCounter = 0;
426
+ _idSuffix;
427
+ settings;
421
428
  options;
422
429
  footnotes;
423
430
  styles;
@@ -426,6 +433,8 @@ class RenderContext {
426
433
  bibliographyMap;
427
434
  bibliographyEntries;
428
435
  constructor(tree, options = {}) {
436
+ this.settings = options.settings ?? import_ast.DEFAULT_SETTINGS;
437
+ this._idSuffix = this.settings.useTrueIds ? null : Math.random().toString(16).slice(2, 8);
429
438
  this.options = options;
430
439
  this.footnotes = options.footnotes ?? tree.footnotes ?? [];
431
440
  this.styles = tree.styles ?? [];
@@ -479,6 +488,18 @@ class RenderContext {
479
488
  nextBibciteCounter() {
480
489
  return ++this._bibciteCounter;
481
490
  }
491
+ generateId(prefix, index) {
492
+ if (this._idSuffix === null) {
493
+ return `${prefix}${index}`;
494
+ }
495
+ return `${prefix}${index}-${this._idSuffix}`;
496
+ }
497
+ generateFixedId(name) {
498
+ if (this._idSuffix === null) {
499
+ return name;
500
+ }
501
+ return `${name}-${this._idSuffix}`;
502
+ }
482
503
  get page() {
483
504
  return this.options.page;
484
505
  }
@@ -488,15 +509,23 @@ class RenderContext {
488
509
  case "url": {
489
510
  const url = source.data;
490
511
  if (url.startsWith("/") && !url.startsWith("//")) {
512
+ if (!this.settings.allowLocalPaths)
513
+ return null;
491
514
  return `/local--files${url}`;
492
515
  }
493
516
  return url;
494
517
  }
495
518
  case "file1":
519
+ if (!this.settings.allowLocalPaths)
520
+ return null;
496
521
  return pageName ? `/local--files/${pageName}/${source.data.file}` : `/local--files/${source.data.file}`;
497
522
  case "file2":
523
+ if (!this.settings.allowLocalPaths)
524
+ return null;
498
525
  return `/local--files/${source.data.page}/${source.data.file}`;
499
526
  case "file3":
527
+ if (!this.settings.allowLocalPaths)
528
+ return null;
500
529
  return `/local--files/${source.data.site}/${source.data.page}/${source.data.file}`;
501
530
  }
502
531
  }
@@ -548,28 +577,28 @@ class RenderContext {
548
577
  }
549
578
 
550
579
  // packages/render/src/elements/container.ts
551
- var import_ast = require("@wdprlib/ast");
580
+ var import_ast2 = require("@wdprlib/ast");
552
581
  function renderContainer(ctx, data) {
553
582
  const { type, attributes, elements } = data;
554
- if (import_ast.isHeaderType(type)) {
583
+ if (import_ast2.isHeaderType(type)) {
555
584
  renderHeader(ctx, type.header.level, type.header["has-toc"], attributes, elements);
556
585
  return;
557
586
  }
558
- if (import_ast.isAlignType(type)) {
587
+ if (import_ast2.isAlignType(type)) {
559
588
  ctx.push(`<div style="text-align: ${type.align};">`);
560
589
  renderElements(ctx, elements);
561
590
  ctx.push("</div>");
562
591
  return;
563
592
  }
564
- if (import_ast.isStringContainerType(type)) {
593
+ if (import_ast2.isStringContainerType(type)) {
565
594
  renderStringContainer(ctx, type, attributes, elements);
566
595
  }
567
596
  }
568
597
  function renderHeader(ctx, level, hasToc, attributes, elements) {
569
598
  const tag = `h${level}`;
570
599
  if (hasToc) {
571
- const tocId = ctx.nextTocIndex();
572
- ctx.push(`<${tag} id="toc${tocId}"${renderAttrs(attributes)}>`);
600
+ const tocId = ctx.generateId("toc", ctx.nextTocIndex());
601
+ ctx.push(`<${tag} id="${tocId}"${renderAttrs(attributes)}>`);
573
602
  } else {
574
603
  ctx.push(`<${tag}${renderAttrs(attributes)}>`);
575
604
  }
@@ -855,6 +884,8 @@ function renderAnchorName(ctx, name) {
855
884
  // packages/render/src/elements/image.ts
856
885
  function renderImage(ctx, data) {
857
886
  let src = ctx.resolveImageSource(data.source);
887
+ if (src === null)
888
+ return;
858
889
  if (isDangerousUrl(src)) {
859
890
  src = "#invalid-url";
860
891
  }
@@ -3939,7 +3970,7 @@ function fnv1aHash(input, hexLen) {
3939
3970
  function renderTabView(ctx, tabs) {
3940
3971
  const labelString = tabs.map((t) => t.label).join("");
3941
3972
  const hash = md5Hash(labelString);
3942
- const widgetId = `wiki-tabview-${hash}`;
3973
+ const widgetId = ctx.generateFixedId(`wiki-tabview-${hash}`);
3943
3974
  ctx.push(`<div id="${widgetId}" class="yui-navset">`);
3944
3975
  ctx.push(`<ul class="yui-nav">`);
3945
3976
  for (let i = 0;i < tabs.length; i++) {
@@ -3954,7 +3985,8 @@ function renderTabView(ctx, tabs) {
3954
3985
  for (let i = 0;i < tabs.length; i++) {
3955
3986
  const tab = tabs[i];
3956
3987
  const displayStyle = i === 0 ? "" : ` style="display:none"`;
3957
- ctx.push(`<div id="wiki-tab-0-${i}"${displayStyle}>`);
3988
+ const tabId = ctx.generateId("wiki-tab-0-", i);
3989
+ ctx.push(`<div id="${tabId}"${displayStyle}>`);
3958
3990
  renderElements(ctx, tab.elements);
3959
3991
  ctx.push("</div>");
3960
3992
  }
@@ -3967,8 +3999,9 @@ function md5Hash(input) {
3967
3999
 
3968
4000
  // packages/render/src/elements/footnote.ts
3969
4001
  function renderFootnoteRef(ctx, index) {
4002
+ const id = ctx.generateId("footnoteref-", index);
3970
4003
  ctx.push(`<sup class="footnoteref">`);
3971
- ctx.push(`<a id="footnoteref-${index}" href="javascript:;" class="footnoteref">${index}</a>`);
4004
+ ctx.push(`<a id="${id}" href="javascript:;" class="footnoteref">${index}</a>`);
3972
4005
  ctx.push("</sup>");
3973
4006
  }
3974
4007
  function renderFootnoteBlock(ctx, data) {
@@ -3980,7 +4013,8 @@ function renderFootnoteBlock(ctx, data) {
3980
4013
  for (let i = 0;i < ctx.footnotes.length; i++) {
3981
4014
  const index = i + 1;
3982
4015
  const elements = ctx.footnotes[i] ?? [];
3983
- ctx.push(`<div class="footnote-footer" id="footnote-${index}">`);
4016
+ const fnId = ctx.generateId("footnote-", index);
4017
+ ctx.push(`<div class="footnote-footer" id="${fnId}">`);
3984
4018
  ctx.push(`<a href="javascript:;">${index}</a>. `);
3985
4019
  renderElements(ctx, elements);
3986
4020
  ctx.push("</div>");
@@ -4018,7 +4052,7 @@ function renderMath(ctx, data) {
4018
4052
  const index = ctx.nextEquationIndex() + 1;
4019
4053
  const latex = data["latex-source"];
4020
4054
  const mathml = renderLatexToMathML(latex, true);
4021
- const id = data.name ? `equation-${data.name}` : `equation-${index}`;
4055
+ const id = data.name ? ctx.generateId("equation-", data.name) : ctx.generateId("equation-", index);
4022
4056
  const dataName = data.name ? ` data-name="${escapeAttr(data.name)}"` : "";
4023
4057
  ctx.push(`<div class="math-block" id="${escapeAttr(id)}"${dataName}>`);
4024
4058
  if (data.name) {
@@ -4057,7 +4091,7 @@ function renderMathInline(ctx, data) {
4057
4091
  ctx.push("</span>");
4058
4092
  }
4059
4093
  function renderEquationRef(ctx, name) {
4060
- const id = `equation-${name}`;
4094
+ const id = ctx.generateId("equation-", name);
4061
4095
  ctx.push(`<span class="eref" data-target="${escapeAttr(id)}">`);
4062
4096
  ctx.push(`<a class="eref-link" href="#${escapeAttr(id)}">`);
4063
4097
  ctx.push(escapeHtml(name));
@@ -4412,8 +4446,9 @@ function renderBibliographyCite(ctx, data) {
4412
4446
  return;
4413
4447
  }
4414
4448
  const idSuffix = generateIdSuffix(data.label, counter);
4415
- const id = `bibcite-${number}-${idSuffix}`;
4416
- const onclick = `WIKIDOT.page.utils.scrollToReference('bibitem-${number}')`;
4449
+ const id = ctx.generateId(`bibcite-${number}-`, idSuffix);
4450
+ const bibitemId = ctx.generateId("bibitem-", number);
4451
+ const onclick = `WIKIDOT.page.utils.scrollToReference('${bibitemId}')`;
4417
4452
  ctx.push(`<a href="javascript:;" class="bibcite" id="${id}" onclick="${escapeAttr(onclick)}">`);
4418
4453
  ctx.push(String(number));
4419
4454
  ctx.push("</a>");
@@ -4426,7 +4461,8 @@ function renderBibliographyBlock(ctx, data, renderElements2) {
4426
4461
  ctx.push(`<div class="title">${escapeHtml(title)}</div>`);
4427
4462
  let index = 1;
4428
4463
  for (const entry of data.entries) {
4429
- ctx.push(`<div class="bibitem" id="bibitem-${index}">`);
4464
+ const itemId = ctx.generateId("bibitem-", index);
4465
+ ctx.push(`<div class="bibitem" id="${itemId}">`);
4430
4466
  ctx.push(`${index}. `);
4431
4467
  renderElements2(ctx, entry.value);
4432
4468
  ctx.push("</div>");
@@ -4459,12 +4495,19 @@ function renderTocList(ctx, listData, depth) {
4459
4495
  renderTocItem(ctx, item, depth);
4460
4496
  }
4461
4497
  }
4498
+ function rewriteTocAnchor(ctx, href) {
4499
+ const match = /^#toc(\d+)$/.exec(href);
4500
+ if (!match)
4501
+ return href;
4502
+ return `#${ctx.generateId("toc", Number(match[1]))}`;
4503
+ }
4462
4504
  function renderTocItem(ctx, item, depth) {
4463
4505
  if (item["item-type"] === "elements") {
4464
4506
  for (const el of item.elements) {
4465
4507
  const link = extractLinkText(el);
4466
4508
  if (link) {
4467
- ctx.push(`<div style="margin-left: ${depth}em;"><a href="${escapeHtml(link.href)}">${escapeHtml(link.text)}</a></div>`);
4509
+ const href = rewriteTocAnchor(ctx, link.href);
4510
+ ctx.push(`<div style="margin-left: ${depth}em;"><a href="${escapeAttr(href)}">${escapeHtml(link.text)}</a></div>`);
4468
4511
  }
4469
4512
  }
4470
4513
  } else if (item["item-type"] === "sub-list") {
@@ -5029,7 +5072,7 @@ function formatNumber(n) {
5029
5072
  function renderToHtml(tree, options = {}) {
5030
5073
  const ctx = new RenderContext(tree, options);
5031
5074
  renderElements(ctx, tree.elements);
5032
- if (tree.styles?.length) {
5075
+ if (ctx.settings.allowStyleElements && tree.styles?.length) {
5033
5076
  for (const style of tree.styles) {
5034
5077
  ctx.push(`<style>${escapeStyleContent(style)}</style>`);
5035
5078
  }
@@ -5173,3 +5216,6 @@ function renderElement(ctx, element) {
5173
5216
  break;
5174
5217
  }
5175
5218
  }
5219
+
5220
+ // packages/render/src/index.ts
5221
+ var import_ast3 = require("@wdprlib/ast");
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { SyntaxTree as SyntaxTree2 } from "@wdprlib/ast";
2
- import { Element } from "@wdprlib/ast";
2
+ import { Element, WikitextSettings } from "@wdprlib/ast";
3
3
  /**
4
4
  * Allowlist entry for embed content validation
5
5
  * Each entry specifies a host pattern and optional path prefix
@@ -70,6 +70,8 @@ interface RenderResolvers {
70
70
  * Options for HTML rendering
71
71
  */
72
72
  interface RenderOptions {
73
+ /** Wikitext settings controlling rendering behavior */
74
+ settings?: WikitextSettings;
73
75
  /** Page context for resolving file paths, links, etc. */
74
76
  page?: PageContext;
75
77
  /** Pre-collected footnote elements from SyntaxTree.footnotes */
@@ -100,4 +102,6 @@ interface RenderOptions {
100
102
  * Render a SyntaxTree to HTML string
101
103
  */
102
104
  declare function renderToHtml(tree: SyntaxTree2, options?: RenderOptions): string;
103
- export { renderToHtml, ResolvedUser, RenderResolvers, RenderOptions, PageContext, DEFAULT_EMBED_ALLOWLIST };
105
+ import { WikitextMode, WikitextSettings as WikitextSettings3 } from "@wdprlib/ast";
106
+ import { createSettings, DEFAULT_SETTINGS } from "@wdprlib/ast";
107
+ export { renderToHtml, createSettings, WikitextSettings3 as WikitextSettings, WikitextMode, ResolvedUser, RenderResolvers, RenderOptions, PageContext, DEFAULT_SETTINGS, DEFAULT_EMBED_ALLOWLIST };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { SyntaxTree as SyntaxTree2 } from "@wdprlib/ast";
2
- import { Element } from "@wdprlib/ast";
2
+ import { Element, WikitextSettings } from "@wdprlib/ast";
3
3
  /**
4
4
  * Allowlist entry for embed content validation
5
5
  * Each entry specifies a host pattern and optional path prefix
@@ -70,6 +70,8 @@ interface RenderResolvers {
70
70
  * Options for HTML rendering
71
71
  */
72
72
  interface RenderOptions {
73
+ /** Wikitext settings controlling rendering behavior */
74
+ settings?: WikitextSettings;
73
75
  /** Page context for resolving file paths, links, etc. */
74
76
  page?: PageContext;
75
77
  /** Pre-collected footnote elements from SyntaxTree.footnotes */
@@ -100,4 +102,6 @@ interface RenderOptions {
100
102
  * Render a SyntaxTree to HTML string
101
103
  */
102
104
  declare function renderToHtml(tree: SyntaxTree2, options?: RenderOptions): string;
103
- export { renderToHtml, ResolvedUser, RenderResolvers, RenderOptions, PageContext, DEFAULT_EMBED_ALLOWLIST };
105
+ import { WikitextMode, WikitextSettings as WikitextSettings3 } from "@wdprlib/ast";
106
+ import { createSettings, DEFAULT_SETTINGS } from "@wdprlib/ast";
107
+ export { renderToHtml, createSettings, WikitextSettings3 as WikitextSettings, WikitextMode, ResolvedUser, RenderResolvers, RenderOptions, PageContext, DEFAULT_SETTINGS, DEFAULT_EMBED_ALLOWLIST };
package/dist/index.js CHANGED
@@ -1,3 +1,6 @@
1
+ // packages/render/src/context.ts
2
+ import { DEFAULT_SETTINGS } from "@wdprlib/ast";
3
+
1
4
  // packages/render/src/escape.ts
2
5
  function escapeHtml(text) {
3
6
  return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
@@ -368,6 +371,8 @@ class RenderContext {
368
371
  _equationIndex = 0;
369
372
  _htmlBlockIndex = 0;
370
373
  _bibciteCounter = 0;
374
+ _idSuffix;
375
+ settings;
371
376
  options;
372
377
  footnotes;
373
378
  styles;
@@ -376,6 +381,8 @@ class RenderContext {
376
381
  bibliographyMap;
377
382
  bibliographyEntries;
378
383
  constructor(tree, options = {}) {
384
+ this.settings = options.settings ?? DEFAULT_SETTINGS;
385
+ this._idSuffix = this.settings.useTrueIds ? null : Math.random().toString(16).slice(2, 8);
379
386
  this.options = options;
380
387
  this.footnotes = options.footnotes ?? tree.footnotes ?? [];
381
388
  this.styles = tree.styles ?? [];
@@ -429,6 +436,18 @@ class RenderContext {
429
436
  nextBibciteCounter() {
430
437
  return ++this._bibciteCounter;
431
438
  }
439
+ generateId(prefix, index) {
440
+ if (this._idSuffix === null) {
441
+ return `${prefix}${index}`;
442
+ }
443
+ return `${prefix}${index}-${this._idSuffix}`;
444
+ }
445
+ generateFixedId(name) {
446
+ if (this._idSuffix === null) {
447
+ return name;
448
+ }
449
+ return `${name}-${this._idSuffix}`;
450
+ }
432
451
  get page() {
433
452
  return this.options.page;
434
453
  }
@@ -438,15 +457,23 @@ class RenderContext {
438
457
  case "url": {
439
458
  const url = source.data;
440
459
  if (url.startsWith("/") && !url.startsWith("//")) {
460
+ if (!this.settings.allowLocalPaths)
461
+ return null;
441
462
  return `/local--files${url}`;
442
463
  }
443
464
  return url;
444
465
  }
445
466
  case "file1":
467
+ if (!this.settings.allowLocalPaths)
468
+ return null;
446
469
  return pageName ? `/local--files/${pageName}/${source.data.file}` : `/local--files/${source.data.file}`;
447
470
  case "file2":
471
+ if (!this.settings.allowLocalPaths)
472
+ return null;
448
473
  return `/local--files/${source.data.page}/${source.data.file}`;
449
474
  case "file3":
475
+ if (!this.settings.allowLocalPaths)
476
+ return null;
450
477
  return `/local--files/${source.data.site}/${source.data.page}/${source.data.file}`;
451
478
  }
452
479
  }
@@ -518,8 +545,8 @@ function renderContainer(ctx, data) {
518
545
  function renderHeader(ctx, level, hasToc, attributes, elements) {
519
546
  const tag = `h${level}`;
520
547
  if (hasToc) {
521
- const tocId = ctx.nextTocIndex();
522
- ctx.push(`<${tag} id="toc${tocId}"${renderAttrs(attributes)}>`);
548
+ const tocId = ctx.generateId("toc", ctx.nextTocIndex());
549
+ ctx.push(`<${tag} id="${tocId}"${renderAttrs(attributes)}>`);
523
550
  } else {
524
551
  ctx.push(`<${tag}${renderAttrs(attributes)}>`);
525
552
  }
@@ -805,6 +832,8 @@ function renderAnchorName(ctx, name) {
805
832
  // packages/render/src/elements/image.ts
806
833
  function renderImage(ctx, data) {
807
834
  let src = ctx.resolveImageSource(data.source);
835
+ if (src === null)
836
+ return;
808
837
  if (isDangerousUrl(src)) {
809
838
  src = "#invalid-url";
810
839
  }
@@ -3889,7 +3918,7 @@ function fnv1aHash(input, hexLen) {
3889
3918
  function renderTabView(ctx, tabs) {
3890
3919
  const labelString = tabs.map((t) => t.label).join("");
3891
3920
  const hash = md5Hash(labelString);
3892
- const widgetId = `wiki-tabview-${hash}`;
3921
+ const widgetId = ctx.generateFixedId(`wiki-tabview-${hash}`);
3893
3922
  ctx.push(`<div id="${widgetId}" class="yui-navset">`);
3894
3923
  ctx.push(`<ul class="yui-nav">`);
3895
3924
  for (let i = 0;i < tabs.length; i++) {
@@ -3904,7 +3933,8 @@ function renderTabView(ctx, tabs) {
3904
3933
  for (let i = 0;i < tabs.length; i++) {
3905
3934
  const tab = tabs[i];
3906
3935
  const displayStyle = i === 0 ? "" : ` style="display:none"`;
3907
- ctx.push(`<div id="wiki-tab-0-${i}"${displayStyle}>`);
3936
+ const tabId = ctx.generateId("wiki-tab-0-", i);
3937
+ ctx.push(`<div id="${tabId}"${displayStyle}>`);
3908
3938
  renderElements(ctx, tab.elements);
3909
3939
  ctx.push("</div>");
3910
3940
  }
@@ -3917,8 +3947,9 @@ function md5Hash(input) {
3917
3947
 
3918
3948
  // packages/render/src/elements/footnote.ts
3919
3949
  function renderFootnoteRef(ctx, index) {
3950
+ const id = ctx.generateId("footnoteref-", index);
3920
3951
  ctx.push(`<sup class="footnoteref">`);
3921
- ctx.push(`<a id="footnoteref-${index}" href="javascript:;" class="footnoteref">${index}</a>`);
3952
+ ctx.push(`<a id="${id}" href="javascript:;" class="footnoteref">${index}</a>`);
3922
3953
  ctx.push("</sup>");
3923
3954
  }
3924
3955
  function renderFootnoteBlock(ctx, data) {
@@ -3930,7 +3961,8 @@ function renderFootnoteBlock(ctx, data) {
3930
3961
  for (let i = 0;i < ctx.footnotes.length; i++) {
3931
3962
  const index = i + 1;
3932
3963
  const elements = ctx.footnotes[i] ?? [];
3933
- ctx.push(`<div class="footnote-footer" id="footnote-${index}">`);
3964
+ const fnId = ctx.generateId("footnote-", index);
3965
+ ctx.push(`<div class="footnote-footer" id="${fnId}">`);
3934
3966
  ctx.push(`<a href="javascript:;">${index}</a>. `);
3935
3967
  renderElements(ctx, elements);
3936
3968
  ctx.push("</div>");
@@ -3968,7 +4000,7 @@ function renderMath(ctx, data) {
3968
4000
  const index = ctx.nextEquationIndex() + 1;
3969
4001
  const latex = data["latex-source"];
3970
4002
  const mathml = renderLatexToMathML(latex, true);
3971
- const id = data.name ? `equation-${data.name}` : `equation-${index}`;
4003
+ const id = data.name ? ctx.generateId("equation-", data.name) : ctx.generateId("equation-", index);
3972
4004
  const dataName = data.name ? ` data-name="${escapeAttr(data.name)}"` : "";
3973
4005
  ctx.push(`<div class="math-block" id="${escapeAttr(id)}"${dataName}>`);
3974
4006
  if (data.name) {
@@ -4007,7 +4039,7 @@ function renderMathInline(ctx, data) {
4007
4039
  ctx.push("</span>");
4008
4040
  }
4009
4041
  function renderEquationRef(ctx, name) {
4010
- const id = `equation-${name}`;
4042
+ const id = ctx.generateId("equation-", name);
4011
4043
  ctx.push(`<span class="eref" data-target="${escapeAttr(id)}">`);
4012
4044
  ctx.push(`<a class="eref-link" href="#${escapeAttr(id)}">`);
4013
4045
  ctx.push(escapeHtml(name));
@@ -4362,8 +4394,9 @@ function renderBibliographyCite(ctx, data) {
4362
4394
  return;
4363
4395
  }
4364
4396
  const idSuffix = generateIdSuffix(data.label, counter);
4365
- const id = `bibcite-${number}-${idSuffix}`;
4366
- const onclick = `WIKIDOT.page.utils.scrollToReference('bibitem-${number}')`;
4397
+ const id = ctx.generateId(`bibcite-${number}-`, idSuffix);
4398
+ const bibitemId = ctx.generateId("bibitem-", number);
4399
+ const onclick = `WIKIDOT.page.utils.scrollToReference('${bibitemId}')`;
4367
4400
  ctx.push(`<a href="javascript:;" class="bibcite" id="${id}" onclick="${escapeAttr(onclick)}">`);
4368
4401
  ctx.push(String(number));
4369
4402
  ctx.push("</a>");
@@ -4376,7 +4409,8 @@ function renderBibliographyBlock(ctx, data, renderElements2) {
4376
4409
  ctx.push(`<div class="title">${escapeHtml(title)}</div>`);
4377
4410
  let index = 1;
4378
4411
  for (const entry of data.entries) {
4379
- ctx.push(`<div class="bibitem" id="bibitem-${index}">`);
4412
+ const itemId = ctx.generateId("bibitem-", index);
4413
+ ctx.push(`<div class="bibitem" id="${itemId}">`);
4380
4414
  ctx.push(`${index}. `);
4381
4415
  renderElements2(ctx, entry.value);
4382
4416
  ctx.push("</div>");
@@ -4409,12 +4443,19 @@ function renderTocList(ctx, listData, depth) {
4409
4443
  renderTocItem(ctx, item, depth);
4410
4444
  }
4411
4445
  }
4446
+ function rewriteTocAnchor(ctx, href) {
4447
+ const match = /^#toc(\d+)$/.exec(href);
4448
+ if (!match)
4449
+ return href;
4450
+ return `#${ctx.generateId("toc", Number(match[1]))}`;
4451
+ }
4412
4452
  function renderTocItem(ctx, item, depth) {
4413
4453
  if (item["item-type"] === "elements") {
4414
4454
  for (const el of item.elements) {
4415
4455
  const link = extractLinkText(el);
4416
4456
  if (link) {
4417
- ctx.push(`<div style="margin-left: ${depth}em;"><a href="${escapeHtml(link.href)}">${escapeHtml(link.text)}</a></div>`);
4457
+ const href = rewriteTocAnchor(ctx, link.href);
4458
+ ctx.push(`<div style="margin-left: ${depth}em;"><a href="${escapeAttr(href)}">${escapeHtml(link.text)}</a></div>`);
4418
4459
  }
4419
4460
  }
4420
4461
  } else if (item["item-type"] === "sub-list") {
@@ -4979,7 +5020,7 @@ function formatNumber(n) {
4979
5020
  function renderToHtml(tree, options = {}) {
4980
5021
  const ctx = new RenderContext(tree, options);
4981
5022
  renderElements(ctx, tree.elements);
4982
- if (tree.styles?.length) {
5023
+ if (ctx.settings.allowStyleElements && tree.styles?.length) {
4983
5024
  for (const style of tree.styles) {
4984
5025
  ctx.push(`<style>${escapeStyleContent(style)}</style>`);
4985
5026
  }
@@ -5123,7 +5164,12 @@ function renderElement(ctx, element) {
5123
5164
  break;
5124
5165
  }
5125
5166
  }
5167
+
5168
+ // packages/render/src/index.ts
5169
+ import { createSettings, DEFAULT_SETTINGS as DEFAULT_SETTINGS2 } from "@wdprlib/ast";
5126
5170
  export {
5127
5171
  renderToHtml,
5172
+ createSettings,
5173
+ DEFAULT_SETTINGS2 as DEFAULT_SETTINGS,
5128
5174
  DEFAULT_EMBED_ALLOWLIST
5129
5175
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wdprlib/render",
3
- "version": "1.0.1",
3
+ "version": "1.1.0",
4
4
  "description": "HTML renderer for Wikidot markup",
5
5
  "keywords": [
6
6
  "html",
@@ -39,7 +39,7 @@
39
39
  "access": "public"
40
40
  },
41
41
  "dependencies": {
42
- "@wdprlib/ast": "1.0.0",
42
+ "@wdprlib/ast": "1.1.0",
43
43
  "domhandler": "^5.0.3",
44
44
  "htmlparser2": "^10.0.0",
45
45
  "sanitize-html": "^2.14.0",