@markup-carve/carve-lsp 0.1.2 → 0.1.4

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 (176) hide show
  1. package/README.md +61 -14
  2. package/dist/analyze.d.ts +15 -1
  3. package/dist/analyze.js +214 -16
  4. package/dist/analyze.js.map +1 -1
  5. package/dist/analyze.test.js +29 -1
  6. package/dist/analyze.test.js.map +1 -1
  7. package/dist/captions.d.ts +49 -0
  8. package/dist/captions.js +124 -0
  9. package/dist/captions.js.map +1 -0
  10. package/dist/codelens.js +12 -0
  11. package/dist/codelens.js.map +1 -1
  12. package/dist/codelens.test.js +5 -0
  13. package/dist/codelens.test.js.map +1 -1
  14. package/dist/colon-fence-kinds.test.d.ts +1 -0
  15. package/dist/colon-fence-kinds.test.js +128 -0
  16. package/dist/colon-fence-kinds.test.js.map +1 -0
  17. package/dist/colon-fences.d.ts +24 -0
  18. package/dist/colon-fences.js +174 -0
  19. package/dist/colon-fences.js.map +1 -0
  20. package/dist/colon-fences.test.d.ts +1 -0
  21. package/dist/colon-fences.test.js +23 -0
  22. package/dist/colon-fences.test.js.map +1 -0
  23. package/dist/completion.d.ts +6 -2
  24. package/dist/completion.js +84 -8
  25. package/dist/completion.js.map +1 -1
  26. package/dist/completion.test.js +7 -0
  27. package/dist/completion.test.js.map +1 -1
  28. package/dist/composite-figure-crossref.test.d.ts +1 -0
  29. package/dist/composite-figure-crossref.test.js +265 -0
  30. package/dist/composite-figure-crossref.test.js.map +1 -0
  31. package/dist/composite-figure.test.d.ts +1 -0
  32. package/dist/composite-figure.test.js +76 -0
  33. package/dist/composite-figure.test.js.map +1 -0
  34. package/dist/definition.d.ts +4 -2
  35. package/dist/definition.js +28 -5
  36. package/dist/definition.js.map +1 -1
  37. package/dist/dependencies.d.ts +15 -0
  38. package/dist/dependencies.js +59 -0
  39. package/dist/dependencies.js.map +1 -0
  40. package/dist/diagnostic-scheduler.d.ts +58 -0
  41. package/dist/diagnostic-scheduler.js +70 -0
  42. package/dist/diagnostic-scheduler.js.map +1 -0
  43. package/dist/diagnostic-scheduler.test.d.ts +1 -0
  44. package/dist/diagnostic-scheduler.test.js +75 -0
  45. package/dist/diagnostic-scheduler.test.js.map +1 -0
  46. package/dist/document-highlights.d.ts +2 -0
  47. package/dist/document-highlights.js +21 -0
  48. package/dist/document-highlights.js.map +1 -0
  49. package/dist/document-highlights.test.d.ts +1 -0
  50. package/dist/document-highlights.test.js +13 -0
  51. package/dist/document-highlights.test.js.map +1 -0
  52. package/dist/document-links.d.ts +3 -0
  53. package/dist/document-links.js +36 -0
  54. package/dist/document-links.js.map +1 -0
  55. package/dist/document-links.test.d.ts +1 -0
  56. package/dist/document-links.test.js +12 -0
  57. package/dist/document-links.test.js.map +1 -0
  58. package/dist/folding.d.ts +1 -0
  59. package/dist/folding.js +36 -1
  60. package/dist/folding.js.map +1 -1
  61. package/dist/folding.test.js +6 -1
  62. package/dist/folding.test.js.map +1 -1
  63. package/dist/format-corpus.test.d.ts +1 -0
  64. package/dist/format-corpus.test.js +16 -0
  65. package/dist/format-corpus.test.js.map +1 -0
  66. package/dist/format.d.ts +3 -0
  67. package/dist/format.js +38 -74
  68. package/dist/format.js.map +1 -1
  69. package/dist/format.test.js +27 -32
  70. package/dist/format.test.js.map +1 -1
  71. package/dist/hover.js +78 -19
  72. package/dist/hover.js.map +1 -1
  73. package/dist/include-cache.d.ts +26 -0
  74. package/dist/include-cache.js +74 -0
  75. package/dist/include-cache.js.map +1 -0
  76. package/dist/include-completion.d.ts +3 -0
  77. package/dist/include-completion.js +68 -0
  78. package/dist/include-completion.js.map +1 -0
  79. package/dist/include-completion.test.d.ts +1 -0
  80. package/dist/include-completion.test.js +15 -0
  81. package/dist/include-completion.test.js.map +1 -0
  82. package/dist/include-definition-denial.test.d.ts +1 -0
  83. package/dist/include-definition-denial.test.js +86 -0
  84. package/dist/include-definition-denial.test.js.map +1 -0
  85. package/dist/include-definition.d.ts +3 -0
  86. package/dist/include-definition.js +37 -0
  87. package/dist/include-definition.js.map +1 -0
  88. package/dist/include-features.test.d.ts +1 -0
  89. package/dist/include-features.test.js +133 -0
  90. package/dist/include-features.test.js.map +1 -0
  91. package/dist/include-path.d.ts +6 -0
  92. package/dist/include-path.js +31 -2
  93. package/dist/include-path.js.map +1 -1
  94. package/dist/include-settings.d.ts +2 -0
  95. package/dist/include-settings.js +1 -0
  96. package/dist/include-settings.js.map +1 -1
  97. package/dist/includes.d.ts +8 -0
  98. package/dist/includes.js +28 -7
  99. package/dist/includes.js.map +1 -1
  100. package/dist/inlay-hints.d.ts +3 -0
  101. package/dist/inlay-hints.js +43 -0
  102. package/dist/inlay-hints.js.map +1 -0
  103. package/dist/inlay-hints.test.d.ts +1 -0
  104. package/dist/inlay-hints.test.js +10 -0
  105. package/dist/inlay-hints.test.js.map +1 -0
  106. package/dist/lint-actions.d.ts +3 -0
  107. package/dist/lint-actions.js +90 -0
  108. package/dist/lint-actions.js.map +1 -0
  109. package/dist/lint-actions.test.d.ts +1 -0
  110. package/dist/lint-actions.test.js +31 -0
  111. package/dist/lint-actions.test.js.map +1 -0
  112. package/dist/no-git-dependencies.test.d.ts +1 -0
  113. package/dist/no-git-dependencies.test.js +243 -0
  114. package/dist/no-git-dependencies.test.js.map +1 -0
  115. package/dist/packaging.test.d.ts +1 -0
  116. package/dist/packaging.test.js +69 -0
  117. package/dist/packaging.test.js.map +1 -0
  118. package/dist/references.d.ts +2 -0
  119. package/dist/references.js +113 -21
  120. package/dist/references.js.map +1 -1
  121. package/dist/selection.d.ts +2 -0
  122. package/dist/selection.js +36 -0
  123. package/dist/selection.js.map +1 -0
  124. package/dist/selection.test.d.ts +1 -0
  125. package/dist/selection.test.js +10 -0
  126. package/dist/selection.test.js.map +1 -0
  127. package/dist/semantic.d.ts +5 -3
  128. package/dist/semantic.js +45 -4
  129. package/dist/semantic.js.map +1 -1
  130. package/dist/semantic.test.js +11 -0
  131. package/dist/semantic.test.js.map +1 -1
  132. package/dist/server-capabilities.test.d.ts +1 -0
  133. package/dist/server-capabilities.test.js +84 -0
  134. package/dist/server-capabilities.test.js.map +1 -0
  135. package/dist/server.js +353 -24
  136. package/dist/server.js.map +1 -1
  137. package/dist/settings.d.ts +11 -0
  138. package/dist/settings.js +50 -0
  139. package/dist/settings.js.map +1 -0
  140. package/dist/settings.test.d.ts +1 -0
  141. package/dist/settings.test.js +22 -0
  142. package/dist/settings.test.js.map +1 -0
  143. package/dist/spec-0-1-4-constructs.test.d.ts +1 -0
  144. package/dist/spec-0-1-4-constructs.test.js +101 -0
  145. package/dist/spec-0-1-4-constructs.test.js.map +1 -0
  146. package/dist/table-diagnostics.d.ts +3 -0
  147. package/dist/table-diagnostics.js +60 -0
  148. package/dist/table-diagnostics.js.map +1 -0
  149. package/dist/table-diagnostics.test.d.ts +1 -0
  150. package/dist/table-diagnostics.test.js +12 -0
  151. package/dist/table-diagnostics.test.js.map +1 -0
  152. package/dist/versioned-cache.d.ts +8 -0
  153. package/dist/versioned-cache.js +17 -0
  154. package/dist/versioned-cache.js.map +1 -0
  155. package/dist/versioned-cache.test.d.ts +1 -0
  156. package/dist/versioned-cache.test.js +13 -0
  157. package/dist/versioned-cache.test.js.map +1 -0
  158. package/dist/workspace-graph.d.ts +25 -0
  159. package/dist/workspace-graph.js +94 -0
  160. package/dist/workspace-graph.js.map +1 -0
  161. package/dist/workspace-graph.test.d.ts +1 -0
  162. package/dist/workspace-graph.test.js +31 -0
  163. package/dist/workspace-graph.test.js.map +1 -0
  164. package/dist/workspace-index.d.ts +40 -0
  165. package/dist/workspace-index.js +254 -0
  166. package/dist/workspace-index.js.map +1 -0
  167. package/dist/workspace-index.test.d.ts +1 -0
  168. package/dist/workspace-index.test.js +65 -0
  169. package/dist/workspace-index.test.js.map +1 -0
  170. package/dist/workspace-loader.d.ts +11 -0
  171. package/dist/workspace-loader.js +50 -0
  172. package/dist/workspace-loader.js.map +1 -0
  173. package/dist/workspace-loader.test.d.ts +1 -0
  174. package/dist/workspace-loader.test.js +19 -0
  175. package/dist/workspace-loader.test.js.map +1 -0
  176. package/package.json +4 -3
