@markup-carve/carve-lsp 0.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.
Files changed (63) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +120 -0
  3. package/dist/analyze.d.ts +6 -0
  4. package/dist/analyze.js +156 -0
  5. package/dist/analyze.js.map +1 -0
  6. package/dist/analyze.test.d.ts +1 -0
  7. package/dist/analyze.test.js +207 -0
  8. package/dist/analyze.test.js.map +1 -0
  9. package/dist/codelens.d.ts +7 -0
  10. package/dist/codelens.js +36 -0
  11. package/dist/codelens.js.map +1 -0
  12. package/dist/codelens.test.d.ts +1 -0
  13. package/dist/codelens.test.js +18 -0
  14. package/dist/codelens.test.js.map +1 -0
  15. package/dist/completion.d.ts +9 -0
  16. package/dist/completion.js +91 -0
  17. package/dist/completion.js.map +1 -0
  18. package/dist/completion.test.d.ts +1 -0
  19. package/dist/completion.test.js +35 -0
  20. package/dist/completion.test.js.map +1 -0
  21. package/dist/definition.d.ts +12 -0
  22. package/dist/definition.js +280 -0
  23. package/dist/definition.js.map +1 -0
  24. package/dist/definition.test.d.ts +1 -0
  25. package/dist/definition.test.js +136 -0
  26. package/dist/definition.test.js.map +1 -0
  27. package/dist/folding.d.ts +8 -0
  28. package/dist/folding.js +64 -0
  29. package/dist/folding.js.map +1 -0
  30. package/dist/folding.test.d.ts +1 -0
  31. package/dist/folding.test.js +20 -0
  32. package/dist/folding.test.js.map +1 -0
  33. package/dist/format.d.ts +1 -0
  34. package/dist/format.js +83 -0
  35. package/dist/format.js.map +1 -0
  36. package/dist/format.test.d.ts +1 -0
  37. package/dist/format.test.js +46 -0
  38. package/dist/format.test.js.map +1 -0
  39. package/dist/hover.d.ts +2 -0
  40. package/dist/hover.js +222 -0
  41. package/dist/hover.js.map +1 -0
  42. package/dist/migration-actions.d.ts +15 -0
  43. package/dist/migration-actions.js +79 -0
  44. package/dist/migration-actions.js.map +1 -0
  45. package/dist/references.d.ts +15 -0
  46. package/dist/references.js +430 -0
  47. package/dist/references.js.map +1 -0
  48. package/dist/references.test.d.ts +1 -0
  49. package/dist/references.test.js +159 -0
  50. package/dist/references.test.js.map +1 -0
  51. package/dist/rename.d.ts +8 -0
  52. package/dist/rename.js +66 -0
  53. package/dist/rename.js.map +1 -0
  54. package/dist/rename.test.d.ts +1 -0
  55. package/dist/rename.test.js +39 -0
  56. package/dist/rename.test.js.map +1 -0
  57. package/dist/semantic.d.ts +15 -0
  58. package/dist/semantic.js +458 -0
  59. package/dist/semantic.js.map +1 -0
  60. package/dist/server.d.ts +2 -0
  61. package/dist/server.js +111 -0
  62. package/dist/server.js.map +1 -0
  63. package/package.json +49 -0
