@ai-markdown/core 3.0.0 → 3.0.1
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/README.md +20 -18
- package/dist/index.cjs +102 -33
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.dev.cjs +102 -33
- package/dist/index.dev.cjs.map +1 -1
- package/dist/index.dev.js +106 -36
- package/dist/index.dev.js.map +1 -1
- package/dist/index.js +106 -36
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.dev.js
CHANGED
|
@@ -341,19 +341,49 @@ function createBlockPlanner() {
|
|
|
341
341
|
let h = 0;
|
|
342
342
|
let reusedContext = false;
|
|
343
343
|
if (previous && source.startsWith(previous.source) && options.phantomFootnoteLabels === previous.phantoms) {
|
|
344
|
+
const prevHast = previous.hast.children;
|
|
345
|
+
const prevPlan = previous.result.plan;
|
|
346
|
+
const isRetainedGap = (i) => {
|
|
347
|
+
const gap = hast.children[i];
|
|
348
|
+
return gap === prevHast[i] && gap.type === "text" && !/\S/.test(gap.value);
|
|
349
|
+
};
|
|
344
350
|
while (m < mdast.children.length) {
|
|
345
351
|
const node = mdast.children[m];
|
|
346
352
|
const el = hast.children[h];
|
|
347
|
-
const item =
|
|
348
|
-
if (node !== previous.mdast.children[m] || el !==
|
|
353
|
+
const item = prevPlan[h];
|
|
354
|
+
if (node !== previous.mdast.children[m] || el !== prevHast[h] || !el || el.type !== "element" || !item || item.kind !== "block" || item.info.startOffset !== node.position?.start.offset || !isEligible(node))
|
|
349
355
|
break;
|
|
356
|
+
const startOffset = item.info.startOffset;
|
|
357
|
+
let next = h + 1;
|
|
358
|
+
let complete = true;
|
|
359
|
+
for (; ; ) {
|
|
360
|
+
let probe = next;
|
|
361
|
+
while (probe < hast.children.length && isRetainedGap(probe)) probe++;
|
|
362
|
+
const sibling = prevPlan[probe];
|
|
363
|
+
if (!sibling || sibling.kind !== "block" || sibling.info.startOffset !== startOffset) break;
|
|
364
|
+
if (hast.children[probe] !== prevHast[probe]) {
|
|
365
|
+
complete = false;
|
|
366
|
+
break;
|
|
367
|
+
}
|
|
368
|
+
next = probe + 1;
|
|
369
|
+
}
|
|
370
|
+
if (!complete) break;
|
|
350
371
|
reusedContext ||= item.info.hasReference;
|
|
351
372
|
m++;
|
|
352
|
-
h
|
|
353
|
-
while (h < hast.children.length)
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
373
|
+
h = next;
|
|
374
|
+
while (h < hast.children.length && isRetainedGap(h)) h++;
|
|
375
|
+
}
|
|
376
|
+
if (m > 0) {
|
|
377
|
+
const prefixEnd = mdast.children[m - 1].position?.end.offset ?? 0;
|
|
378
|
+
for (let i = h; i < hast.children.length; i++) {
|
|
379
|
+
const child = hast.children[i];
|
|
380
|
+
const at = child.type === "element" ? child.position?.start.offset : void 0;
|
|
381
|
+
if (at !== void 0 && at < prefixEnd) {
|
|
382
|
+
m = 0;
|
|
383
|
+
h = 0;
|
|
384
|
+
reusedContext = false;
|
|
385
|
+
break;
|
|
386
|
+
}
|
|
357
387
|
}
|
|
358
388
|
}
|
|
359
389
|
}
|
|
@@ -387,7 +417,7 @@ function createBlockPlanner() {
|
|
|
387
417
|
}
|
|
388
418
|
|
|
389
419
|
// src/contribution.ts
|
|
390
|
-
import { extractContributions, extractDefBodiesFromHast } from "@ai-markdown/engine";
|
|
420
|
+
import { extractContributions, extractDefBodiesFromHast, footnoteSafeId } from "@ai-markdown/engine";
|
|
391
421
|
function createContributionSession() {
|
|
392
422
|
let lastContribution = null;
|
|
393
423
|
return {
|
|
@@ -400,7 +430,12 @@ function createContributionSession() {
|
|
|
400
430
|
phantomFootnoteLabels: targetPhantoms.missingFootnotes
|
|
401
431
|
})) {
|
|
402
432
|
if (node.kind === "ref") {
|
|
403
|
-
refs.push({
|
|
433
|
+
refs.push({
|
|
434
|
+
label: node.label,
|
|
435
|
+
kind: node.refKind,
|
|
436
|
+
referenceType: node.referenceType,
|
|
437
|
+
...node.nestedIn !== void 0 ? { nestedIn: node.nestedIn } : {}
|
|
438
|
+
});
|
|
404
439
|
} else if (node.kind === "fnDef") {
|
|
405
440
|
defMeta.set(node.label, {
|
|
406
441
|
identifier: node.label,
|
|
@@ -434,14 +469,14 @@ function createContributionSession() {
|
|
|
434
469
|
if (last?.registry === registry && last.symbol === sym && last.fp === fp && last.chain.length === chain.length && last.chain.every((dep, i) => dep === chain[i])) {
|
|
435
470
|
return;
|
|
436
471
|
}
|
|
437
|
-
const
|
|
472
|
+
const bodiesBySafeId = extractDefBodiesFromHast(pipeline.hast, clobberPrefix);
|
|
438
473
|
const defs = /* @__PURE__ */ new Map();
|
|
439
474
|
for (const [label, meta] of defMeta) {
|
|
440
475
|
defs.set(label, {
|
|
441
476
|
identifier: meta.identifier,
|
|
442
477
|
sourceIdentifier: meta.sourceIdentifier,
|
|
443
478
|
contentSource: meta.contentSource,
|
|
444
|
-
bodyHast:
|
|
479
|
+
bodyHast: bodiesBySafeId.get(footnoteSafeId(meta.sourceIdentifier)) ?? []
|
|
445
480
|
});
|
|
446
481
|
}
|
|
447
482
|
lastContribution = { registry, symbol: sym, fp, chain };
|
|
@@ -578,7 +613,7 @@ function deriveTailSignal(mdast, contentLength) {
|
|
|
578
613
|
}
|
|
579
614
|
|
|
580
615
|
// src/aggregateFootnotes.ts
|
|
581
|
-
import { footnoteSafeId, lastMeaningfulIdx } from "@ai-markdown/engine";
|
|
616
|
+
import { footnoteSafeId as footnoteSafeId2, lastMeaningfulIdx } from "@ai-markdown/engine";
|
|
582
617
|
|
|
583
618
|
// src/cloneHastForRender.ts
|
|
584
619
|
function cloneHastForRender(node) {
|
|
@@ -649,6 +684,7 @@ function buildAggregateTree(registry, clobberPrefix, preserveOrphanReferences =
|
|
|
649
684
|
});
|
|
650
685
|
}
|
|
651
686
|
}
|
|
687
|
+
ordered.sort((a, b) => (a.n ?? 0) - (b.n ?? 0));
|
|
652
688
|
if (preserveOrphanReferences) {
|
|
653
689
|
for (const sym of registry.chunkOrder) {
|
|
654
690
|
const data = registry.chunkData.get(sym);
|
|
@@ -669,7 +705,7 @@ function buildAggregateTree(registry, clobberPrefix, preserveOrphanReferences =
|
|
|
669
705
|
}
|
|
670
706
|
if (ordered.length === 0) return null;
|
|
671
707
|
const liElements = ordered.map(({ normalizedLabel, sourceIdentifier, bodyHast, n, withBackref }) => {
|
|
672
|
-
const safeId =
|
|
708
|
+
const safeId = footnoteSafeId2(sourceIdentifier);
|
|
673
709
|
const liChildren = bodyHast.map((c) => cloneHastForRender(c));
|
|
674
710
|
if (withBackref) {
|
|
675
711
|
const totalRefs = registry.getRefsForLabel(normalizedLabel);
|
|
@@ -735,6 +771,7 @@ function buildAggregateTree(registry, clobberPrefix, preserveOrphanReferences =
|
|
|
735
771
|
|
|
736
772
|
// src/pipelineSession.ts
|
|
737
773
|
import {
|
|
774
|
+
EngineRawHtmlDepthError,
|
|
738
775
|
advanceIncrementalParse,
|
|
739
776
|
buildPhantomSuffix,
|
|
740
777
|
phantomSuffixCloser,
|
|
@@ -742,6 +779,30 @@ import {
|
|
|
742
779
|
transformStage
|
|
743
780
|
} from "@ai-markdown/engine";
|
|
744
781
|
var unmeasured = (_stage, fn) => fn();
|
|
782
|
+
function endPoint(text) {
|
|
783
|
+
let line = 1;
|
|
784
|
+
let lineStart = 0;
|
|
785
|
+
for (let i = 0; i < text.length; i++) {
|
|
786
|
+
const code = text.charCodeAt(i);
|
|
787
|
+
if (code === 10 || code === 13 && text.charCodeAt(i + 1) !== 10) {
|
|
788
|
+
line += 1;
|
|
789
|
+
lineStart = i + 1;
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
return { line, column: text.length - lineStart + 1, offset: text.length };
|
|
793
|
+
}
|
|
794
|
+
function plainTextTrees(content) {
|
|
795
|
+
const position = { start: { line: 1, column: 1, offset: 0 }, end: endPoint(content) };
|
|
796
|
+
const text = { type: "text", value: content, position };
|
|
797
|
+
return {
|
|
798
|
+
mdast: { type: "root", children: [{ type: "paragraph", children: [text], position }], position },
|
|
799
|
+
hast: {
|
|
800
|
+
type: "root",
|
|
801
|
+
children: [{ type: "element", tagName: "p", properties: {}, children: [text], position }],
|
|
802
|
+
position
|
|
803
|
+
}
|
|
804
|
+
};
|
|
805
|
+
}
|
|
745
806
|
function createPipelineSession() {
|
|
746
807
|
let state = null;
|
|
747
808
|
return {
|
|
@@ -783,19 +844,33 @@ function createPipelineSession() {
|
|
|
783
844
|
} : {
|
|
784
845
|
...remarkRehypeOptions
|
|
785
846
|
};
|
|
847
|
+
const fullPipeline = () => {
|
|
848
|
+
try {
|
|
849
|
+
const parsed = measureHere(
|
|
850
|
+
"parse",
|
|
851
|
+
() => parseStage({
|
|
852
|
+
children: augmented,
|
|
853
|
+
remarkPlugins,
|
|
854
|
+
rehypePlugins,
|
|
855
|
+
remarkRehypeOptions: mergedRemarkRehypeOptions
|
|
856
|
+
})
|
|
857
|
+
);
|
|
858
|
+
const hastRoot = measureHere("transform", () => transformStage(parsed));
|
|
859
|
+
return { mdast: parsed.mdast, hast: hastRoot };
|
|
860
|
+
} catch (error) {
|
|
861
|
+
if (!(error instanceof EngineRawHtmlDepthError)) throw error;
|
|
862
|
+
if (true) {
|
|
863
|
+
console.error(
|
|
864
|
+
"[ai-react-markdown] raw HTML nested past the engine depth bound \u2014 rendering this frame as plain text:",
|
|
865
|
+
error
|
|
866
|
+
);
|
|
867
|
+
}
|
|
868
|
+
return plainTextTrees(content ?? "");
|
|
869
|
+
}
|
|
870
|
+
};
|
|
786
871
|
if (!incrementalParse) {
|
|
787
872
|
state = null;
|
|
788
|
-
|
|
789
|
-
"parse",
|
|
790
|
-
() => parseStage({
|
|
791
|
-
children: augmented,
|
|
792
|
-
remarkPlugins,
|
|
793
|
-
rehypePlugins,
|
|
794
|
-
remarkRehypeOptions: mergedRemarkRehypeOptions
|
|
795
|
-
})
|
|
796
|
-
);
|
|
797
|
-
const hastRoot = measureHere("transform", () => transformStage(parsed));
|
|
798
|
-
return { mdast: parsed.mdast, hast: hastRoot };
|
|
873
|
+
return fullPipeline();
|
|
799
874
|
}
|
|
800
875
|
try {
|
|
801
876
|
const result = advanceIncrementalParse(state, content ?? "", {
|
|
@@ -818,7 +893,12 @@ function createPipelineSession() {
|
|
|
818
893
|
// Explicit even though `rehypePlugins` already carries it: a
|
|
819
894
|
// credential change must never reuse trees stamped under the
|
|
820
895
|
// old one.
|
|
821
|
-
provenance
|
|
896
|
+
provenance,
|
|
897
|
+
// The boundary scanner's grammar profile. The scan checkpoint
|
|
898
|
+
// already refuses to resume under a different profile, but the
|
|
899
|
+
// retained TREES were still spliced against — a prefix frozen
|
|
900
|
+
// under one profile must not survive into frames under the other.
|
|
901
|
+
defListEnabled
|
|
822
902
|
],
|
|
823
903
|
defListEnabled,
|
|
824
904
|
phantomSuffix,
|
|
@@ -831,17 +911,7 @@ function createPipelineSession() {
|
|
|
831
911
|
if (true) {
|
|
832
912
|
console.error("[ai-react-markdown] incremental parse failed \u2014 full parse fallback for this frame:", error);
|
|
833
913
|
}
|
|
834
|
-
|
|
835
|
-
"parse",
|
|
836
|
-
() => parseStage({
|
|
837
|
-
children: augmented,
|
|
838
|
-
remarkPlugins,
|
|
839
|
-
rehypePlugins,
|
|
840
|
-
remarkRehypeOptions: mergedRemarkRehypeOptions
|
|
841
|
-
})
|
|
842
|
-
);
|
|
843
|
-
const hastRoot = measureHere("transform", () => transformStage(parsed));
|
|
844
|
-
return { mdast: parsed.mdast, hast: hastRoot };
|
|
914
|
+
return fullPipeline();
|
|
845
915
|
}
|
|
846
916
|
}
|
|
847
917
|
};
|