@@ -1,9 +1,13 @@
1
1
  import { type CompletionItem, type Position } from 'vscode-languageserver/node.js';
2
+ import type { IndexedToken } from './workspace-index.js';
2
3
  /**
3
4
  * Context-aware completions driven by the text immediately before the cursor:
4
- * - `::: ` opens an admonition -> canonical kinds
5
+ * - `::: ` opens a container -> canonical admonition kinds, and `figure`
5
6
  * - `</#` cross-reference -> heading ids in the document
6
7
  * - `[^` footnote reference -> defined footnote labels
7
8
  * - `][` reference link -> defined link reference labels
8
9
  */
9
- export declare function completionAt(source: string, position: Position): CompletionItem[];
10
+ export interface CompletionContext {
11
+ workspaceTokens?: IndexedToken[];
12
+ }
13
+ export declare function completionAt(source: string, position: Position, context?: CompletionContext): CompletionItem[];
@@ -1,23 +1,38 @@
1
1
  import { CompletionItemKind, } from 'vscode-languageserver/node.js';
2
2
  import { parse, resolve } from '@markup-carve/carve';
3
+ import { captionTargets } from './captions.js';
3
4
  /** The eight canonical admonition kinds (grammar PART 9 §12, Tier 1). */
4
5
  const ADMONITIONS = ['note', 'tip', 'warning', 'danger', 'info', 'success', 'example', 'quote'];
