@bendyline/squisq 2.11.12 → 2.11.13

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.
@@ -6,7 +6,9 @@ import {
6
6
  import {
7
7
  formatFrontmatterYaml,
8
8
  getChildren,
9
- splitFrontmatterBlock
9
+ splitFrontmatterBlock,
10
+ stringifyHtmlNodes,
11
+ walkMarkdownTree
10
12
  } from "./chunk-X7BNDUNI.js";
11
13
 
12
14
  // src/markdown/stringify.ts
@@ -964,6 +966,175 @@ function detectMarkdownWrapState(source) {
964
966
  };
965
967
  }
966
968
 
969
+ // src/markdown/contentReferences.ts
970
+ function rewriteMarkdownReferences(source, options = {}) {
971
+ const { frontmatter, body } = splitFrontmatterBlock(source);
972
+ const document = parseMarkdown(body, { frontmatter: false });
973
+ const html = (nodes, insidePicture = false) => {
974
+ let changed = false;
975
+ const output2 = nodes.flatMap((node) => {
976
+ if (node.type !== "htmlElement") return [node];
977
+ if (options.images === "omit" && node.tagName === "picture") {
978
+ changed = true;
979
+ return html(node.children, true).nodes;
980
+ }
981
+ if (options.images === "omit" && (node.tagName === "img" || node.tagName === "source" && insidePicture)) {
982
+ changed = true;
983
+ const alt = node.tagName === "img" ? node.attributes.alt : void 0;
984
+ return alt ? [
985
+ {
986
+ type: "htmlText",
987
+ value: alt.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;")
988
+ }
989
+ ] : [];
990
+ }
991
+ const child = html(node.children);
992
+ changed || (changed = child.changed);
993
+ const copy = { ...node, attributes: { ...node.attributes }, children: child.nodes };
994
+ const key = node.tagName === "a" ? "href" : node.tagName === "img" ? "src" : void 0;
995
+ if (key && node.attributes[key]) {
996
+ const value = options.rewriteUrl?.(node.attributes[key], key === "href" ? "link" : "image");
997
+ if (value !== void 0 && value !== node.attributes[key]) {
998
+ copy.attributes[key] = value;
999
+ changed = true;
1000
+ }
1001
+ }
1002
+ return [copy];
1003
+ });
1004
+ return { nodes: output2, changed };
1005
+ };
1006
+ const blocks = /* @__PURE__ */ new Set([
1007
+ "heading",
1008
+ "paragraph",
1009
+ "blockquote",
1010
+ "code",
1011
+ "thematicBreak",
1012
+ "list",
1013
+ "table",
1014
+ "htmlBlock",
1015
+ "mathBlock",
1016
+ "definition",
1017
+ "footnoteDefinition",
1018
+ "containerDirective",
1019
+ "leafDirective",
1020
+ "definitionList"
1021
+ ]);
1022
+ const structural = /* @__PURE__ */ new Set([
1023
+ "listItem",
1024
+ "tableRow",
1025
+ "tableCell",
1026
+ "definitionTerm",
1027
+ "definitionDescription"
1028
+ ]);
1029
+ const render = (node) => {
1030
+ if (node.type === "document") return stringifyMarkdown(node).trimEnd();
1031
+ return stringifyMarkdown({
1032
+ type: "document",
1033
+ children: blocks.has(node.type) ? [node] : [{ type: "paragraph", children: [node] }]
1034
+ }).trimEnd();
1035
+ };
1036
+ const visit = (node) => {
1037
+ const children = getChildren(node).map(visit);
1038
+ const childChanged = children.some((child) => child.changed);
1039
+ let clone = childChanged && "children" in node ? { ...node, children: children.map((child) => child.node) } : node;
1040
+ let ownChange = false;
1041
+ if ((node.type === "image" || node.type === "imageReference") && options.images === "omit") {
1042
+ clone = { type: "text", value: node.alt ?? "" };
1043
+ ownChange = true;
1044
+ } else if (node.type === "htmlBlock" || node.type === "htmlInline") {
1045
+ const transformed = html(node.htmlChildren);
1046
+ if (transformed.changed) {
1047
+ clone = {
1048
+ ...node,
1049
+ htmlChildren: transformed.nodes,
1050
+ rawHtml: stringifyHtmlNodes(transformed.nodes)
1051
+ };
1052
+ ownChange = true;
1053
+ }
1054
+ } else if (clone.type === "link" || clone.type === "image" || clone.type === "definition") {
1055
+ const url = options.rewriteUrl?.(clone.url, clone.type === "image" ? "image" : "link");
1056
+ if (url !== void 0 && url !== clone.url) {
1057
+ clone = { ...clone, url };
1058
+ ownChange = true;
1059
+ }
1060
+ }
1061
+ const changed = ownChange || childChanged;
1062
+ const pending = ownChange || children.some((child) => child.pending);
1063
+ const start = node.position?.start.offset;
1064
+ const end = node.position?.end.offset;
1065
+ if (pending && start !== void 0 && end !== void 0 && !structural.has(node.type)) {
1066
+ return { node: clone, changed, pending: false, edits: [{ start, end, text: render(clone) }] };
1067
+ }
1068
+ return { node: clone, changed, pending, edits: children.flatMap((child) => child.edits) };
1069
+ };
1070
+ const result = visit(document);
1071
+ if (result.pending) throw new Error("Reference edit has no positioned ancestor");
1072
+ const edits = result.edits;
1073
+ let output = body;
1074
+ let boundary = body.length;
1075
+ for (const e of edits.sort((a, b) => b.start - a.start)) {
1076
+ if (e.end > boundary) throw new Error("Overlapping reference edits");
1077
+ output = output.slice(0, e.start) + e.text + output.slice(e.end);
1078
+ boundary = e.start;
1079
+ }
1080
+ return (frontmatter ?? "") + output;
1081
+ }
1082
+
1083
+ // src/markdown/docfxMarkdown.ts
1084
+ function normalizeDocfxMarkdown(source, options = {}) {
1085
+ const { frontmatter, body } = splitFrontmatterBlock(source);
1086
+ const protectedSpans = [];
1087
+ for (const comment of body.matchAll(/<!--[\s\S]*?-->/g))
1088
+ protectedSpans.push([comment.index, comment.index + comment[0].length]);
1089
+ walkMarkdownTree(parseMarkdown(body, { frontmatter: false }), (node) => {
1090
+ if ((node.type === "code" || node.type === "inlineCode") && node.position?.start.offset !== void 0 && node.position.end.offset !== void 0)
1091
+ protectedSpans.push([node.position.start.offset, node.position.end.offset]);
1092
+ });
1093
+ const escape = (text) => stringifyMarkdown({
1094
+ type: "document",
1095
+ children: [{ type: "paragraph", children: [{ type: "text", value: text }] }]
1096
+ }).trimEnd();
1097
+ const output = body.replace(
1098
+ /(^[^\S\n]*(?:>\s*)?):::\s*([\w-]+)([^\n]*?)(?=\r?$)|(^[^\S\n]*>\s*)\[!(NOTE|TIP|IMPORTANT|WARNING|CAUTION|div)\b([^\]]*)\]|:::\s*(image)\b([^\n]*?):::/gim,
1099
+ (match, prefix, name, raw, quote, admonition, _extra, inlineName, inlineRaw, offset) => {
1100
+ if (protectedSpans.some(([start, end]) => offset >= start && offset < end)) return match;
1101
+ if (admonition)
1102
+ return admonition.toLowerCase() === "div" ? quote ?? "" : `${quote}**${admonition[0] + admonition.slice(1).toLowerCase()}:**`;
1103
+ name ?? (name = inlineName);
1104
+ raw ?? (raw = inlineRaw);
1105
+ const attributes = /* @__PURE__ */ new Map();
1106
+ for (const attr of (raw ?? "").matchAll(/([\w-]+)\s*=\s*(?:"([^"]*)"|'([^']*)')/g))
1107
+ attributes.set(attr[1], attr[2] ?? attr[3]);
1108
+ switch (name?.toLowerCase()) {
1109
+ case "image": {
1110
+ const alt = attributes.get("alt-text") ?? "";
1111
+ const url = attributes.get("source");
1112
+ if (options.images === "omit") return `${prefix ?? ""}${escape(alt)}`;
1113
+ if (!url) throw new Error("DocFX image has no source");
1114
+ const image = stringifyMarkdown({
1115
+ type: "document",
1116
+ children: [{ type: "paragraph", children: [{ type: "image", url, alt }] }]
1117
+ }).trimEnd();
1118
+ return `${prefix ?? ""}${image}`;
1119
+ }
1120
+ case "zone":
1121
+ return attributes.has("pivot") ? `${prefix ?? ""}**Applies to: ${escape(attributes.get("pivot"))}**
1122
+ ` : "";
1123
+ case "zone-end":
1124
+ case "image-end":
1125
+ case "row":
1126
+ case "row-end":
1127
+ case "column":
1128
+ case "column-end":
1129
+ return "";
1130
+ default:
1131
+ throw new Error(`Unsupported DocFX directive: ${name}`);
1132
+ }
1133
+ }
1134
+ );
1135
+ return (frontmatter ?? "") + output;
1136
+ }
1137
+
967
1138
  export {
968
1139
  stringifyMarkdown,
969
1140
  DEFAULT_RESOURCE_MAX_BYTES,
@@ -979,5 +1150,7 @@ export {
979
1150
  unwrapMarkdownSource,
980
1151
  wrapMarkdownSource,
981
1152
  cleanupMarkdownSource,
982
- detectMarkdownWrapState
1153
+ detectMarkdownWrapState,
1154
+ rewriteMarkdownReferences,
1155
+ normalizeDocfxMarkdown
983
1156
  };
package/dist/index.d.ts CHANGED
@@ -10,7 +10,7 @@ export { M as MaterializePageSectionOptions, a as MaterializePageSectionsOptions
10
10
  export { calculateBearing, decodeGeohash, destinationPoint, encodeGeohash, geohashOverlapsBounds, geohashToHierarchicalPath, getGeohash4Neighbors, getGeohashPath, getGeohashPrefix, getNeighbors, haversineDistance, interpolateGreatCircle, sampleGreatCircle } from './spatial/index.js';
11
11
  export { LocalForageAdapter, LocalForageAdapterOptions, LocalStorageAdapter, MemoryStorageAdapter, ScopedContentContainer, StorageAdapter, createMediaProviderFromContainer, scopeContainer } from './storage/index.js';
12
12
  export { C as ContentContainer, a as ContentEntry, M as MemoryContentContainer, f as findDocumentPath } from './ContentContainer-B2w9sUoL.js';
13
- export { DEFAULT_INTERACTIVE_RESOURCE_POLICY, DEFAULT_RESOURCE_MAX_BYTES, DEFAULT_RESOURCE_TIMEOUT_MS, DEFAULT_WRAP_WIDTH, FetchResourceBytesOptions, FetchedResource, HtmlPolicy, LOCAL_ONLY_RESOURCE_POLICY, MARKDOWN_SOURCE_TRANSFORMS, MarkdownSourceEdit, MarkdownSourceTransform, MarkdownSourceTransformId, MarkdownSourceTransformOptions, MarkdownSourceTransformResult, MarkdownWrapState, ResourcePolicy, ResourcePolicyError, SanitizeUrlOptions, TrailingAnnotationMatch, UrlKind, applyMarkdownSourceTransform, cleanupMarkdownSource, countNodes, createDocument, detectMarkdownWrapState, extractPlainText, fetchResourceBytes, findNodesByType, formatBlockScalar, formatFrontmatterValue, formatFrontmatterYaml, fromMdast, getChildren, inferDocumentTitle, isResourceUrlAllowed, matchTrailingPandocAttr, matchTrailingTemplateAnnotation, needsQuoting, parseFrontmatter, parseHtmlToNodes, parseMarkdown, parsePandocAttrTokens, plainTextFromInlineHtml, quoteAttrValue, readFrontmatterThemeId, sanitizeHtmlNodes, sanitizeUrl, serializePandocAttributes, setFrontmatterValues, splitFrontmatterBlock, splitKeyValueToken, stringifyHtmlNodes, stringifyMarkdown, toMdast, tokenizeAttrTokens, unquoteAttrValue, unwrapMarkdownSource, walkMarkdownTree, wrapMarkdownSource } from './markdown/index.js';
13
+ export { DEFAULT_INTERACTIVE_RESOURCE_POLICY, DEFAULT_RESOURCE_MAX_BYTES, DEFAULT_RESOURCE_TIMEOUT_MS, DEFAULT_WRAP_WIDTH, DocfxMarkdownOptions, FetchResourceBytesOptions, FetchedResource, HtmlPolicy, LOCAL_ONLY_RESOURCE_POLICY, MARKDOWN_SOURCE_TRANSFORMS, MarkdownReferenceOptions, MarkdownSourceEdit, MarkdownSourceTransform, MarkdownSourceTransformId, MarkdownSourceTransformOptions, MarkdownSourceTransformResult, MarkdownWrapState, ResourcePolicy, ResourcePolicyError, SanitizeUrlOptions, TrailingAnnotationMatch, UrlKind, applyMarkdownSourceTransform, cleanupMarkdownSource, countNodes, createDocument, detectMarkdownWrapState, extractPlainText, fetchResourceBytes, findNodesByType, formatBlockScalar, formatFrontmatterValue, formatFrontmatterYaml, fromMdast, getChildren, inferDocumentTitle, isResourceUrlAllowed, matchTrailingPandocAttr, matchTrailingTemplateAnnotation, needsQuoting, normalizeDocfxMarkdown, parseFrontmatter, parseHtmlToNodes, parseMarkdown, parsePandocAttrTokens, plainTextFromInlineHtml, quoteAttrValue, readFrontmatterThemeId, rewriteMarkdownReferences, sanitizeHtmlNodes, sanitizeUrl, serializePandocAttributes, setFrontmatterValues, splitFrontmatterBlock, splitKeyValueToken, stringifyHtmlNodes, stringifyMarkdown, toMdast, tokenizeAttrTokens, unquoteAttrValue, unwrapMarkdownSource, walkMarkdownTree, wrapMarkdownSource } from './markdown/index.js';
14
14
  export { B as BLOCK_META_KEY_DESCRIPTORS, a as BlockMetaKeyDescriptor, K as KNOWN_BLOCK_META_KEYS, b as KnownBlockMetaKey, p as parseTimeSeconds } from './annotationCoercion-Ckqpu33y.js';
15
15
  export { BuildCaptionTrackOptions, CaptionSegmentSource, DEFAULT_WORDS_PER_SECOND, NarrationTimeEstimate, NarrationTimeOptions, ReadingTimeEstimate, ReadingTimeOptions, buildCaptionTrack, calculatePrefixDuration, countSpokenWords, estimateNarrationDuration, estimateNarrationTime, estimateReadingTime, estimateSpokenWordCount, estimateTimeFromText } from './timing/index.js';
16
16
  export { SeededRandom, hashString } from './random/index.js';
package/dist/index.js CHANGED
@@ -542,10 +542,12 @@ import {
542
542
  detectMarkdownWrapState,
543
543
  fetchResourceBytes,
544
544
  isResourceUrlAllowed,
545
+ normalizeDocfxMarkdown,
546
+ rewriteMarkdownReferences,
545
547
  stringifyMarkdown,
546
548
  unwrapMarkdownSource,
547
549
  wrapMarkdownSource
548
- } from "./chunk-XZVBR5BP.js";
550
+ } from "./chunk-RLBHQSUG.js";
549
551
  import {
550
552
  DEFAULT_MARKDOWN_SAFETY_LIMITS,
551
553
  MarkdownLimitError,
@@ -1025,6 +1027,7 @@ export {
1025
1027
  nearestSnapPoint,
1026
1028
  needsQuoting,
1027
1029
  normalizeDashboardZoom,
1030
+ normalizeDocfxMarkdown,
1028
1031
  normalizeShapeKind,
1029
1032
  normalizeTransitionDirection,
1030
1033
  normalizeTransitionType,
@@ -1119,6 +1122,7 @@ export {
1119
1122
  resolveTransitionDuration,
1120
1123
  revertToImageEditVersion,
1121
1124
  revertToVersion,
1125
+ rewriteMarkdownReferences,
1122
1126
  rightFeature,
1123
1127
  sampleGreatCircle,
1124
1128
  sanitizeHtmlNodes,
@@ -616,4 +616,29 @@ declare function cleanupMarkdownSource(source: string, options?: MarkdownSourceT
616
616
  */
617
617
  declare function detectMarkdownWrapState(source: string): MarkdownWrapState;
618
618
 
619
- export { DEFAULT_INTERACTIVE_RESOURCE_POLICY, DEFAULT_RESOURCE_MAX_BYTES, DEFAULT_RESOURCE_TIMEOUT_MS, DEFAULT_WRAP_WIDTH, type FetchResourceBytesOptions, type FetchedResource, HeadingAttributes, HtmlNode, type HtmlPolicy, LOCAL_ONLY_RESOURCE_POLICY, MARKDOWN_SOURCE_TRANSFORMS, MarkdownDocument, MarkdownNode, type MarkdownSourceEdit, type MarkdownSourceTransform, type MarkdownSourceTransformId, type MarkdownSourceTransformOptions, type MarkdownSourceTransformResult, type MarkdownWrapState, ParseOptions, type ResourcePolicy, ResourcePolicyError, type SanitizeUrlOptions, StringifyOptions, type TrailingAnnotationMatch, type UrlKind, applyMarkdownSourceTransform, cleanupMarkdownSource, countNodes, createDocument, detectMarkdownWrapState, extractPlainText, fetchResourceBytes, findNodesByType, formatBlockScalar, formatFrontmatterValue, formatFrontmatterYaml, fromMdast, getChildren, inferDocumentTitle, isResourceUrlAllowed, matchTrailingPandocAttr, matchTrailingTemplateAnnotation, needsQuoting, parseFrontmatter, parseHtmlToNodes, parseMarkdown, parsePandocAttrTokens, plainTextFromInlineHtml, quoteAttrValue, readFrontmatterThemeId, sanitizeHtmlNodes, sanitizeUrl, serializePandocAttributes, setFrontmatterValues, splitFrontmatterBlock, splitKeyValueToken, stringifyHtmlNodes, stringifyMarkdown, toMdast, tokenizeAttrTokens, unquoteAttrValue, unwrapMarkdownSource, walkMarkdownTree, wrapMarkdownSource };
619
+ interface MarkdownReferenceOptions {
620
+ /** Return undefined to retain a URL. The caller owns source-specific resolution. */
621
+ rewriteUrl?: (url: string, kind: 'link' | 'image') => string | undefined;
622
+ /** Omit image nodes, retaining their alternative text; default preserve. */
623
+ images?: 'preserve' | 'omit';
624
+ }
625
+ /**
626
+ * Rewrite references using the Markdown and HTML trees. Only changed node
627
+ * spans are serialized: frontmatter, prose, and code outside those spans stay
628
+ * byte-identical. Handles inline and reference links, images, and raw HTML.
629
+ * Does not fetch resources and is not an HTML sanitizer.
630
+ */
631
+ declare function rewriteMarkdownReferences(source: string, options?: MarkdownReferenceOptions): string;
632
+
633
+ interface DocfxMarkdownOptions {
634
+ /** Image omission retains descriptive alt text. */
635
+ images?: 'preserve' | 'omit';
636
+ }
637
+ /** Convert presentational DocFX directives to portable Markdown without fetching.
638
+ * Includes and code transclusions remain the source adapter's responsibility.
639
+ * All zone variants are retained with their pivot labels. Code examples and
640
+ * frontmatter remain untouched. Unsupported directives throw instead of losing text.
641
+ */
642
+ declare function normalizeDocfxMarkdown(source: string, options?: DocfxMarkdownOptions): string;
643
+
644
+ export { DEFAULT_INTERACTIVE_RESOURCE_POLICY, DEFAULT_RESOURCE_MAX_BYTES, DEFAULT_RESOURCE_TIMEOUT_MS, DEFAULT_WRAP_WIDTH, type DocfxMarkdownOptions, type FetchResourceBytesOptions, type FetchedResource, HeadingAttributes, HtmlNode, type HtmlPolicy, LOCAL_ONLY_RESOURCE_POLICY, MARKDOWN_SOURCE_TRANSFORMS, MarkdownDocument, MarkdownNode, type MarkdownReferenceOptions, type MarkdownSourceEdit, type MarkdownSourceTransform, type MarkdownSourceTransformId, type MarkdownSourceTransformOptions, type MarkdownSourceTransformResult, type MarkdownWrapState, ParseOptions, type ResourcePolicy, ResourcePolicyError, type SanitizeUrlOptions, StringifyOptions, type TrailingAnnotationMatch, type UrlKind, applyMarkdownSourceTransform, cleanupMarkdownSource, countNodes, createDocument, detectMarkdownWrapState, extractPlainText, fetchResourceBytes, findNodesByType, formatBlockScalar, formatFrontmatterValue, formatFrontmatterYaml, fromMdast, getChildren, inferDocumentTitle, isResourceUrlAllowed, matchTrailingPandocAttr, matchTrailingTemplateAnnotation, needsQuoting, normalizeDocfxMarkdown, parseFrontmatter, parseHtmlToNodes, parseMarkdown, parsePandocAttrTokens, plainTextFromInlineHtml, quoteAttrValue, readFrontmatterThemeId, rewriteMarkdownReferences, sanitizeHtmlNodes, sanitizeUrl, serializePandocAttributes, setFrontmatterValues, splitFrontmatterBlock, splitKeyValueToken, stringifyHtmlNodes, stringifyMarkdown, toMdast, tokenizeAttrTokens, unquoteAttrValue, unwrapMarkdownSource, walkMarkdownTree, wrapMarkdownSource };
@@ -11,10 +11,12 @@ import {
11
11
  detectMarkdownWrapState,
12
12
  fetchResourceBytes,
13
13
  isResourceUrlAllowed,
14
+ normalizeDocfxMarkdown,
15
+ rewriteMarkdownReferences,
14
16
  stringifyMarkdown,
15
17
  unwrapMarkdownSource,
16
18
  wrapMarkdownSource
17
- } from "../chunk-XZVBR5BP.js";
19
+ } from "../chunk-RLBHQSUG.js";
18
20
  import {
19
21
  DEFAULT_MARKDOWN_SAFETY_LIMITS,
20
22
  MarkdownLimitError,
@@ -94,6 +96,7 @@ export {
94
96
  matchTrailingPandocAttr,
95
97
  matchTrailingTemplateAnnotation,
96
98
  needsQuoting,
99
+ normalizeDocfxMarkdown,
97
100
  parseFrontmatter,
98
101
  parseHtmlToNodes,
99
102
  parseMarkdown,
@@ -103,6 +106,7 @@ export {
103
106
  quoteAttrValue,
104
107
  readFrontmatterThemeId,
105
108
  resolveMarkdownSafetyLimits,
109
+ rewriteMarkdownReferences,
106
110
  sanitizeHtmlNodes,
107
111
  sanitizeUrl,
108
112
  serializePandocAttributes,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bendyline/squisq",
3
- "version": "2.11.12",
3
+ "version": "2.11.13",
4
4
  "description": "Headless utilities for doc/block rendering, spatial math, Markdown, and storage",
5
5
  "license": "MIT",
6
6
  "author": "Bendyline",