@@ -0,0 +1,91 @@
1
+ import { CompletionItemKind, } from 'vscode-languageserver/node.js';
2
+ import { parse, resolve } from '@markup-carve/carve';
3
+ /** The eight canonical admonition kinds (grammar PART 9 §12, Tier 1). */
4
+ const ADMONITIONS = ['note', 'tip', 'warning', 'danger', 'info', 'success', 'example', 'quote'];
5
+ /**
6
+ * Context-aware completions driven by the text immediately before the cursor:
7
+ * - `::: ` opens an admonition -> canonical kinds
8
+ * - `</#` cross-reference -> heading ids in the document
9
+ * - `[^` footnote reference -> defined footnote labels
10
+ * - `][` reference link -> defined link reference labels
11
+ */
12
+ export function completionAt(source, position) {
13
+ const line = source.split(/\r?\n/)[position.line] ?? '';
14
+ const prefix = line.slice(0, position.character);
15
+ let match;
16
+ if ((match = /:::\s*([\w-]*)$/.exec(prefix))) {
17
+ return ADMONITIONS.map((kind) => completion(kind, CompletionItemKind.Keyword, match[1], position, 'Admonition kind'));
18
+ }
19
+ if ((match = /<\/#([\w-]*)$/.exec(prefix))) {
20
+ return headingIds(source).map((id) => completion(id, CompletionItemKind.Reference, match[1], position, 'Heading id'));
21
+ }
22
+ if ((match = /\[\^([\w-]*)$/.exec(prefix))) {
23
+ return footnoteLabels(source).map((label) => completion(label, CompletionItemKind.Reference, match[1], position, 'Footnote'));
24
+ }
25
+ if ((match = /\]\[([\w-]*)$/.exec(prefix))) {
26
+ return linkReferenceLabels(source).map((label) => completion(label, CompletionItemKind.Reference, match[1], position, 'Link reference'));
27
+ }
28
+ return [];
29
+ }
30
+ function completion(value, kind, partial, position, detail) {
31
+ return {
32
+ label: value,
33
+ kind,
34
+ detail,
35
+ // Replace the partial token the user already typed so values containing
36
+ // `-` or `#` are not mangled by the editor's default word range.
37
+ textEdit: {
38
+ range: {
39
+ start: { line: position.line, character: position.character - partial.length },
40
+ end: position,
41
+ },
42
+ newText: value,
43
+ },
44
+ };
45
+ }
46
+ function headingIds(source) {
47
+ const ids = [];
48
+ try {
49
+ const doc = resolve(parse(source));
50
+ walkBlocks(doc.children, (node) => {
51
+ if (node.type === 'heading' && node.attrs?.id)
52
+ ids.push(node.attrs.id);
53
+ });
54
+ }
55
+ catch {
56
+ // Parsing may fail mid-edit; offer no ids rather than throwing.
57
+ }
58
+ return [...new Set(ids)];
59
+ }
60
+ function footnoteLabels(source) {
61
+ try {
62
+ const doc = resolve(parse(source));
63
+ return Object.keys(doc.footnoteDefs ?? {});
64
+ }
65
+ catch {
66
+ return [];
67
+ }
68
+ }
69
+ /** Scrape `[label]: url` reference definitions straight from the source. */
70
+ function linkReferenceLabels(source) {
71
+ const labels = new Set();
72
+ for (const line of source.split(/\r?\n/)) {
73
+ const match = /^\s{0,3}\[([^\]]+)\]:\s+\S/.exec(line);
74
+ // `[^label]:` is a footnote definition, not a link reference definition.
75
+ if (match && !match[1].startsWith('^'))
76
+ labels.add(match[1]);
77
+ }
78
+ return [...labels];
79
+ }
80
+ function walkBlocks(nodes, visit) {
81
+ for (const node of nodes) {
82
+ visit(node);
83
+ if ('children' in node && Array.isArray(node.children)) {
84
+ walkBlocks(node.children.filter(isBlockNode), visit);
85
+ }
86
+ }
87
+ }
88
+ function isBlockNode(node) {
89
+ return Boolean(node && typeof node === 'object' && 'type' in node);
90
+ }
91
+ //# sourceMappingURL=completion.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"completion.js","sourceRoot":"","sources":["../src/completion.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,35 @@
1
+ import assert from 'node:assert/strict';
2
+ import test from 'node:test';
3
+ import { completionAt } from './completion.js';
4
+ const labels = (source, line, character) => completionAt(source, { line, character }).map((item) => item.label);
5
+ test('suggests admonition kinds after a colon fence', () => {
6
+ const items = labels(':::', 0, 3);
7
+ assert.ok(items.includes('note'));
8
+ assert.ok(items.includes('warning'));
9
+ });
10
+ test('suggests heading ids for a cross-reference', () => {
11
+ const source = '# Hello World\n\n</#';
12
+ // carve-js derives case-preserving heading ids (spaces -> hyphens).
13
+ assert.deepEqual(labels(source, 2, 3), ['Hello-World']);
14
+ });
15
+ test('suggests defined footnote labels', () => {
16
+ const source = 'text[^a]\n\n[^a]: note\n\n[^';
17
+ assert.deepEqual(labels(source, 4, 2), ['a']);
18
+ });
19
+ test('suggests link reference labels', () => {
20
+ const source = '[site]: https://example.com\n\nsee [text][';
21
+ assert.deepEqual(labels(source, 2, 11), ['site']);
22
+ });
23
+ test('does not offer footnote definitions as link references', () => {
24
+ const source = '[site]: https://example.com\n[^fn]: a footnote\n\nsee [text][';
25
+ assert.deepEqual(labels(source, 3, 11), ['site']);
26
+ });
27
+ test('returns nothing in plain prose', () => {
28
+ assert.deepEqual(labels('just some text', 0, 9), []);
29
+ });
30
+ test('completion replaces the typed partial', () => {
31
+ const items = completionAt('</#hel', { line: 0, character: 6 });
32
+ // Nothing to complete against (no headings) -> empty, but must not throw.
33
+ assert.deepEqual(items, []);
34
+ });
35
+ //# sourceMappingURL=completion.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"completion.test.js","sourceRoot":"","sources":["../src/completion.test.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,oBAAoB,CAAA;AACvC,OAAO,IAAI,MAAM,WAAW,CAAA;AAC5B,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAE9C,MAAM,MAAM,GAAG,CAAC,MAAc,EAAE,IAAY,EAAE,SAAiB,EAAY,EAAE,CAC3E,YAAY,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;AAErE,IAAI,CAAC,+CAA+C,EAAE,GAAG,EAAE;IACzD,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;IACjC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAA;IACjC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAA;AACtC,CAAC,CAAC,CAAA;AAEF,IAAI,CAAC,4CAA4C,EAAE,GAAG,EAAE;IACtD,MAAM,MAAM,GAAG,sBAAsB,CAAA;IACrC,oEAAoE;IACpE,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAA;AACzD,CAAC,CAAC,CAAA;AAEF,IAAI,CAAC,kCAAkC,EAAE,GAAG,EAAE;IAC5C,MAAM,MAAM,GAAG,8BAA8B,CAAA;IAC7C,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAA;AAC/C,CAAC,CAAC,CAAA;AAEF,IAAI,CAAC,gCAAgC,EAAE,GAAG,EAAE;IAC1C,MAAM,MAAM,GAAG,4CAA4C,CAAA;IAC3D,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAA;AACnD,CAAC,CAAC,CAAA;AAEF,IAAI,CAAC,wDAAwD,EAAE,GAAG,EAAE;IAClE,MAAM,MAAM,GAAG,+DAA+D,CAAA;IAC9E,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAA;AACnD,CAAC,CAAC,CAAA;AAEF,IAAI,CAAC,gCAAgC,EAAE,GAAG,EAAE;IAC1C,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,gBAAgB,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;AACtD,CAAC,CAAC,CAAA;AAEF,IAAI,CAAC,uCAAuC,EAAE,GAAG,EAAE;IACjD,MAAM,KAAK,GAAG,YAAY,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC,CAAA;IAC/D,0EAA0E;IAC1E,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,EAAE,CAAC,CAAA;AAC7B,CAAC,CAAC,CAAA"}
@@ -0,0 +1,12 @@
1
+ import { type Location, type Position } from 'vscode-languageserver/node.js';
2
+ /**
3
+ * Go-to-definition for Carve constructs:
4
+ *
5
+ * - Cross-reference `</#id>` -> the heading whose generated id is `id`
6
+ * - Fragment link `[text](#id)` -> same (href starts with `#`)
7
+ * - Footnote ref `[^name]` -> the `[^name]:` definition line
8
+ * - Link reference `[text][ref]` -> the `[ref]:` definition line
9
+ * - Citation `[@key]` -> the `[@key]:` definition line
10
+ * - Wikilink `[[Page]]` -> heading whose text matches Page (best-effort)
11
+ */
12
+ export declare function definitionAt(uri: string, source: string, position: Position): Location | null;
@@ -0,0 +1,280 @@
1
+ import { parse, resolve } from '@markup-carve/carve';
2
+ /**
3
+ * Go-to-definition for Carve constructs:
4
+ *
5
+ * - Cross-reference `</#id>` -> the heading whose generated id is `id`
6
+ * - Fragment link `[text](#id)` -> same (href starts with `#`)
7
+ * - Footnote ref `[^name]` -> the `[^name]:` definition line
8
+ * - Link reference `[text][ref]` -> the `[ref]:` definition line
9
+ * - Citation `[@key]` -> the `[@key]:` definition line
10
+ * - Wikilink `[[Page]]` -> heading whose text matches Page (best-effort)
11
+ */
12
+ export function definitionAt(uri, source, position) {
13
+ const lines = source.replace(/\r\n?/g, '\n').split('\n');
14
+ const line = lines[position.line] ?? '';
15
+ // 1. Citation [@key] - check before link-ref so `[@foo]` doesn't match as link-ref
16
+ const citationTarget = resolveCitationAt(lines, line, position);
17
+ if (citationTarget !== null)
18
+ return locationAtLine(uri, citationTarget);
19
+ // 2. Cross-reference </#id> or fragment link [text](#id)
20
+ const crossrefTarget = resolveCrossrefAt(uri, source, line, position);
21
+ if (crossrefTarget !== null)
22
+ return crossrefTarget;
23
+ // 3. Footnote reference [^name]
24
+ const footnoteTarget = resolveFootnoteAt(lines, line, position);
25
+ if (footnoteTarget !== null)
26
+ return locationAtLine(uri, footnoteTarget);
27
+ // 4. Link reference [text][ref] or collapsed [ref][]
28
+ const linkrefTarget = resolveLinkrefAt(lines, line, position);
29
+ if (linkrefTarget !== null)
30
+ return locationAtLine(uri, linkrefTarget);
31
+ // 5. Wikilink [[Page]]
32
+ const wikilinkTarget = resolveWikilinkAt(uri, source, line, position);
33
+ if (wikilinkTarget !== null)
34
+ return wikilinkTarget;
35
+ return null;
36
+ }
37
+ // ---------------------------------------------------------------------------
38
+ // Citation: [@key] or [text; @key] -- navigate to the [@key]: definition line
39
+ // ---------------------------------------------------------------------------
40
+ function resolveCitationAt(lines, line, position) {
41
+ // Find all citation groups on the line: [...@key...]
42
+ // A citation key appears after @ inside [...]
43
+ const citationGroupRe = /\[([^\]]*@[^\]]*)\]/g;
44
+ for (const m of line.matchAll(citationGroupRe)) {
45
+ const start = m.index;
46
+ const end = start + m[0].length;
47
+ if (position.character < start || position.character >= end)
48
+ continue;
49
+ // Extract the key that the cursor is on
50
+ const inner = m[1];
51
+ // Keys: @key tokens separated by ; optionally prefixed with +/-
52
+ const keyRe = /-?@([A-Za-z0-9_.:-]+)/g;
53
+ for (const km of inner.matchAll(keyRe)) {
54
+ // offset of key label relative to full match
55
+ const keyAbsStart = start + 1 + km.index + 1; // skip '[' then '-?' then '@'
56
+ const keyAbsEnd = keyAbsStart + km[1].length;
57
+ if (position.character < start + 1 + km.index || position.character > keyAbsEnd)
58
+ continue;
59
+ const key = km[1];
60
+ // Find [@key]: definition line
61
+ return findCitationDef(lines, key);
62
+ }
63
+ }
64
+ return null;
65
+ }
66
+ function findCitationDef(lines, key) {
67
+ const defRe = new RegExp(`^\\[@${escapeRegExp(key)}\\]:`);
68
+ for (let i = 0; i < lines.length; i++) {
69
+ if (defRe.test(lines[i]))
70
+ return i;
71
+ }
72
+ return null;
73
+ }
74
+ // ---------------------------------------------------------------------------
75
+ // Cross-reference: </#id> or [text](#id) -> heading
76
+ // ---------------------------------------------------------------------------
77
+ function resolveCrossrefAt(uri, source, line, position) {
78
+ // Pattern 1: </#id>
79
+ const crossrefRe = /<\/#([A-Za-z0-9_.:-]+)>/g;
80
+ for (const m of line.matchAll(crossrefRe)) {
81
+ const start = m.index;
82
+ const end = start + m[0].length;
83
+ if (position.character < start || position.character >= end)
84
+ continue;
85
+ return findHeadingById(uri, source, m[1]);
86
+ }
87
+ // Pattern 2: [text](#id) - inline link to a fragment
88
+ const fragLinkRe = /\[[^\]]*\]\(#([A-Za-z0-9_.:-]+)[^)]*\)/g;
89
+ for (const m of line.matchAll(fragLinkRe)) {
90
+ const start = m.index;
91
+ const end = start + m[0].length;
92
+ if (position.character < start || position.character >= end)
93
+ continue;
94
+ return findHeadingById(uri, source, m[1]);
95
+ }
96
+ return null;
97
+ }
98
+ function findHeadingById(uri, source, targetId) {
99
+ let doc;
100
+ try {
101
+ doc = resolve(parse(source));
102
+ }
103
+ catch {
104
+ return null;
105
+ }
106
+ const heading = findHeadingWithId(doc.children, targetId.toLowerCase());
107
+ if (!heading || !heading.pos)
108
+ return null;
109
+ const line = heading.pos.startLine - 1;
110
+ return {
111
+ uri,
112
+ range: {
113
+ start: { line, character: 0 },
114
+ end: { line, character: (heading.pos.endColumn ?? 200) - 1 },
115
+ },
116
+ };
117
+ }
118
+ function findHeadingWithId(nodes, targetId) {
119
+ for (const node of nodes) {
120
+ if (node.type === 'heading') {
121
+ const headingId = node.attrs?.id;
122
+ if (headingId && headingId.toLowerCase() === targetId)
123
+ return node;
124
+ }
125
+ if ('children' in node && Array.isArray(node.children)) {
126
+ const found = findHeadingWithId(node.children.filter(isBlockNode), targetId);
127
+ if (found)
128
+ return found;
129
+ }
130
+ }
131
+ return null;
132
+ }
133
+ function isBlockNode(node) {
134
+ return Boolean(node && typeof node === 'object' && 'type' in node);
135
+ }
136
+ // ---------------------------------------------------------------------------
137
+ // Footnote reference [^name] -> definition line [^name]: ...
138
+ // ---------------------------------------------------------------------------
139
+ function resolveFootnoteAt(lines, line, position) {
140
+ const fnRefRe = /\[\^([^\]\s]+)\]/g;
141
+ for (const m of line.matchAll(fnRefRe)) {
142
+ const start = m.index;
143
+ const end = start + m[0].length;
144
+ if (position.character < start || position.character >= end)
145
+ continue;
146
+ const label = m[1];
147
+ // Find the definition (starts at line beginning: [^label]: ...)
148
+ return findFootnoteDef(lines, label);
149
+ }
150
+ return null;
151
+ }
152
+ function findFootnoteDef(lines, label) {
153
+ const defRe = new RegExp(`^\\[\\^${escapeRegExp(label)}\\]:`);
154
+ for (let i = 0; i < lines.length; i++) {
155
+ if (defRe.test(lines[i]))
156
+ return i;
157
+ }
158
+ return null;
159
+ }
160
+ // ---------------------------------------------------------------------------
161
+ // Link reference [text][ref] or [ref][] -> definition line [ref]: url
162
+ // ---------------------------------------------------------------------------
163
+ function resolveLinkrefAt(lines, line, position) {
164
+ // Match ][label] (full reference) or ][](collapsed) — exclude footnotes
165
+ const fullRefRe = /\]\[([^\]^][^\]]*)\]/g;
166
+ for (const m of line.matchAll(fullRefRe)) {
167
+ // cursor is on the label portion (after `][`)
168
+ const labelStart = m.index + 2;
169
+ const labelEnd = labelStart + m[1].length;
170
+ if (position.character < labelStart || position.character > labelEnd)
171
+ continue;
172
+ const label = m[1];
173
+ return findLinkrefDef(lines, label);
174
+ }
175
+ // Collapsed reference: [ref][] — cursor on first bracket group
176
+ const collapsedRe = /\[([^\]^][^\]]*)\]\[\]/g;
177
+ for (const m of line.matchAll(collapsedRe)) {
178
+ const labelStart = m.index + 1;
179
+ const labelEnd = labelStart + m[1].length;
180
+ if (position.character < labelStart || position.character > labelEnd)
181
+ continue;
182
+ const label = m[1];
183
+ return findLinkrefDef(lines, label);
184
+ }
185
+ return null;
186
+ }
187
+ function findLinkrefDef(lines, label) {
188
+ const normalized = label.replace(/\s+/g, ' ').trim();
189
+ for (let i = 0; i < lines.length; i++) {
190
+ const line = lines[i];
191
+ // Definition: [label]: url at line start (up to 3 leading spaces)
192
+ const defMatch = /^( {0,3})\[([^\]]+)\]:/.exec(line);
193
+ if (defMatch && !defMatch[2].startsWith('^')) {
194
+ const defLabel = defMatch[2].replace(/\s+/g, ' ').trim();
195
+ if (defLabel === normalized)
196
+ return i;
197
+ }
198
+ }
199
+ return null;
200
+ }
201
+ // ---------------------------------------------------------------------------
202
+ // Wikilink [[Page]] -> heading whose text matches Page
203
+ // ---------------------------------------------------------------------------
204
+ function resolveWikilinkAt(uri, source, line, position) {
205
+ const wikilinkRe = /\[\[([^\]|#]+?)(?:[|#][^\]]*)?]]/g;
206
+ for (const m of line.matchAll(wikilinkRe)) {
207
+ const start = m.index;
208
+ const end = start + m[0].length;
209
+ if (position.character < start || position.character >= end)
210
+ continue;
211
+ const page = m[1].trim();
212
+ return findHeadingByText(uri, source, page);
213
+ }
214
+ return null;
215
+ }
216
+ function findHeadingByText(uri, source, text) {
217
+ let doc;
218
+ try {
219
+ doc = resolve(parse(source));
220
+ }
221
+ catch {
222
+ return null;
223
+ }
224
+ const target = text.toLowerCase();
225
+ const heading = findHeadingWithText(doc.children, target);
226
+ if (!heading || !heading.pos)
227
+ return null;
228
+ const line = heading.pos.startLine - 1;
229
+ return {
230
+ uri,
231
+ range: {
232
+ start: { line, character: 0 },
233
+ end: { line, character: (heading.pos.endColumn ?? 200) - 1 },
234
+ },
235
+ };
236
+ }
237
+ function headingPlainText(nodes) {
238
+ let out = '';
239
+ for (const node of nodes) {
240
+ if (node.type === 'text')
241
+ out += node.value;
242
+ else if ('children' in node && Array.isArray(node.children)) {
243
+ out += headingPlainText(node.children);
244
+ }
245
+ else if (node.type === 'code')
246
+ out += node.value;
247
+ }
248
+ return out.trim();
249
+ }
250
+ function findHeadingWithText(nodes, targetText) {
251
+ for (const node of nodes) {
252
+ if (node.type === 'heading') {
253
+ const text = headingPlainText(node.children).toLowerCase();
254
+ if (text === targetText)
255
+ return node;
256
+ }
257
+ if ('children' in node && Array.isArray(node.children)) {
258
+ const found = findHeadingWithText(node.children.filter(isBlockNode), targetText);
259
+ if (found)
260
+ return found;
261
+ }
262
+ }
263
+ return null;
264
+ }
265
+ // ---------------------------------------------------------------------------
266
+ // Helpers
267
+ // ---------------------------------------------------------------------------
268
+ function locationAtLine(uri, line) {
269
+ return {
270
+ uri,
271
+ range: {
272
+ start: { line, character: 0 },
273
+ end: { line, character: 9999 },
274
+ },
275
+ };
276
+ }
277
+ function escapeRegExp(value) {
278
+ return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
279
+ }
280
+ //# sourceMappingURL=definition.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"definition.js","sourceRoot":"","sources":["../src/definition.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,136 @@
1
+ import assert from 'node:assert/strict';
2
+ import test from 'node:test';
3
+ import { definitionAt } from './definition.js';
4
+ const URI = 'file:///doc.crv';
5
+ // ---------------------------------------------------------------------------
6
+ // Cross-reference </#id>
7
+ // ---------------------------------------------------------------------------
8
+ test('crossref </#id> jumps to the matching heading', () => {
9
+ const source = '# Introduction\n\nSee </#introduction>.';
10
+ const loc = definitionAt(URI, source, { line: 2, character: 6 });
11
+ assert.ok(loc, 'expected a location');
12
+ assert.equal(loc.uri, URI);
13
+ assert.equal(loc.range.start.line, 0);
14
+ });
15
+ test('crossref </#id> with explicit {#custom-id} block attribute', () => {
16
+ // In Carve, a block attribute ({#id}) is placed on the line BEFORE the heading.
17
+ const source = '{#my-section}\n# Intro\n\nSee </#my-section>.';
18
+ const loc = definitionAt(URI, source, { line: 3, character: 8 });
19
+ assert.ok(loc);
20
+ // The heading is on line 1 (0-based), but its pos.startLine = 2 (block attr on line 1).
21
+ assert.equal(loc.range.start.line, 1);
22
+ });
23
+ test('crossref </#id> returns null for unknown id', () => {
24
+ const source = '# Hello\n\nSee </#nope>.';
25
+ const loc = definitionAt(URI, source, { line: 2, character: 6 });
26
+ assert.equal(loc, null);
27
+ });
28
+ // ---------------------------------------------------------------------------
29
+ // Fragment link [text](#id)
30
+ // ---------------------------------------------------------------------------
31
+ test('fragment link [text](#id) jumps to heading', () => {
32
+ const source = '# Getting Started\n\n[jump](#getting-started)';
33
+ const loc = definitionAt(URI, source, { line: 2, character: 8 });
34
+ assert.ok(loc);
35
+ assert.equal(loc.range.start.line, 0);
36
+ });
37
+ test('fragment link returns null for missing heading', () => {
38
+ const source = '# Hello\n\n[jump](#nowhere)';
39
+ const loc = definitionAt(URI, source, { line: 2, character: 8 });
40
+ assert.equal(loc, null);
41
+ });
42
+ // ---------------------------------------------------------------------------
43
+ // Footnote reference [^name]
44
+ // ---------------------------------------------------------------------------
45
+ test('footnote reference jumps to definition', () => {
46
+ const source = 'see note[^fn]\n\n[^fn]: The footnote text.';
47
+ const loc = definitionAt(URI, source, { line: 0, character: 10 });
48
+ assert.ok(loc);
49
+ assert.equal(loc.range.start.line, 2);
50
+ });
51
+ test('footnote definition does NOT navigate to itself (cursor on def)', () => {
52
+ // On the definition line, there is no "go to definition" target — it IS the definition.
53
+ // The function should return the line itself (same-line definition found).
54
+ const source = 'see note[^fn]\n\n[^fn]: The footnote text.';
55
+ const loc = definitionAt(URI, source, { line: 2, character: 3 });
56
+ assert.ok(loc);
57
+ // It finds the def line itself (first match is the def pattern).
58
+ assert.equal(loc.range.start.line, 2);
59
+ });
60
+ test('footnote reference returns null when definition is missing', () => {
61
+ const source = 'see note[^missing]';
62
+ const loc = definitionAt(URI, source, { line: 0, character: 12 });
63
+ assert.equal(loc, null);
64
+ });
65
+ // ---------------------------------------------------------------------------
66
+ // Link reference [text][ref]
67
+ // ---------------------------------------------------------------------------
68
+ test('full link reference [text][ref] jumps to definition', () => {
69
+ const source = '[carve]: https://example.com\n\nsee [the site][carve]';
70
+ const loc = definitionAt(URI, source, { line: 2, character: 16 });
71
+ assert.ok(loc);
72
+ assert.equal(loc.range.start.line, 0);
73
+ });
74
+ test('collapsed link reference [ref][] jumps to definition', () => {
75
+ const source = '[carve]: https://example.com\n\nsee [carve][]';
76
+ const loc = definitionAt(URI, source, { line: 2, character: 6 });
77
+ assert.ok(loc);
78
+ assert.equal(loc.range.start.line, 0);
79
+ });
80
+ test('link reference returns null when definition is missing', () => {
81
+ const source = '[text][nope]';
82
+ const loc = definitionAt(URI, source, { line: 0, character: 9 });
83
+ assert.equal(loc, null);
84
+ });
85
+ test('link reference with spaces in label resolves correctly', () => {
86
+ const source = '[my label]: https://example.com\n\nsee [text][my label]';
87
+ const loc = definitionAt(URI, source, { line: 2, character: 13 });
88
+ assert.ok(loc);
89
+ assert.equal(loc.range.start.line, 0);
90
+ });
91
+ // ---------------------------------------------------------------------------
92
+ // Citation [@key]
93
+ // ---------------------------------------------------------------------------
94
+ test('citation [@key] jumps to definition', () => {
95
+ const source = '[@smith2024]: Smith et al. 2024\n\nSee [@smith2024].';
96
+ const loc = definitionAt(URI, source, { line: 2, character: 7 });
97
+ assert.ok(loc);
98
+ assert.equal(loc.range.start.line, 0);
99
+ });
100
+ test('citation returns null when definition is missing', () => {
101
+ const source = 'See [@nobody].';
102
+ const loc = definitionAt(URI, source, { line: 0, character: 7 });
103
+ assert.equal(loc, null);
104
+ });
105
+ // ---------------------------------------------------------------------------
106
+ // Wikilink [[Page]]
107
+ // ---------------------------------------------------------------------------
108
+ test('wikilink [[Page]] jumps to matching heading', () => {
109
+ const source = '# Tigers\n\nSee [[Tigers]].';
110
+ const loc = definitionAt(URI, source, { line: 2, character: 6 });
111
+ assert.ok(loc);
112
+ assert.equal(loc.range.start.line, 0);
113
+ });
114
+ test('wikilink [[Page]] is case-insensitive', () => {
115
+ const source = '# Tigers\n\nSee [[tigers]].';
116
+ const loc = definitionAt(URI, source, { line: 2, character: 6 });
117
+ assert.ok(loc);
118
+ assert.equal(loc.range.start.line, 0);
119
+ });
120
+ test('wikilink returns null when no matching heading exists', () => {
121
+ const source = '# Hello\n\nSee [[Nowhere]].';
122
+ const loc = definitionAt(URI, source, { line: 2, character: 6 });
123
+ assert.equal(loc, null);
124
+ });
125
+ // ---------------------------------------------------------------------------
126
+ // No-op cases: cursor not on any navigable construct
127
+ // ---------------------------------------------------------------------------
128
+ test('returns null on plain text', () => {
129
+ const loc = definitionAt(URI, 'just some text here', { line: 0, character: 5 });
130
+ assert.equal(loc, null);
131
+ });
132
+ test('returns null on empty line', () => {
133
+ const loc = definitionAt(URI, 'line one\n\nline three', { line: 1, character: 0 });
134
+ assert.equal(loc, null);
135
+ });
136
+ //# sourceMappingURL=definition.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"definition.test.js","sourceRoot":"","sources":["../src/definition.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import { type FoldingRange } from 'vscode-languageserver/node.js';
2
+ /**
3
+ * Folding regions for a Carve document:
4
+ * - every multi-line block (code, admonition, div, list, table, …)
5
+ * - each heading's section, from the heading line down to the line before
6
+ * the next heading of the same or shallower level (or end of document).
7
+ */
8
+ export declare function foldingRanges(source: string): FoldingRange[];