@mikedown/core 0.2.0 → 0.4.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.
Files changed (42) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +121 -2
  3. package/dist/ai/engines-page.d.ts +137 -0
  4. package/dist/ai/engines-page.js +11 -0
  5. package/dist/ai/engines-page.js.map +1 -0
  6. package/dist/ai/index.d.ts +2722 -0
  7. package/dist/ai/index.js +684 -0
  8. package/dist/ai/index.js.map +1 -0
  9. package/dist/ai-ui-QFYFN73D.js +6397 -0
  10. package/dist/ai-ui-QFYFN73D.js.map +1 -0
  11. package/dist/chunk-APPBNQEY.js +216 -0
  12. package/dist/chunk-APPBNQEY.js.map +1 -0
  13. package/dist/chunk-DWXGWVA3.js +5748 -0
  14. package/dist/chunk-DWXGWVA3.js.map +1 -0
  15. package/dist/chunk-GWCRPPCX.js +18 -0
  16. package/dist/chunk-GWCRPPCX.js.map +1 -0
  17. package/dist/chunk-IWCXWUWW.js +6958 -0
  18. package/dist/chunk-IWCXWUWW.js.map +1 -0
  19. package/dist/chunk-L4FO63DF.js +113 -0
  20. package/dist/chunk-L4FO63DF.js.map +1 -0
  21. package/dist/chunk-N4N54LK2.js +39 -0
  22. package/dist/chunk-N4N54LK2.js.map +1 -0
  23. package/dist/chunk-QWKT57TR.js +62 -0
  24. package/dist/chunk-QWKT57TR.js.map +1 -0
  25. package/dist/chunk-TSP7BAV3.js +22 -0
  26. package/dist/chunk-TSP7BAV3.js.map +1 -0
  27. package/dist/index.d.ts +19 -463
  28. package/dist/index.js +7717 -2103
  29. package/dist/index.js.map +1 -1
  30. package/dist/schema-DVfssxQX.d.ts +100 -0
  31. package/dist/shared/anchoring.js +4 -16
  32. package/dist/shared/anchoring.js.map +1 -1
  33. package/dist/shared/imagePaste.js +3 -57
  34. package/dist/shared/imagePaste.js.map +1 -1
  35. package/dist/shared/sha1.js +3 -57
  36. package/dist/shared/sha1.js.map +1 -1
  37. package/dist/shared/wordCount.js +4 -12
  38. package/dist/shared/wordCount.js.map +1 -1
  39. package/dist/styles.css +4562 -108
  40. package/dist/types-2TZErbJr.d.ts +619 -0
  41. package/dist/types-DO8UBybZ.d.ts +741 -0
  42. package/package.json +11 -1