5
6
  /**
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
7
+ * `figure` is not one of them. It is RESERVED among the `:::` types (PART 9
8
+ * §4c): a BARE `::: figure` opener is one figure of ordered panels, and the same
9
+ * word with a title or a `[label]` is an ordinary container. Offering it beside
10
+ * the eight would say it is a ninth admonition, so it is offered separately and
11
+ * labelled for what it opens.
11
12
  */
12
- export function completionAt(source, position) {
13
+ const FIGURE_GROUP = 'figure';
14
+ export function completionAt(source, position, context = {}) {
13
15
  const line = source.split(/\r?\n/)[position.line] ?? '';
14
16
  const prefix = line.slice(0, position.character);
15
17
  let match;
16
18
  if ((match = /:::\s*([\w-]*)$/.exec(prefix))) {
17
- return ADMONITIONS.map((kind) => completion(kind, CompletionItemKind.Keyword, match[1], position, 'Admonition kind'));
19
+ return [
20
+ ...ADMONITIONS.map((kind) => completion(kind, CompletionItemKind.Keyword, match[1], position, 'Admonition kind')),
21
+ completion(FIGURE_GROUP, CompletionItemKind.Struct, match[1], position, 'Composite figure'),
22
+ ];
18
23
  }
19
24
  if ((match = /<\/#([\w-]*)$/.exec(prefix))) {
20
- return headingIds(source).map((id) => completion(id, CompletionItemKind.Reference, match[1], position, 'Heading id'));
25
+ // A crossref reaches a captioned host as well as a heading (PART 9R R4).
26
+ // Offering only heading ids said the others were not targets, which is the
27
+ // reading that made a `</#fig>` naming a figure look like a typo.
28
+ const workspace = (context.workspaceTokens ?? [])
29
+ .filter((token) => token.declaration && (token.kind === 'heading' || token.kind === 'caption'))
30
+ .map((token) => completion(token.key, CompletionItemKind.Reference, match[1], position, `${token.kind} in workspace`));
31
+ return uniqueCompletions([
32
+ ...headingIds(source).map((id) => completion(id, CompletionItemKind.Reference, match[1], position, 'Heading id')),
33
+ ...resolvableCaptionIds(source).map(({ id, detail }) => completion(id, CompletionItemKind.Reference, match[1], position, detail)),
34
+ ...workspace,
35
+ ]);
21
36
  }
22
37
  if ((match = /\[\^([\w-]*)$/.exec(prefix))) {
23
38
  return footnoteLabels(source).map((label) => completion(label, CompletionItemKind.Reference, match[1], position, 'Footnote'));
@@ -25,8 +40,32 @@ export function completionAt(source, position) {
25
40
  if ((match = /\]\[([\w-]*)$/.exec(prefix))) {
26
41
  return linkReferenceLabels(source).map((label) => completion(label, CompletionItemKind.Reference, match[1], position, 'Link reference'));
27
42
  }
43
+ if ((match = /\[@([\w:.-]*)$/.exec(prefix))) {
44
+ const local = citationLabels(source);
45
+ const workspace = (context.workspaceTokens ?? [])
46
+ .filter((token) => token.declaration && token.kind === 'citation')
47
+ .map((token) => token.key);
48
+ return [...new Set([...local, ...workspace])].map((label) => completion(label, CompletionItemKind.Reference, match[1], position, 'Citation key'));
49
+ }
50
+ if ((match = /\{[^}\n]*\b([\w-]*)$/.exec(prefix))) {
51
+ const attributes = ['#id', '.class', 'align=', 'valign=', 'width=', 'aligns=', 'valigns=', 'widths=',
52
+ 'header-rows=', 'header-cols=', 'footer-rows=', 'start=', 'type=', 'title=', 'label='];
53
+ return attributes.map((attribute) => completion(attribute, CompletionItemKind.Property, match[1], position, 'Carve attribute'));
54
+ }
55
+ if ((match = /:(\w*)$/.exec(prefix))) {
56
+ return ['abbr', 'time', 'kbd', 'samp', 'var', 'cite', 'dfn'].map((name) => completion(name, CompletionItemKind.TypeParameter, match[1], position, 'Semantic span'));
57
+ }
28
58
  return [];
29
59
  }
60
+ function uniqueCompletions(items) {
61
+ const seen = new Set();
62
+ return items.filter((item) => {
63
+ if (seen.has(item.label))
64
+ return false;
65
+ seen.add(item.label);
66
+ return true;
67
+ });
68
+ }
30
69
  function completion(value, kind, partial, position, detail) {
31
70
  return {
32
71
  label: value,
@@ -57,6 +96,34 @@ function headingIds(source) {
57
96
  }
58
97
  return [...new Set(ids)];
59
98
  }
99
+ /**
100
+ * The caption ids a `</#…>` can actually RESOLVE, each with what it resolves to
101
+ * - "Figure 2" beside "Figure 2a", so the list distinguishes a group from its
102
+ * panels without the author having to remember which is which.
103
+ *
104
+ * A host that drew NO number is left out. Its id is a real anchor, and a
105
+ * `[text](#id)` fragment link reaches it, but a CROSSREF to it renders as
106
+ * literal text (PART 9 §4c: an unnumbered group's panels are anchors, not
107
+ * caption crossref targets). Every heading id this list offers resolves, and a
108
+ * caption id that did not would be the one entry that quietly does not work.
109
+ */
110
+ function resolvableCaptionIds(source) {
111
+ let targets;
112
+ try {
113
+ targets = captionTargets(resolve(parse(source, { positions: true })));
114
+ }
115
+ catch {
116
+ // Parsing may fail mid-edit; offer no ids rather than throwing.
117
+ return [];
118
+ }
119
+ const resolvable = [];
120
+ for (const target of targets) {
121
+ if (target.text === null)
122
+ continue;
123
+ resolvable.push({ id: target.id, detail: `${target.text} (${target.kind})` });
124
+ }
125
+ return resolvable;
126
+ }
60
127
  function footnoteLabels(source) {
61
128
  try {
62
129
  const doc = resolve(parse(source));
@@ -77,6 +144,15 @@ function linkReferenceLabels(source) {
77
144
  }
78
145
  return [...labels];
79
146
  }
147
+ function citationLabels(source) {
148
+ const labels = new Set();
149
+ for (const line of source.split(/\r?\n/)) {
150
+ const match = /^\s{0,3}\[@([^\]]+)\]:/.exec(line);
151
+ if (match)
152
+ labels.add(match[1]);
153
+ }
154
+ return [...labels];
155
+ }
80
156
  function walkBlocks(nodes, visit) {
81
157
  for (const node of nodes) {
82
158
  visit(node);
@@ -1 +1 @@
1
- {"version":3,"file":"completion.js","sourceRoot":"","sources":["../src/completion.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"completion.js","sourceRoot":"","sources":["../src/completion.ts"],"names":[],"mappings":"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"}
@@ -32,4 +32,11 @@ test('completion replaces the typed partial', () => {
32
32
  // Nothing to complete against (no headings) -> empty, but must not throw.
33
33
  assert.deepEqual(items, []);
34
34
  });
35
+ test('suggests citation keys, semantic spans, and structural attributes', () => {
36
+ assert.deepEqual(labels('[@doc]: Entry\n\n[@do', 2, 4), ['doc']);
37
+ assert.ok(labels(':k', 0, 2).includes('kbd'));
38
+ const attrs = labels('{vali', 0, 5);
39
+ assert.ok(attrs.includes('valign='));
40
+ assert.ok(attrs.includes('valigns='));
41
+ });
35
42
  //# sourceMappingURL=completion.test.js.map
@@ -1 +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"}
1
+ {"version":3,"file":"completion.test.js","sourceRoot":"","sources":["../src/completion.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,265 @@
1
+ import assert from 'node:assert/strict';
2
+ import test from 'node:test';
3
+ import { carveToHtml, lintCarve, parse, resolve } from '@markup-carve/carve';
4
+ import { analyzeCarve } from './analyze.js';
5
+ import { captionTargets, panelLetter } from './captions.js';
6
+ import { completionAt } from './completion.js';
7
+ import { definitionAt } from './definition.js';
8
+ import { hoverAt } from './hover.js';
9
+ import { referencesAt } from './references.js';
10
+ /*
11
+ * A composite figure across the features that resolve an id (PART 9 §4c,
12
+ * markup-carve/carve#1122), plus the diagnostics the clause names.
13
+ *
14
+ * The crossref half of this was NOT a figure_group gap. The server resolved no
15
+ * caption id at all - not a group's, not a panel's, and not the plain captioned
16
+ * figure's that predates the feature - because every crossref feature walked
17
+ * headings only. The `{#fig}` figure below is here for exactly that reason: it
18
+ * is the case that has been broken the longest and is the control for the group
19
+ * cases, so a fix that only taught the walk about `figure_group` fails it.
20
+ *
21
+ * WHERE THE EXPECTED TEXT COMES FROM. The engine, not this file's reading of
22
+ * §4c. `carveToHtml` writes the resolved text into the anchor for each id, and
23
+ * the assertions below compare the server's answer against THAT rather than
24
+ * against a literal - so a letter scheme or a numbering rule that changes
25
+ * upstream fails here instead of diverging quietly in an editor.
26
+ */
27
+ const DOC = `# Section
28
+
29
+ {#fig}
30
+ ![plain](p.png)
31
+ ^ Figure #: Plain
32
+
33
+ {#g}
34
+ ::: figure
35
+ {#one}
36
+ ![one](a.png)
37
+ ^ (a) One
38
+
39
+ A stray paragraph between the panels.
40
+
41
+ {#two}
42
+ ![two](b.png)
43
+ ^ (b) Two
44
+ :::
45
+ ^ Figure #: Group caption
46
+
47
+ See </#fig>, </#g>, </#one> and </#two>.
48
+ `;
49
+ /**
50
+ * The line the references sit on, and the column of each one. Derived from the
51
+ * document rather than written down, so editing DOC cannot silently move an
52
+ * assertion onto a blank line where every feature correctly answers nothing.
53
+ */
54
+ const REF_LINE = DOC.split('\n').findIndex((line) => line.startsWith('See '));
55
+ const refColumn = (id) => DOC.split('\n')[REF_LINE].indexOf(`</#${id}>`) + 3;
56
+ /** The text the ENGINE renders for `</#id>`, read off the anchor it writes. */
57
+ const engineRefText = (source, id) => {
58
+ const match = new RegExp(`<a href="#${id}">([^<]*)</a>`).exec(carveToHtml(source));
59
+ return match ? match[1] : null;
60
+ };
61
+ const targetFor = (source, id) => captionTargets(resolve(parse(source, { positions: true }))).find((t) => t.id === id);
62
+ test('every caption id resolves to the text the engine renders for it', () => {
63
+ for (const id of ['fig', 'g', 'one', 'two']) {
64
+ assert.equal(targetFor(DOC, id)?.text, engineRefText(DOC, id), `crossref text for #${id} disagrees with the rendered anchor`);
65
+ }
66
+ // Not merely "equal to each other": the group's own reference carries no
67
+ // letter and its panels do, which is the rule under test.
68
+ assert.equal(engineRefText(DOC, 'g'), 'Figure 2');
69
+ assert.equal(engineRefText(DOC, 'one'), 'Figure 2a');
70
+ assert.equal(engineRefText(DOC, 'two'), 'Figure 2b');
71
+ });
72
+ test('a stray block between panels does not take a letter', () => {
73
+ // The paragraph sits between the two panels. If the walk counted children
74
+ // rather than PANELS, the second panel would be "Figure 2c".
75
+ assert.equal(targetFor(DOC, 'two')?.text, 'Figure 2b');
76
+ });
77
+ test('panel letters run a..z then aa', () => {
78
+ assert.deepEqual([0, 1, 25, 26, 27, 51, 52].map(panelLetter), [
79
+ 'a',
80
+ 'b',
81
+ 'z',
82
+ 'aa',
83
+ 'ab',
84
+ 'az',
85
+ 'ba',
86
+ ]);
87
+ });
88
+ test('an unnumbered group registers anchors but no crossref text', () => {
89
+ const source = `{#ug}\n::: figure\n{#u1}\n![u](u.png)\n^ (a) U\n:::\n^ No number here\n\nSee </#ug> and </#u1>.\n`;
90
+ assert.equal(targetFor(source, 'ug')?.text, null);
91
+ assert.equal(targetFor(source, 'u1')?.text, null);
92
+ // The engine agrees: it leaves both references as literal text rather than
93
+ // linking them, which is what "not a caption crossref target" means (§4c).
94
+ assert.equal(engineRefText(source, 'ug'), null);
95
+ assert.equal(engineRefText(source, 'u1'), null);
96
+ });
97
+ test('go-to-definition on a crossref reaches the host, panel or not', () => {
98
+ // `</#fig>` is the control: a captioned figure, no group involved, and it
99
+ // jumped nowhere before this.
100
+ const hostLine = (id) => definitionAt('file:///d.crv', DOC, { line: REF_LINE, character: refColumn(id) })?.range.start.line;
101
+ assert.equal(hostLine('fig'), 3);
102
+ assert.equal(hostLine('g'), 7);
103
+ assert.equal(hostLine('one'), 9);
104
+ });
105
+ test('a crossref hover names what the id resolves to', () => {
106
+ const text = (id) => {
107
+ const hover = hoverAt(DOC, { line: REF_LINE, character: refColumn(id) });
108
+ return typeof hover?.contents === 'object' && 'value' in hover.contents ? hover.contents.value : '';
109
+ };
110
+ assert.match(text('one'), /Figure 2a/);
111
+ assert.match(text('one'), /panel/);
112
+ assert.match(text('g'), /Figure 2/);
113
+ // CONTROL. Before this, no `heading_ref` case existed and the lexical rules
114
+ // took the `#` inside the reference, so every crossref hovered as a heading.
115
+ assert.doesNotMatch(text('one'), /create section headings/);
116
+ });
117
+ test('find-references pairs a panel id with its usages', () => {
118
+ const locations = referencesAt('file:///d.crv', DOC, { line: REF_LINE, character: refColumn('one') }, { includeDeclaration: true });
119
+ assert.deepEqual(locations?.map((location) => location.range.start.line), [9, REF_LINE]);
120
+ });
121
+ test('crossref completion offers caption ids beside heading ids', () => {
122
+ const source = DOC.replace('See </#fig>, </#g>, </#one> and </#two>.', 'See </#');
123
+ const items = completionAt(source, { line: REF_LINE, character: 7 });
124
+ const detail = (label) => items.find((i) => i.label === label)?.detail;
125
+ assert.equal(detail('Section'), 'Heading id');
126
+ assert.equal(detail('fig'), 'Figure 1 (figure)');
127
+ assert.equal(detail('g'), 'Figure 2 (composite figure)');
128
+ assert.equal(detail('one'), 'Figure 2a (panel)');
129
+ assert.equal(detail('two'), 'Figure 2b (panel)');
130
+ });
131
+ test('an unnumbered host is not offered as a crossref target', () => {
132
+ // Every id `</#` offers has to RESOLVE. An unnumbered host is a real anchor
133
+ // and a fragment link reaches it, but a crossref to it renders as literal
134
+ // text, so offering it here would be the one entry in the list that does not
135
+ // work - the heading ids beside it all do.
136
+ const source = `{#ug}\n::: figure\n{#u1}\n![u](u.png)\n^ (a) U\n:::\n^ No number here\n\nSee </#`;
137
+ const labels = completionAt(source, { line: 8, character: 7 }).map((item) => item.label);
138
+ assert.deepEqual(labels, []);
139
+ });
140
+ test('find-references works from the declaration as well as from a usage', () => {
141
+ // A heading declares its id on its own line; a captioned host declares it on
142
+ // the block-attribute line ABOVE itself. Both are where an author puts the
143
+ // cursor to ask "what points at this?".
144
+ const fromAttributeLine = referencesAt('file:///d.crv', DOC, { line: 6, character: 2 }, {
145
+ includeDeclaration: false,
146
+ });
147
+ const fromHostLine = referencesAt('file:///d.crv', DOC, { line: 7, character: 2 }, {
148
+ includeDeclaration: false,
149
+ });
150
+ assert.deepEqual(fromAttributeLine?.map((location) => location.range.start.line), [REF_LINE]);
151
+ assert.deepEqual(fromHostLine?.map((location) => location.range.start.line), [REF_LINE]);
152
+ });
153
+ test('a declaration inside a container still declares', () => {
154
+ // The id's line is not always a bare `{#id}` at column 0. A shape test on it
155
+ // reads like a safety check and is not one - a host only has an id because a
156
+ // block-attribute line gave it one - so it can only reject a right answer.
157
+ const quoted = '> {#fig}\n> ![a](a.png)\n> ^ Figure #: A\n\nSee </#fig>.\n';
158
+ assert.deepEqual(referencesAt('file:///d.crv', quoted, { line: 0, character: 3 }, { includeDeclaration: false })
159
+ ?.map((location) => location.range.start.line), [4]);
160
+ });
161
+ test('a line that declares no id declares nothing', () => {
162
+ // CONTROL. The lookup keys on hosts that CARRY an id, not on hosts. An
163
+ // uncaptioned-id figure has no entry, so the prose above it is just prose.
164
+ assert.equal(referencesAt('file:///d.crv', 'Prose.\n![a](a.png)\n^ Figure #: A\n', { line: 0, character: 2 }, {
165
+ includeDeclaration: false,
166
+ }), null);
167
+ // And a line nowhere near a host answers nothing either.
168
+ assert.equal(referencesAt('file:///d.crv', DOC, { line: 12, character: 2 }, { includeDeclaration: false }), null);
169
+ });
170
+ test('a construct on the declaration line still wins', () => {
171
+ // CONTROL for the declaration lookup, which is matched by LINE and so
172
+ // answers for every column on it. A host line can carry a reference image,
173
+ // and asking on its label must reach the link-reference definition rather
174
+ // than the figure that happens to wrap it.
175
+ const source = '{#fig}\n![alt][img]\n^ Figure #: C\n\n[img]: pic.png\n\nAgain [x][img].\n';
176
+ const onLabel = referencesAt('file:///d.crv', source, { line: 1, character: 8 }, {
177
+ includeDeclaration: true,
178
+ });
179
+ assert.deepEqual(onLabel?.map((location) => location.range.start.line), [1, 4, 6]);
180
+ // The same line still declares the figure where nothing else claims the
181
+ // cursor - here, on the `!` that opens the image.
182
+ const onHost = referencesAt('file:///d.crv', source, { line: 0, character: 2 }, {
183
+ includeDeclaration: false,
184
+ });
185
+ assert.deepEqual(onHost?.map((location) => location.range.start.line), []);
186
+ });
187
+ test('a collapsed reference is not a usage of a caption id', () => {
188
+ // `[foo][]` falls back to the implicit HEADING target and to nothing else
189
+ // (PART 9R R1): beside a figure `{#foo}` it renders as literal text, so
190
+ // reporting it as a usage would be a reference the author cannot follow.
191
+ const source = '{#foo}\n![a](a.png)\n^ Figure #: Foo\n\nSee [foo][] and </#foo>.\n';
192
+ const locations = referencesAt('file:///d.crv', source, { line: 4, character: 22 }, {
193
+ includeDeclaration: false,
194
+ });
195
+ assert.deepEqual(locations?.map((location) => location.range.start.character), [16]);
196
+ });
197
+ test('a collapsed reference IS a usage of a heading id', () => {
198
+ // CONTROL. The scan is not removed, it is scoped: the same spelling still
199
+ // reaches a heading, which is the target it actually resolves to.
200
+ const source = '# Foo\n\nSee [foo][] and </#Foo>.\n';
201
+ const locations = referencesAt('file:///d.crv', source, { line: 2, character: 20 }, {
202
+ includeDeclaration: false,
203
+ });
204
+ assert.deepEqual(locations?.map((location) => location.range.start.character), [16, 4]);
205
+ });
206
+ test('the outline carries the group and nests its panels', () => {
207
+ const symbols = analyzeCarve(DOC).symbols;
208
+ assert.equal(symbols.length, 1, 'the heading is still the only root');
209
+ const group = symbols[0].children?.find((child) => child.name.startsWith('Figure 2'));
210
+ assert.ok(group, `no group symbol under the heading: ${JSON.stringify(symbols[0].children)}`);
211
+ assert.equal(group.name, 'Figure 2: Group caption');
212
+ assert.equal(group.detail, '2 panels');
213
+ assert.deepEqual(group.children?.map((panel) => panel.name), ['(a) One', '(b) Two']);
214
+ });
215
+ test('a heading inside a panel stays in the outline', () => {
216
+ // CONTROL for the group's own entry. A panel yields no outline entry of its
217
+ // own, but the walk still descends through it: a panel can wrap a quote
218
+ // holding headings, and those belong to the section the group sits in - which
219
+ // is where they were before the group had an entry at all.
220
+ const symbols = analyzeCarve('# Section\n\n::: figure\n> ## Inside a panel\n>\n> Quoted.\n^ (a) A\n:::\n^ Figure #: g\n').symbols;
221
+ assert.deepEqual(symbols[0].children?.map((child) => child.name), ['Figure 1: g', 'Inside a panel']);
222
+ });
223
+ test('a group with no caption is still an outline entry, named for what it is', () => {
224
+ const symbols = analyzeCarve('::: figure\n![a](a.png)\n^ (a) A\n:::\n').symbols;
225
+ assert.deepEqual(symbols.map((symbol) => symbol.name), ['Composite figure']);
226
+ assert.equal(symbols[0].detail, '1 panel');
227
+ });
228
+ test('an uncaptioned panel falls back to the letter a crossref would use', () => {
229
+ const symbols = analyzeCarve('::: figure\n| a |\n\n| b |\n:::\n^ Figure #: g\n').symbols;
230
+ assert.deepEqual(symbols[0].children?.map((panel) => panel.name), ['Panel a', 'Panel b']);
231
+ });
232
+ test('a heading is still a heading, wherever it sits relative to a group', () => {
233
+ // CONTROL for the outline change. A group takes no heading level, so it must
234
+ // not pop the stack: the section after it stays a sibling of the one before.
235
+ const symbols = analyzeCarve('# One\n\n::: figure\n![a](a.png)\n^ (a) A\n:::\n\n## Under one\n\n# Two\n').symbols;
236
+ assert.deepEqual(symbols.map((symbol) => symbol.name), ['One', 'Two']);
237
+ assert.deepEqual(symbols[0].children?.map((child) => child.name), ['Composite figure', 'Under one']);
238
+ });
239
+ /*
240
+ * The five §4c findings. The server derives none of them - it publishes what
241
+ * `lintCarve` reports - so what is pinned here is that the passthrough works
242
+ * and that the engine still emits each id under the pinned build. Nothing
243
+ * asserted it before, so a passthrough that stopped would have been silent.
244
+ */
245
+ const LINT_CASES = [
246
+ ['figure-group-nested', '::: figure\n::: figure\nBody.\n:::\n:::\n^ Figure #: outer\n'],
247
+ ['figure-group-opener-metadata', '::: figure "T"\n![a](a.png)\n^ (a) A\n:::\n'],
248
+ ['figure-group-panel-number', '::: figure\n![a](a.png)\n^ Figure #: panel\n:::\n^ Figure #: group\n'],
249
+ ['figure-group-empty', '::: figure\nJust text.\n:::\n^ Figure #: g\n'],
250
+ ['figure-group-single-panel', '::: figure\n![a](a.png)\n^ (a) A\n:::\n^ Figure #: g\n'],
251
+ ];
252
+ for (const [code, source] of LINT_CASES) {
253
+ test(`${code} reaches the server's diagnostics`, () => {
254
+ assert.ok(lintCarve(source).some((warning) => warning.rule === code), `the pinned engine no longer emits ${code}`);
255
+ assert.ok(analyzeCarve(source).diagnostics.some((diagnostic) => diagnostic.code === code), `${code} did not reach the server: ${JSON.stringify(analyzeCarve(source).diagnostics.map((d) => d.code))}`);
256
+ });
257
+ }
258
+ test('a well-formed group reports none of them', () => {
259
+ // CONTROL. Every case above differs from this document in one line, so a
260
+ // passthrough that published a fixed list would look identical up there.
261
+ const clean = '::: figure\n![a](a.png)\n^ (a) A\n\n![b](b.png)\n^ (b) B\n:::\n^ Figure #: g\n';
262
+ const codes = analyzeCarve(clean).diagnostics.map((diagnostic) => diagnostic.code);
263
+ assert.deepEqual(codes.filter((code) => String(code).startsWith('figure-group-')), []);
264
+ });
265
+ //# sourceMappingURL=composite-figure-crossref.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"composite-figure-crossref.test.js","sourceRoot":"","sources":["../src/composite-figure-crossref.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,76 @@
1
+ import assert from 'node:assert/strict';
2
+ import test from 'node:test';
3
+ import { parse, resolve } from '@markup-carve/carve';
4
+ import { completionAt } from './completion.js';
5
+ import { foldingRanges } from './folding.js';
6
+ import { hoverAt } from './hover.js';
7
+ import { semanticTokens } from './semantic.js';
8
+ /*
9
+ * Composite figures across the four features that read block types (PART 9 §4c,
10
+ * markup-carve/carve#1215).
11
+ *
12
+ * A BARE `::: figure` opener - the fence, its separator, the kind word, and
13
+ * NOTHING else - is ONE figure of ordered panels, and the engine normalizes it
14
+ * to a `figure_group` node. An opener carrying a quoted title or a `[label]` is
15
+ * not that production at all and stays a generic container.
16
+ *
17
+ * Every feature here switches on `node.type` with a default that does nothing,
18
+ * so a node type the engine grew and the server never learned is INVISIBLE
19
+ * rather than a type error: the container simply stops folding, hovering and
20
+ * tokenizing, and every existing test stays green. That is the failure this file
21
+ * is here to catch, which is why the first test asserts the engine's shape
22
+ * directly - if the dependency stops producing `figure_group`, this file should
23
+ * say so plainly rather than reporting four unrelated feature failures.
24
+ */
25
+ const GROUP = '::: figure\n![one](a.png)\n^ (a) One\n:::\n^ Figure #: Group caption\n';
26
+ const TITLED = '::: figure "A titled figure div"\n![one](a.png)\n^ (a) One\n:::\n';
27
+ const LABELLED = '::: figure [g]\nBody.\n:::\n';
28
+ const topLevelTypes = (source) => resolve(parse(source, { positions: true })).children.map((node) => node.type);
29
+ test('the pinned engine normalizes a bare figure fence to a figure_group', () => {
30
+ assert.deepEqual(topLevelTypes(GROUP), ['figure_group']);
31
+ });
32
+ test('a title or a label leaves it a generic container', () => {
33
+ // The control for every case below. These two differ from GROUP only in the
34
+ // tail of one line, so a reading that fires on the kind word alone would
35
+ // report them as groups and nothing else here would notice.
36
+ assert.deepEqual(topLevelTypes(TITLED), ['admonition']);
37
+ assert.deepEqual(topLevelTypes(LABELLED), ['admonition']);
38
+ });
39
+ test('a composite figure folds', () => {
40
+ const ranges = foldingRanges(GROUP);
41
+ assert.ok(ranges.some((range) => range.startLine === 0 && range.endLine >= 3), `no fold for the group: ${JSON.stringify(ranges)}`);
42
+ });
43
+ test('the opener carries the reserved kind word as a type token', () => {
44
+ const opener = semanticTokens(GROUP).filter((token) => token.line === 0);
45
+ assert.ok(opener.length > 0, 'the opener line produced no token at all');
46
+ assert.equal(opener[0].type, 'type');
47
+ // `::: figure` - the whole reserved opener, not just the fence run.
48
+ assert.equal(opener[0].character, 0);
49
+ assert.equal(opener[0].length, 10);
50
+ });
51
+ test('the group caption after the closing fence is tokenized', () => {
52
+ // Line 4, the `^ ` line BELOW the closer. It is the group's caption and it
53
+ // sits outside the container, which is the one placement §4c adds: read from
54
+ // any child instead of from the group, and this line has no token at all.
55
+ assert.ok(semanticTokens(GROUP).some((token) => token.line === 4), 'the caption line below the closing fence produced no token');
56
+ });
57
+ test('hovering a composite figure describes the group, not an admonition', () => {
58
+ const hover = hoverAt(GROUP, { line: 0, character: 4 });
59
+ const text = typeof hover?.contents === 'object' && 'value' in hover.contents ? hover.contents.value : '';
60
+ assert.match(text, /Composite Figure/);
61
+ });
62
+ test('a titled figure opener still hovers as an admonition', () => {
63
+ const hover = hoverAt(TITLED, { line: 0, character: 4 });
64
+ const text = typeof hover?.contents === 'object' && 'value' in hover.contents ? hover.contents.value : '';
65
+ assert.match(text, /Admonition/);
66
+ });
67
+ test('a colon fence offers figure, and not as a ninth admonition kind', () => {
68
+ const items = completionAt(':::', { line: 0, character: 3 });
69
+ const figure = items.find((item) => item.label === 'figure');
70
+ assert.ok(figure, `figure is not offered: ${items.map((i) => i.label).join(',')}`);
71
+ assert.equal(figure.detail, 'Composite figure');
72
+ // The eight are still there and still say what they are.
73
+ const note = items.find((item) => item.label === 'note');
74
+ assert.equal(note?.detail, 'Admonition kind');
75
+ });
76
+ //# sourceMappingURL=composite-figure.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"composite-figure.test.js","sourceRoot":"","sources":["../src/composite-figure.test.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,oBAAoB,CAAA;AACvC,OAAO,IAAI,MAAM,WAAW,CAAA;AAC5B,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AACpC,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAE9C;;;;;;;;;;;;;;;;GAgBG;AAEH,MAAM,KAAK,GAAG,wEAAwE,CAAA;AACtF,MAAM,MAAM,GAAG,mEAAmE,CAAA;AAClF,MAAM,QAAQ,GAAG,8BAA8B,CAAA;AAE/C,MAAM,aAAa,GAAG,CAAC,MAAc,EAAY,EAAE,CACjD,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AAE/E,IAAI,CAAC,oEAAoE,EAAE,GAAG,EAAE;IAC9E,MAAM,CAAC,SAAS,CAAC,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC,cAAc,CAAC,CAAC,CAAA;AAC1D,CAAC,CAAC,CAAA;AAEF,IAAI,CAAC,kDAAkD,EAAE,GAAG,EAAE;IAC5D,4EAA4E;IAC5E,yEAAyE;IACzE,4DAA4D;IAC5D,MAAM,CAAC,SAAS,CAAC,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,CAAA;IACvD,MAAM,CAAC,SAAS,CAAC,aAAa,CAAC,QAAQ,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,CAAA;AAC3D,CAAC,CAAC,CAAA;AAEF,IAAI,CAAC,0BAA0B,EAAE,GAAG,EAAE;IACpC,MAAM,MAAM,GAAG,aAAa,CAAC,KAAK,CAAC,CAAA;IACnC,MAAM,CAAC,EAAE,CACP,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,SAAS,KAAK,CAAC,IAAI,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC,EACnE,0BAA0B,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CACnD,CAAA;AACH,CAAC,CAAC,CAAA;AAEF,IAAI,CAAC,2DAA2D,EAAE,GAAG,EAAE;IACrE,MAAM,MAAM,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,CAAC,CAAA;IACxE,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,0CAA0C,CAAC,CAAA;IACxE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;IACpC,oEAAoE;IACpE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,CAAA;IACpC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;AACpC,CAAC,CAAC,CAAA;AAEF,IAAI,CAAC,wDAAwD,EAAE,GAAG,EAAE;IAClE,2EAA2E;IAC3E,6EAA6E;IAC7E,0EAA0E;IAC1E,MAAM,CAAC,EAAE,CACP,cAAc,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,CAAC,EACvD,4DAA4D,CAC7D,CAAA;AACH,CAAC,CAAC,CAAA;AAEF,IAAI,CAAC,oEAAoE,EAAE,GAAG,EAAE;IAC9E,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC,CAAA;IACvD,MAAM,IAAI,GAAG,OAAO,KAAK,EAAE,QAAQ,KAAK,QAAQ,IAAI,OAAO,IAAI,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAA;IACzG,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,kBAAkB,CAAC,CAAA;AACxC,CAAC,CAAC,CAAA;AAEF,IAAI,CAAC,sDAAsD,EAAE,GAAG,EAAE;IAChE,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC,CAAA;IACxD,MAAM,IAAI,GAAG,OAAO,KAAK,EAAE,QAAQ,KAAK,QAAQ,IAAI,OAAO,IAAI,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAA;IACzG,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,YAAY,CAAC,CAAA;AAClC,CAAC,CAAC,CAAA;AAEF,IAAI,CAAC,iEAAiE,EAAE,GAAG,EAAE;IAC3E,MAAM,KAAK,GAAG,YAAY,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC,CAAA;IAC5D,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAA;IAC5D,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,0BAA0B,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;IAClF,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAA;IAC/C,yDAAyD;IACzD,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,KAAK,MAAM,CAAC,CAAA;IACxD,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,iBAAiB,CAAC,CAAA;AAC/C,CAAC,CAAC,CAAA"}
@@ -1,12 +1,14 @@
1
1
  import { type Location, type Position } from 'vscode-languageserver/node.js';
2
+ import type { IncludeOptions } from './includes.js';
2
3
  /**
3
4
  * Go-to-definition for Carve constructs:
4
5
  *
5
- * - Cross-reference `</#id>` -> the heading whose generated id is `id`
6
+ * - Cross-reference `</#id>` -> the heading whose generated id is `id`,
7
+ * or the captioned host carrying it
6
8
  * - Fragment link `[text](#id)` -> same (href starts with `#`)
7
9
  * - Footnote ref `[^name]` -> the `[^name]:` definition line
8
10
  * - Link reference `[text][ref]` -> the `[ref]:` definition line
9
11
  * - Citation `[@key]` -> the `[@key]:` definition line
10
12
  * - Wikilink `[[Page]]` -> heading whose text matches Page (best-effort)
11
13
  */
12
- export declare function definitionAt(uri: string, source: string, position: Position): Location | null;
14
+ export declare function definitionAt(uri: string, source: string, position: Position, includes?: IncludeOptions): Location | null;