@@ -0,0 +1,113 @@
1
+ // src/portal.ts
2
+ var portalEl = null;
3
+ var source = null;
4
+ function getPortal() {
5
+ if (!portalEl || !portalEl.isConnected) {
6
+ portalEl = document.createElement("div");
7
+ portalEl.className = "mikedown-portal";
8
+ document.body.appendChild(portalEl);
9
+ syncPortal();
10
+ }
11
+ return portalEl;
12
+ }
13
+ function setPortalSource(root) {
14
+ source = root;
15
+ syncPortal();
16
+ }
17
+ function releasePortalSource(root) {
18
+ if (source === root) {
19
+ source = null;
20
+ }
21
+ }
22
+ function syncPortal() {
23
+ if (!portalEl || !source) {
24
+ return;
25
+ }
26
+ const theme = source.getAttribute("data-mikedown-theme");
27
+ if (theme) {
28
+ portalEl.setAttribute("data-mikedown-theme", theme);
29
+ } else {
30
+ portalEl.removeAttribute("data-mikedown-theme");
31
+ }
32
+ portalEl.style.cssText = source.style.cssText;
33
+ }
34
+
35
+ // src/ai-rewrite-highlight.ts
36
+ import { Extension } from "@tiptap/core";
37
+ import { Plugin, PluginKey } from "@tiptap/pm/state";
38
+ import { Decoration, DecorationSet } from "@tiptap/pm/view";
39
+ import { StateEffect, StateField } from "@codemirror/state";
40
+ import { Decoration as CmDecoration, EditorView as CmEditorView } from "@codemirror/view";
41
+ var aiRewriteHighlightKey = new PluginKey("mikedownAiRewriteHighlight");
42
+ var AiRewriteHighlight = Extension.create({
43
+ name: "mikedownAiRewriteHighlight",
44
+ addProseMirrorPlugins() {
45
+ return [new Plugin({
46
+ key: aiRewriteHighlightKey,
47
+ state: {
48
+ init: () => null,
49
+ apply(tr, value) {
50
+ const meta = tr.getMeta(aiRewriteHighlightKey);
51
+ if (meta) {
52
+ return meta.range;
53
+ }
54
+ if (!value || !tr.docChanged) {
55
+ return value;
56
+ }
57
+ if (value.anchor) {
58
+ const p = tr.mapping.map(value.from, -1);
59
+ return { ...value, from: p, to: p };
60
+ }
61
+ const from = tr.mapping.map(value.from, 1);
62
+ const to = tr.mapping.map(value.to, -1);
63
+ return to > from ? { from, to, id: value.id } : null;
64
+ }
65
+ },
66
+ props: {
67
+ decorations(state) {
68
+ const r = aiRewriteHighlightKey.getState(state);
69
+ if (!r || r.to <= r.from) {
70
+ return null;
71
+ }
72
+ return DecorationSet.create(state.doc, [Decoration.inline(r.from, r.to, { class: "mikedown-ai-rewrite-target" })]);
73
+ }
74
+ }
75
+ })];
76
+ }
77
+ });
78
+ var setCmRewriteRange = StateEffect.define();
79
+ var cmRewriteRange = StateField.define({
80
+ create: () => null,
81
+ update(value, tr) {
82
+ for (const e of tr.effects) {
83
+ if (e.is(setCmRewriteRange)) {
84
+ return e.value;
85
+ }
86
+ }
87
+ if (!value || !tr.docChanged) {
88
+ return value;
89
+ }
90
+ if (value.anchor) {
91
+ const p = tr.changes.mapPos(value.from, -1);
92
+ return { ...value, from: p, to: p };
93
+ }
94
+ const from = tr.changes.mapPos(value.from, 1);
95
+ const to = tr.changes.mapPos(value.to, -1);
96
+ return to > from ? { from, to, id: value.id } : null;
97
+ },
98
+ provide: (f) => CmEditorView.decorations.from(f, (r) => r && r.to > r.from ? CmDecoration.set([CmDecoration.mark({ class: "mikedown-ai-rewrite-target" }).range(r.from, r.to)]) : CmDecoration.none)
99
+ });
100
+ var cmAiRewriteHighlight = [cmRewriteRange];
101
+
102
+ export {
103
+ getPortal,
104
+ setPortalSource,
105
+ releasePortalSource,
106
+ syncPortal,
107
+ aiRewriteHighlightKey,
108
+ AiRewriteHighlight,
109
+ setCmRewriteRange,
110
+ cmRewriteRange,
111
+ cmAiRewriteHighlight
112
+ };
113
+ //# sourceMappingURL=chunk-L4FO63DF.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/portal.ts","../src/ai-rewrite-highlight.ts"],"sourcesContent":["/**\n * Overlay portal.\n *\n * Menus, pickers and dialogs that must escape the editor box (slash menu,\n * context menu, emoji picker, settings dialog, ...) are appended to a single\n * `<div class=\"mikedown-portal\">` on `<body>` instead of to `<body>` itself.\n * The core CSS is scoped to `.mikedown-root` and `.mikedown-portal`, so this is\n * what lets those overlays be styled without the stylesheet touching the host\n * page. The portal is `display: contents` (no box of its own).\n *\n * The portal copies the theme attribute and inline CSS variables of the editor\n * root that last asked for it (the focused or most recently themed editor), so\n * overlays share that editor's tokens and fonts.\n */\n\nlet portalEl: HTMLElement | null = null;\nlet source: HTMLElement | null = null;\n\n/** The portal element, created on first use (and again if something removed it). */\nexport function getPortal(): HTMLElement {\n if (!portalEl || !portalEl.isConnected) {\n portalEl = document.createElement('div');\n portalEl.className = 'mikedown-portal';\n document.body.appendChild(portalEl);\n syncPortal();\n }\n return portalEl;\n}\n\n/** Make `root` the editor whose theme the portal mirrors, and mirror it now. */\nexport function setPortalSource(root: HTMLElement): void {\n source = root;\n syncPortal();\n}\n\n/** Forget `root` as the portal's source (on destroy). */\nexport function releasePortalSource(root: HTMLElement): void {\n if (source === root) {source = null;}\n}\n\n/** Copy the source root's theme attribute and inline variables onto the portal. */\nexport function syncPortal(): void {\n if (!portalEl || !source) {return;}\n const theme = source.getAttribute('data-mikedown-theme');\n if (theme) {portalEl.setAttribute('data-mikedown-theme', theme);}\n else {portalEl.removeAttribute('data-mikedown-theme');}\n portalEl.style.cssText = source.style.cssText;\n}\n","/**\n * The rewrite target highlight (a PM plugin in rich text, a CM state field in\n * source mode). Kept apart from the popover in `ai-rewrite.ts` because the\n * editor adds both extensions when it is built, while the rest of the AI UI\n * loads on demand (`ai-lite.ts`).\n */\n\nimport { Extension } from '@tiptap/core';\nimport { Plugin, PluginKey } from '@tiptap/pm/state';\nimport { Decoration, DecorationSet } from '@tiptap/pm/view';\nimport { StateEffect, StateField } from '@codemirror/state';\nimport { Decoration as CmDecoration, EditorView as CmEditorView } from '@codemirror/view';\n\n/**\n * A target range; `id` tells one open target from the next. An `anchor` is\n * a caret position (from === to) that follows edits and is never dropped.\n */\nexport interface Range { from: number; to: number; id: number; anchor?: boolean }\n\n// ── Target highlight: rich text ─────────────────────────────────────────────\n\nexport const aiRewriteHighlightKey = new PluginKey<Range | null>('mikedownAiRewriteHighlight');\n\n/** Marks the rewrite target while the popover is open; the range follows edits. */\nexport const AiRewriteHighlight = Extension.create({\n name: 'mikedownAiRewriteHighlight',\n addProseMirrorPlugins() {\n return [new Plugin<Range | null>({\n key: aiRewriteHighlightKey,\n state: {\n init: () => null,\n apply(tr, value) {\n const meta = tr.getMeta(aiRewriteHighlightKey) as { range: Range | null } | undefined;\n if (meta) {return meta.range;}\n if (!value || !tr.docChanged) {return value;}\n if (value.anchor) {\n const p = tr.mapping.map(value.from, -1);\n return { ...value, from: p, to: p };\n }\n const from = tr.mapping.map(value.from, 1);\n const to = tr.mapping.map(value.to, -1);\n return to > from ? { from, to, id: value.id } : null;\n },\n },\n props: {\n decorations(state) {\n const r = aiRewriteHighlightKey.getState(state);\n if (!r || r.to <= r.from) {return null;}\n return DecorationSet.create(state.doc, [Decoration.inline(r.from, r.to, { class: 'mikedown-ai-rewrite-target' })]);\n },\n },\n })];\n },\n});\n\n// ── Target highlight: source mode ───────────────────────────────────────────\n\nexport const setCmRewriteRange = StateEffect.define<Range | null>();\n\nexport const cmRewriteRange = StateField.define<Range | null>({\n create: () => null,\n update(value, tr) {\n for (const e of tr.effects) {if (e.is(setCmRewriteRange)) {return e.value;}}\n if (!value || !tr.docChanged) {return value;}\n if (value.anchor) {\n const p = tr.changes.mapPos(value.from, -1);\n return { ...value, from: p, to: p };\n }\n const from = tr.changes.mapPos(value.from, 1);\n const to = tr.changes.mapPos(value.to, -1);\n return to > from ? { from, to, id: value.id } : null;\n },\n provide: (f) => CmEditorView.decorations.from(f, (r) => (r && r.to > r.from\n ? CmDecoration.set([CmDecoration.mark({ class: 'mikedown-ai-rewrite-target' }).range(r.from, r.to)])\n : CmDecoration.none)),\n});\n\n/** Add to the source view's extensions. */\nexport const cmAiRewriteHighlight = [cmRewriteRange];\n"],"mappings":"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","names":[]}
@@ -0,0 +1,39 @@
1
+ // src/ai-lite.ts
2
+ var aiUi = null;
3
+ var loading = null;
4
+ function loadedAiUi() {
5
+ return aiUi;
6
+ }
7
+ function loadAiUi() {
8
+ if (aiUi) {
9
+ return Promise.resolve(aiUi);
10
+ }
11
+ loading ?? (loading = import("./ai-ui-QFYFN73D.js").then(
12
+ (m) => {
13
+ aiUi = m;
14
+ return m;
15
+ },
16
+ (err) => {
17
+ loading = null;
18
+ throw err;
19
+ }
20
+ ));
21
+ return loading;
22
+ }
23
+ function aiHostTier(ai) {
24
+ return typeof ai.listEngines === "function" ? 2 : 1;
25
+ }
26
+ function aiToolbarButtonMode(hasAiHost, settings) {
27
+ if (!hasAiHost || !settings.showToolbarButton) {
28
+ return "hidden";
29
+ }
30
+ return settings.enabled ? "menu" : "firstRun";
31
+ }
32
+
33
+ export {
34
+ loadedAiUi,
35
+ loadAiUi,
36
+ aiHostTier,
37
+ aiToolbarButtonMode
38
+ };
39
+ //# sourceMappingURL=chunk-N4N54LK2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/ai-lite.ts"],"sourcesContent":["/**\n * The little of the AI layer the editor needs before the AI UI is loaded,\n * and the loader for the rest.\n *\n * Everything behind `host.ai` (the rewrite popover, the AI settings tab and\n * Engines page, the toolbar menu, the prompts and the router) lives in\n * `ai-ui.ts`, which the editor imports with `import()` only when the host has\n * an AI adapter. Bundlers split it into its own chunk, so an editor without\n * AI never downloads it. A host that wants it in its main bundle, loaded\n * synchronously (the VS Code webview), imports `ai-ui-eager.ts` once.\n */\n\nimport type { AiSettings, MikeDownAiHost } from './ai/types';\n\n// Types only: the recorder itself is in the lazy chunk (`ai-ui.ts`).\nexport type {\n AiActivityEntry, AiActivityLog, AiActivityPatch, AiActivityResponse, AiActivityRoute, AiActivityStatus,\n} from './ai-activity';\n\nexport type AiUi = typeof import('./ai-ui');\n\nlet aiUi: AiUi | null = null;\nlet loading: Promise<AiUi> | null = null;\n\n/** The AI UI when it is already loaded (or registered), else null. */\nexport function loadedAiUi(): AiUi | null {\n return aiUi;\n}\n\n/** Load the AI UI chunk once; a failed load is tried again on the next call. */\nexport function loadAiUi(): Promise<AiUi> {\n if (aiUi) {return Promise.resolve(aiUi);}\n loading ??= import('./ai-ui').then(\n (m) => { aiUi = m; return m; },\n (err: unknown) => { loading = null; throw err; },\n );\n return loading;\n}\n\n/** Make the AI UI available synchronously (`ai-ui-eager.ts`); null forgets it (tests). */\nexport function registerAiUi(m: AiUi | null): void {\n aiUi = m;\n loading = null;\n}\n\n// ── Host tier ───────────────────────────────────────────────────────────────\n\n/** 1: `complete` only, the host routes. 2: the host has an engine registry and core routes. */\nexport type AiHostTier = 1 | 2;\n\nexport function aiHostTier(ai: MikeDownAiHost): AiHostTier {\n return typeof ai.listEngines === 'function' ? 2 : 1;\n}\n\n// ── Toolbar button ──────────────────────────────────────────────────────────\n\nexport type AiToolbarButtonMode = 'hidden' | 'firstRun' | 'menu';\n\n/** What the button does: hidden without AI support or when turned off in settings. */\nexport function aiToolbarButtonMode(hasAiHost: boolean, settings: Pick<AiSettings, 'enabled' | 'showToolbarButton'>): AiToolbarButtonMode {\n if (!hasAiHost || !settings.showToolbarButton) {return 'hidden';}\n return settings.enabled ? 'menu' : 'firstRun';\n}\n"],"mappings":";AAqBA,IAAI,OAAoB;AACxB,IAAI,UAAgC;AAG7B,SAAS,aAA0B;AACxC,SAAO;AACT;AAGO,SAAS,WAA0B;AACxC,MAAI,MAAM;AAAC,WAAO,QAAQ,QAAQ,IAAI;AAAA,EAAE;AACxC,wBAAY,OAAO,qBAAS,EAAE;AAAA,IAC5B,CAAC,MAAM;AAAE,aAAO;AAAG,aAAO;AAAA,IAAG;AAAA,IAC7B,CAAC,QAAiB;AAAE,gBAAU;AAAM,YAAM;AAAA,IAAK;AAAA,EACjD;AACA,SAAO;AACT;AAaO,SAAS,WAAW,IAAgC;AACzD,SAAO,OAAO,GAAG,gBAAgB,aAAa,IAAI;AACpD;AAOO,SAAS,oBAAoB,WAAoB,UAAkF;AACxI,MAAI,CAAC,aAAa,CAAC,SAAS,mBAAmB;AAAC,WAAO;AAAA,EAAS;AAChE,SAAO,SAAS,UAAU,SAAS;AACrC;","names":[]}
@@ -0,0 +1,62 @@
1
+ // src/shared/sha1.ts
2
+ function rotl(x, n) {
3
+ return x << n | x >>> 32 - n;
4
+ }
5
+ function sha1Hex(data) {
6
+ const len = data.length;
7
+ const padded = new Uint8Array((len + 8 >> 6) + 1 << 6);
8
+ padded.set(data);
9
+ padded[len] = 128;
10
+ const view = new DataView(padded.buffer);
11
+ view.setUint32(padded.length - 8, Math.floor(len / 536870912));
12
+ view.setUint32(padded.length - 4, len * 8 >>> 0);
13
+ let h0 = 1732584193;
14
+ let h1 = 4023233417;
15
+ let h2 = 2562383102;
16
+ let h3 = 271733878;
17
+ let h4 = 3285377520;
18
+ const w = new Uint32Array(80);
19
+ for (let off = 0; off < padded.length; off += 64) {
20
+ for (let i = 0; i < 16; i++) {
21
+ w[i] = view.getUint32(off + i * 4);
22
+ }
23
+ for (let i = 16; i < 80; i++) {
24
+ w[i] = rotl(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16], 1);
25
+ }
26
+ let a = h0, b = h1, c = h2, d = h3, e = h4;
27
+ for (let i = 0; i < 80; i++) {
28
+ let f;
29
+ let k;
30
+ if (i < 20) {
31
+ f = b & c | ~b & d;
32
+ k = 1518500249;
33
+ } else if (i < 40) {
34
+ f = b ^ c ^ d;
35
+ k = 1859775393;
36
+ } else if (i < 60) {
37
+ f = b & c | b & d | c & d;
38
+ k = 2400959708;
39
+ } else {
40
+ f = b ^ c ^ d;
41
+ k = 3395469782;
42
+ }
43
+ const t = rotl(a, 5) + f + e + k + w[i] >>> 0;
44
+ e = d;
45
+ d = c;
46
+ c = rotl(b, 30) >>> 0;
47
+ b = a;
48
+ a = t;
49
+ }
50
+ h0 = h0 + a >>> 0;
51
+ h1 = h1 + b >>> 0;
52
+ h2 = h2 + c >>> 0;
53
+ h3 = h3 + d >>> 0;
54
+ h4 = h4 + e >>> 0;
55
+ }
56
+ return [h0, h1, h2, h3, h4].map((h) => h.toString(16).padStart(8, "0")).join("");
57
+ }
58
+
59
+ export {
60
+ sha1Hex
61
+ };
62
+ //# sourceMappingURL=chunk-QWKT57TR.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/shared/sha1.ts"],"sourcesContent":["// Pure, synchronous SHA-1 over bytes. No node:crypto, so it runs in the\n// webview, a Tauri webview, and Node alike. Used only for the image-paste\n// `${hash}` token and hash-dedupe (content fingerprinting, not security);\n// hosts with a native hash (Node `crypto`) can inject theirs instead.\n\nfunction rotl(x: number, n: number): number {\n return (x << n) | (x >>> (32 - n));\n}\n\nexport function sha1Hex(data: Uint8Array): string {\n const len = data.length;\n const padded = new Uint8Array((((len + 8) >> 6) + 1) << 6);\n padded.set(data);\n padded[len] = 0x80;\n const view = new DataView(padded.buffer);\n // 64-bit big-endian bit length.\n view.setUint32(padded.length - 8, Math.floor(len / 0x20000000));\n view.setUint32(padded.length - 4, (len * 8) >>> 0);\n\n let h0 = 0x67452301;\n let h1 = 0xefcdab89;\n let h2 = 0x98badcfe;\n let h3 = 0x10325476;\n let h4 = 0xc3d2e1f0;\n const w = new Uint32Array(80);\n\n for (let off = 0; off < padded.length; off += 64) {\n for (let i = 0; i < 16; i++) {w[i] = view.getUint32(off + i * 4);}\n for (let i = 16; i < 80; i++) {w[i] = rotl(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16], 1);}\n let a = h0, b = h1, c = h2, d = h3, e = h4;\n for (let i = 0; i < 80; i++) {\n let f: number;\n let k: number;\n if (i < 20) { f = (b & c) | (~b & d); k = 0x5a827999; }\n else if (i < 40) { f = b ^ c ^ d; k = 0x6ed9eba1; }\n else if (i < 60) { f = (b & c) | (b & d) | (c & d); k = 0x8f1bbcdc; }\n else { f = b ^ c ^ d; k = 0xca62c1d6; }\n const t = (rotl(a, 5) + f + e + k + w[i]) >>> 0;\n e = d; d = c; c = rotl(b, 30) >>> 0; b = a; a = t;\n }\n h0 = (h0 + a) >>> 0;\n h1 = (h1 + b) >>> 0;\n h2 = (h2 + c) >>> 0;\n h3 = (h3 + d) >>> 0;\n h4 = (h4 + e) >>> 0;\n }\n return [h0, h1, h2, h3, h4].map(h => h.toString(16).padStart(8, '0')).join('');\n}\n"],"mappings":";AAKA,SAAS,KAAK,GAAW,GAAmB;AAC1C,SAAQ,KAAK,IAAM,MAAO,KAAK;AACjC;AAEO,SAAS,QAAQ,MAA0B;AAChD,QAAM,MAAM,KAAK;AACjB,QAAM,SAAS,IAAI,YAAc,MAAM,KAAM,KAAK,KAAM,CAAC;AACzD,SAAO,IAAI,IAAI;AACf,SAAO,GAAG,IAAI;AACd,QAAM,OAAO,IAAI,SAAS,OAAO,MAAM;AAEvC,OAAK,UAAU,OAAO,SAAS,GAAG,KAAK,MAAM,MAAM,SAAU,CAAC;AAC9D,OAAK,UAAU,OAAO,SAAS,GAAI,MAAM,MAAO,CAAC;AAEjD,MAAI,KAAK;AACT,MAAI,KAAK;AACT,MAAI,KAAK;AACT,MAAI,KAAK;AACT,MAAI,KAAK;AACT,QAAM,IAAI,IAAI,YAAY,EAAE;AAE5B,WAAS,MAAM,GAAG,MAAM,OAAO,QAAQ,OAAO,IAAI;AAChD,aAAS,IAAI,GAAG,IAAI,IAAI,KAAK;AAAC,QAAE,CAAC,IAAI,KAAK,UAAU,MAAM,IAAI,CAAC;AAAA,IAAE;AACjE,aAAS,IAAI,IAAI,IAAI,IAAI,KAAK;AAAC,QAAE,CAAC,IAAI,KAAK,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC;AAAA,IAAE;AAC3F,QAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI;AACxC,aAAS,IAAI,GAAG,IAAI,IAAI,KAAK;AAC3B,UAAI;AACJ,UAAI;AACJ,UAAI,IAAI,IAAI;AAAE,YAAK,IAAI,IAAM,CAAC,IAAI;AAAI,YAAI;AAAA,MAAY,WAC7C,IAAI,IAAI;AAAE,YAAI,IAAI,IAAI;AAAG,YAAI;AAAA,MAAY,WACzC,IAAI,IAAI;AAAE,YAAK,IAAI,IAAM,IAAI,IAAM,IAAI;AAAI,YAAI;AAAA,MAAY,OAC/D;AAAE,YAAI,IAAI,IAAI;AAAG,YAAI;AAAA,MAAY;AACtC,YAAM,IAAK,KAAK,GAAG,CAAC,IAAI,IAAI,IAAI,IAAI,EAAE,CAAC,MAAO;AAC9C,UAAI;AAAG,UAAI;AAAG,UAAI,KAAK,GAAG,EAAE,MAAM;AAAG,UAAI;AAAG,UAAI;AAAA,IAClD;AACA,SAAM,KAAK,MAAO;AAClB,SAAM,KAAK,MAAO;AAClB,SAAM,KAAK,MAAO;AAClB,SAAM,KAAK,MAAO;AAClB,SAAM,KAAK,MAAO;AAAA,EACpB;AACA,SAAO,CAAC,IAAI,IAAI,IAAI,IAAI,EAAE,EAAE,IAAI,OAAK,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC,EAAE,KAAK,EAAE;AAC/E;","names":[]}
@@ -0,0 +1,22 @@
1
+ // src/shared/anchoring.ts
2
+ function githubAnchorId(text) {
3
+ return text.toLowerCase().trim().replace(/[^\w\s-]/g, "").replace(/\s/g, "-");
4
+ }
5
+ function dedupedAnchorIdAt(headingTexts, index) {
6
+ const seen = /* @__PURE__ */ new Map();
7
+ for (let i = 0; i < headingTexts.length; i++) {
8
+ const base = githubAnchorId(headingTexts[i]);
9
+ const count = seen.get(base) ?? 0;
10
+ seen.set(base, count + 1);
11
+ if (i === index) {
12
+ return count === 0 ? base : `${base}-${count}`;
13
+ }
14
+ }
15
+ return "";
16
+ }
17
+
18
+ export {
19
+ githubAnchorId,
20
+ dedupedAnchorIdAt
21
+ };
22
+ //# sourceMappingURL=chunk-TSP7BAV3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/shared/anchoring.ts"],"sourcesContent":["// Shared GitHub-style anchor slug generation.\n//\n// IMPORTANT: this module must be importable by BOTH webpack bundles — the\n// extension host (node target, tsconfig.json) and the webview (web target,\n// tsconfig.webview.json). Keep it dependency-free: no `vscode`, no `node:*`,\n// no DOM. (Same rule as imageDisplayPath.ts.) The \"Heading Rename → Fix Links\"\n// feature relies on host and webview computing byte-identical slugs.\n\n/**\n * Convert heading text to a GitHub-style anchor id (the \"base\" slug, before any\n * duplicate-disambiguation suffix).\n *\n * Match GitHub exactly: strip punctuation, then turn each whitespace char into a\n * hyphen. Do NOT collapse consecutive hyphens or trim trailing ones — GitHub\n * keeps them (e.g. \"Memory & Hardware\" → \"memory--hardware\", \"UD-\" → \"ud-\").\n */\nexport function githubAnchorId(text: string): string {\n return text\n .toLowerCase()\n .trim()\n .replace(/[^\\w\\s-]/g, '') // remove punctuation (keep word chars, whitespace, hyphens)\n .replace(/\\s/g, '-'); // each whitespace char → hyphen (preserve consecutive)\n}\n\n/**\n * Given heading texts in document order, return the deduplicated anchor id for\n * the heading at `index`, using GitHub's encounter-order suffixing\n * (`setup`, `setup-1`, `setup-2`, …). The first occurrence keeps the base slug.\n */\nexport function dedupedAnchorIdAt(headingTexts: string[], index: number): string {\n const seen = new Map<string, number>();\n for (let i = 0; i < headingTexts.length; i++) {\n const base = githubAnchorId(headingTexts[i]);\n const count = seen.get(base) ?? 0;\n seen.set(base, count + 1);\n if (i === index) {return count === 0 ? base : `${base}-${count}`;}\n }\n return '';\n}\n"],"mappings":";AAgBO,SAAS,eAAe,MAAsB;AACnD,SAAO,KACJ,YAAY,EACZ,KAAK,EACL,QAAQ,aAAa,EAAE,EACvB,QAAQ,OAAO,GAAG;AACvB;AAOO,SAAS,kBAAkB,cAAwB,OAAuB;AAC/E,QAAM,OAAO,oBAAI,IAAoB;AACrC,WAAS,IAAI,GAAG,IAAI,aAAa,QAAQ,KAAK;AAC5C,UAAM,OAAO,eAAe,aAAa,CAAC,CAAC;AAC3C,UAAM,QAAQ,KAAK,IAAI,IAAI,KAAK;AAChC,SAAK,IAAI,MAAM,QAAQ,CAAC;AACxB,QAAI,MAAM,OAAO;AAAC,aAAO,UAAU,IAAI,OAAO,GAAG,IAAI,IAAI,KAAK;AAAA,IAAG;AAAA,EACnE;AACA,SAAO;AACT;","names":[]}