aws-iam-language-server 0.0.12 → 0.0.14

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 (53) hide show
  1. package/package.json +1 -1
  2. package/readme.md +12 -0
  3. package/src/handlers/completion/action-value.d.ts +2 -0
  4. package/src/handlers/completion/action-value.js +1 -1
  5. package/src/handlers/completion/condition-key.d.ts +2 -0
  6. package/src/handlers/completion/condition-key.js +3 -3
  7. package/src/handlers/completion/index.d.ts +2 -2
  8. package/src/handlers/completion/index.js +4 -4
  9. package/src/handlers/completion/principal-identifier-completions.d.ts +1 -1
  10. package/src/handlers/diagnostics/resource.js +24 -9
  11. package/src/handlers/diagnostics/utils.js +1 -13
  12. package/src/handlers/document-link/document-link.js +1 -3
  13. package/src/handlers/hover/action-value.d.ts +3 -0
  14. package/src/handlers/hover/action-value.js +21 -0
  15. package/src/handlers/hover/condition-block.d.ts +3 -0
  16. package/src/handlers/hover/condition-block.js +18 -0
  17. package/src/handlers/hover/condition-key.d.ts +3 -0
  18. package/src/handlers/hover/condition-key.js +53 -0
  19. package/src/handlers/hover/condition-operator.d.ts +3 -0
  20. package/src/handlers/hover/condition-operator.js +14 -0
  21. package/src/handlers/hover/effect-value.d.ts +3 -0
  22. package/src/handlers/hover/effect-value.js +17 -0
  23. package/src/handlers/hover/index.d.ts +3 -0
  24. package/src/handlers/hover/index.js +69 -0
  25. package/src/handlers/hover/principal-block.d.ts +3 -0
  26. package/src/handlers/hover/principal-block.js +17 -0
  27. package/src/handlers/hover/principal-type.d.ts +3 -0
  28. package/src/handlers/hover/principal-type.js +25 -0
  29. package/src/handlers/hover/principal-typed-value.d.ts +3 -0
  30. package/src/handlers/hover/principal-typed-value.js +118 -0
  31. package/src/handlers/hover/principal-value.d.ts +3 -0
  32. package/src/handlers/hover/principal-value.js +13 -0
  33. package/src/handlers/hover/resource-value.d.ts +3 -0
  34. package/src/handlers/hover/resource-value.js +45 -0
  35. package/src/handlers/hover/statement-block.d.ts +3 -0
  36. package/src/handlers/hover/statement-block.js +14 -0
  37. package/src/handlers/hover/statement-key.d.ts +3 -0
  38. package/src/handlers/hover/statement-key.js +14 -0
  39. package/src/lib/iam-policy/arn.d.ts +17 -0
  40. package/src/lib/iam-policy/arn.js +77 -0
  41. package/src/lib/iam-policy/location.d.ts +31 -1
  42. package/src/lib/iam-policy/location.js +56 -19
  43. package/src/lib/iam-policy/partitions.d.ts +4 -0
  44. package/src/lib/iam-policy/partitions.js +6 -0
  45. package/src/lib/iam-policy/reference/services.d.ts +5 -3
  46. package/src/lib/iam-policy/reference/services.js +58 -19
  47. package/src/lib/iam-policy/reference/types.d.ts +5 -0
  48. package/src/lib/treesitter/base.d.ts +3 -8
  49. package/src/lib/treesitter/base.js +3 -3
  50. package/src/lib/treesitter/hcl.js +32 -24
  51. package/src/lib/treesitter/json.js +14 -11
  52. package/src/lib/treesitter/yaml.js +30 -27
  53. package/src/server.js +5 -3
@@ -11,7 +11,9 @@ export class TreeHcl extends TreeBase {
11
11
  const node = this.getNodeAtPosition(uri, position);
12
12
  if (!node)
13
13
  return null;
14
- const nodeBefore = position.column > 0 ? this.getNodeAtPosition(uri, { line: position.line, column: position.column - 1 }) : null;
14
+ const nodeBefore = position.character > 0
15
+ ? this.getNodeAtPosition(uri, { line: position.line, character: position.character - 1 })
16
+ : null;
15
17
  // Try jsonencode mode first (more specific structure)
16
18
  const jsonencodeContext = this.#tryJsonencodeMode(node, nodeBefore, position);
17
19
  if (jsonencodeContext)
@@ -174,8 +176,8 @@ export class TreeHcl extends TreeBase {
174
176
  const valueRange = expression
175
177
  ? nodeRange(expression)
176
178
  : {
177
- start: { line: child.endPosition.row, column: child.endPosition.column },
178
- end: { line: child.endPosition.row, column: child.endPosition.column },
179
+ start: { line: child.endPosition.row, character: child.endPosition.column },
180
+ end: { line: child.endPosition.row, character: child.endPosition.column },
179
181
  };
180
182
  entries.push({ key: id.text, keyRange, values, valueRange });
181
183
  }
@@ -242,8 +244,8 @@ export class TreeHcl extends TreeBase {
242
244
  const valueRange = valueExpression
243
245
  ? nodeRange(valueExpression)
244
246
  : {
245
- start: { line: child.endPosition.row, column: child.endPosition.column },
246
- end: { line: child.endPosition.row, column: child.endPosition.column },
247
+ start: { line: child.endPosition.row, character: child.endPosition.column },
248
+ end: { line: child.endPosition.row, character: child.endPosition.column },
247
249
  };
248
250
  const nestedKeys = new Set(['Condition', 'Principal', 'NotPrincipal']);
249
251
  let children;
@@ -310,8 +312,8 @@ export class TreeHcl extends TreeBase {
310
312
  const valueRange = valueExpression
311
313
  ? nodeRange(valueExpression)
312
314
  : {
313
- start: { line: child.endPosition.row, column: child.endPosition.column },
314
- end: { line: child.endPosition.row, column: child.endPosition.column },
315
+ start: { line: child.endPosition.row, character: child.endPosition.column },
316
+ end: { line: child.endPosition.row, character: child.endPosition.column },
315
317
  };
316
318
  let nestedObject;
317
319
  if (valueExpression) {
@@ -424,8 +426,8 @@ export class TreeHcl extends TreeBase {
424
426
  }
425
427
  if (role === null)
426
428
  role = 'key';
427
- const { partial, value } = this.#extractJsonencodePartialAndValue(cursorNode, position);
428
- return { keys, role, partial, value };
429
+ const { partial, value, range } = this.#extractJsonencodePartialAndValue(cursorNode, position);
430
+ return { keys, role, partial, value, range };
429
431
  }
430
432
  #getObjectElemKey(element) {
431
433
  const keyExpression = element.namedChildren.find((child) => child.type === 'expression');
@@ -457,10 +459,11 @@ export class TreeHcl extends TreeBase {
457
459
  while (current) {
458
460
  if (current.type === 'identifier' || current.type === 'template_literal') {
459
461
  const value = current.text;
462
+ const range = nodeRange(current);
460
463
  if (position.line === current.startPosition.row) {
461
- return { partial: value.slice(0, position.column - current.startPosition.column), value };
464
+ return { partial: value.slice(0, position.character - current.startPosition.column), value, range };
462
465
  }
463
- return { partial: value, value };
466
+ return { partial: value, value, range };
464
467
  }
465
468
  if (current.type === 'object' || current.type === 'object_elem')
466
469
  break;
@@ -488,7 +491,7 @@ export class TreeHcl extends TreeBase {
488
491
  return this.#pickBestCursorContext(context1, context2);
489
492
  }
490
493
  // Cursor is on the block itself (outside body span) — statement-key level
491
- const { partial, value } = this.#extractBlockPartialAndValue(node, position);
494
+ const { partial, value, range } = this.#extractBlockPartialAndValue(node, position);
492
495
  // Check for incomplete attributes on the same line (may be in ERROR nodes
493
496
  // when tree-sitter can't parse the body due to a missing value)
494
497
  const searchParent = statementBody ?? statementBlock;
@@ -515,6 +518,7 @@ export class TreeHcl extends TreeBase {
515
518
  role: 'key',
516
519
  partial,
517
520
  value,
521
+ range,
518
522
  policyFormat: 'hcl-block',
519
523
  };
520
524
  }
@@ -603,8 +607,8 @@ export class TreeHcl extends TreeBase {
603
607
  }
604
608
  if (role === null)
605
609
  role = 'key';
606
- const { partial, value } = this.#extractBlockPartialAndValue(cursorNode, position);
607
- return { keys, role, partial, value };
610
+ const { partial, value, range } = this.#extractBlockPartialAndValue(cursorNode, position);
611
+ return { keys, role, partial, value, range };
608
612
  }
609
613
  #findEnclosingBlock(node, blockName, statementBody) {
610
614
  let current = node;
@@ -659,10 +663,11 @@ export class TreeHcl extends TreeBase {
659
663
  while (current) {
660
664
  if (current.type === 'identifier' || current.type === 'template_literal') {
661
665
  const value = current.text;
666
+ const range = nodeRange(current);
662
667
  if (position.line === current.startPosition.row) {
663
- return { partial: value.slice(0, position.column - current.startPosition.column), value };
668
+ return { partial: value.slice(0, position.character - current.startPosition.column), value, range };
664
669
  }
665
- return { partial: value, value };
670
+ return { partial: value, value, range };
666
671
  }
667
672
  if (current.type === 'body' || current.type === 'attribute' || current.type === 'block')
668
673
  break;
@@ -711,7 +716,7 @@ export class TreeHcl extends TreeBase {
711
716
  (nodeBefore && this.#isInsideQuote(nodeBefore)) ||
712
717
  errorNode.children.some((child) => child.type === 'quoted_template_start' &&
713
718
  child.startPosition.row === position.line &&
714
- child.endPosition.column <= position.column);
719
+ child.endPosition.column <= position.character);
715
720
  if (!hasQuoteOnLine)
716
721
  return null;
717
722
  let foundStatement = false;
@@ -804,12 +809,13 @@ export class TreeHcl extends TreeBase {
804
809
  // extract from the template_literal. Otherwise extract from ERROR node text.
805
810
  let partial = '';
806
811
  let value = '';
812
+ let range;
807
813
  if (!lastKeyFromAttribute) {
808
814
  if (this.#isInsideQuote(node)) {
809
- ({ partial, value } = this.#extractQuotedPartialAndValue(node, position));
815
+ ({ partial, value, range } = this.#extractQuotedPartialAndValue(node, position));
810
816
  }
811
817
  else if (nodeBefore && this.#isInsideQuote(nodeBefore)) {
812
- ({ partial, value } = this.#extractQuotedPartialAndValue(nodeBefore, position));
818
+ ({ partial, value, range } = this.#extractQuotedPartialAndValue(nodeBefore, position));
813
819
  }
814
820
  else {
815
821
  ({ partial, value } = this.#extractPartialAndValueFromErrorNode(errorNode, position));
@@ -828,6 +834,7 @@ export class TreeHcl extends TreeBase {
828
834
  role: 'value',
829
835
  partial,
830
836
  value,
837
+ range,
831
838
  policyFormat,
832
839
  };
833
840
  }
@@ -840,10 +847,11 @@ export class TreeHcl extends TreeBase {
840
847
  while (current) {
841
848
  if (current.type === 'template_literal') {
842
849
  const value = current.text;
850
+ const range = nodeRange(current);
843
851
  if (position.line === current.startPosition.row) {
844
- return { partial: value.slice(0, position.column - current.startPosition.column), value };
852
+ return { partial: value.slice(0, position.character - current.startPosition.column), value, range };
845
853
  }
846
- return { partial: '', value };
854
+ return { partial: '', value, range };
847
855
  }
848
856
  if (current.type === 'quoted_template_start')
849
857
  return { partial: '', value: '' };
@@ -865,10 +873,10 @@ export class TreeHcl extends TreeBase {
865
873
  // like attributes have endPosition from a different row)
866
874
  if (child.endPosition.row !== position.line)
867
875
  continue;
868
- if (child.endPosition.column <= position.column) {
876
+ if (child.endPosition.column <= position.character) {
869
877
  afterColumn = child.endPosition.column;
870
878
  }
871
- else if (nextChildColumn === null && child.startPosition.column > position.column) {
879
+ else if (nextChildColumn === null && child.startPosition.column > position.character) {
872
880
  nextChildColumn = child.startPosition.column;
873
881
  }
874
882
  }
@@ -878,7 +886,7 @@ export class TreeHcl extends TreeBase {
878
886
  return { partial: '', value: '' };
879
887
  const line = lines[lineIndex];
880
888
  const startColumn = lineIndex === 0 ? errorNode.startPosition.column : 0;
881
- const partial = line.slice(afterColumn - startColumn, position.column - startColumn);
889
+ const partial = line.slice(afterColumn - startColumn, position.character - startColumn);
882
890
  const valueEnd = nextChildColumn !== null ? nextChildColumn - startColumn : line.length;
883
891
  const value = line.slice(afterColumn - startColumn, valueEnd);
884
892
  return { partial, value };
@@ -11,7 +11,9 @@ export class TreeJson extends TreeBase {
11
11
  const node = this.getNodeAtPosition(uri, position);
12
12
  if (!node)
13
13
  return null;
14
- const nodeBefore = position.column > 0 ? this.getNodeAtPosition(uri, { line: position.line, column: position.column - 1 }) : null;
14
+ const nodeBefore = position.character > 0
15
+ ? this.getNodeAtPosition(uri, { line: position.line, character: position.character - 1 })
16
+ : null;
15
17
  // Cursor right after closing quote — no completions
16
18
  if (this.#isCursorAfterClosingQuote(nodeBefore))
17
19
  return null;
@@ -36,8 +38,8 @@ export class TreeJson extends TreeBase {
36
38
  if (!node)
37
39
  return null;
38
40
  let statementObject = this.#findStatementObject(node);
39
- if (!statementObject && position.column > 0) {
40
- const nodeBefore = this.getNodeAtPosition(uri, { line: position.line, column: position.column - 1 });
41
+ if (!statementObject && position.character > 0) {
42
+ const nodeBefore = this.getNodeAtPosition(uri, { line: position.line, character: position.character - 1 });
41
43
  if (nodeBefore)
42
44
  statementObject = this.#findStatementObject(nodeBefore);
43
45
  }
@@ -50,8 +52,8 @@ export class TreeJson extends TreeBase {
50
52
  if (!node)
51
53
  return [];
52
54
  let statementObject = this.#findStatementObject(node);
53
- if (!statementObject && position.column > 0) {
54
- const nodeBefore = this.getNodeAtPosition(uri, { line: position.line, column: position.column - 1 });
55
+ if (!statementObject && position.character > 0) {
56
+ const nodeBefore = this.getNodeAtPosition(uri, { line: position.line, character: position.character - 1 });
55
57
  if (nodeBefore)
56
58
  statementObject = this.#findStatementObject(nodeBefore);
57
59
  }
@@ -178,8 +180,8 @@ export class TreeJson extends TreeBase {
178
180
  const valueNode = pair.namedChildren[1];
179
181
  if (!valueNode) {
180
182
  return {
181
- start: { line: pair.endPosition.row, column: pair.endPosition.column },
182
- end: { line: pair.endPosition.row, column: pair.endPosition.column },
183
+ start: { line: pair.endPosition.row, character: pair.endPosition.column },
184
+ end: { line: pair.endPosition.row, character: pair.endPosition.column },
183
185
  };
184
186
  }
185
187
  return nodeRange(valueNode);
@@ -247,8 +249,8 @@ export class TreeJson extends TreeBase {
247
249
  }
248
250
  if (role === null)
249
251
  role = 'key';
250
- const { partial, value } = this.#extractPartialAndValue(cursorNode, position);
251
- return { keys, role, partial, value };
252
+ const { partial, value, range } = this.#extractPartialAndValue(cursorNode, position);
253
+ return { keys, role, partial, value, range };
252
254
  }
253
255
  /**
254
256
  * Walk up from a node to find an object that sits inside a Statement array.
@@ -367,10 +369,11 @@ export class TreeJson extends TreeBase {
367
369
  while (current) {
368
370
  if (current.type === 'string_content') {
369
371
  const value = current.text;
372
+ const range = nodeRange(current);
370
373
  if (position.line === current.startPosition.row) {
371
- return { partial: value.slice(0, position.column - current.startPosition.column), value };
374
+ return { partial: value.slice(0, position.character - current.startPosition.column), value, range };
372
375
  }
373
- return { partial: value, value };
376
+ return { partial: value, value, range };
374
377
  }
375
378
  if (current.type === 'object' || current.type === 'pair')
376
379
  break;
@@ -11,7 +11,9 @@ export class TreeYaml extends TreeBase {
11
11
  const node = this.getNodeAtPosition(uri, position);
12
12
  if (!node)
13
13
  return null;
14
- const nodeBefore = position.column > 0 ? this.getNodeAtPosition(uri, { line: position.line, column: position.column - 1 }) : null;
14
+ const nodeBefore = position.character > 0
15
+ ? this.getNodeAtPosition(uri, { line: position.line, character: position.character - 1 })
16
+ : null;
15
17
  const root = this.getTree(uri)?.rootNode;
16
18
  if (!root)
17
19
  return null;
@@ -189,8 +191,8 @@ export class TreeYaml extends TreeBase {
189
191
  if (pair.namedChildren.length < 2) {
190
192
  // No value — zero-width range at key end
191
193
  return {
192
- start: { line: pair.endPosition.row, column: pair.endPosition.column },
193
- end: { line: pair.endPosition.row, column: pair.endPosition.column },
194
+ start: { line: pair.endPosition.row, character: pair.endPosition.column },
195
+ end: { line: pair.endPosition.row, character: pair.endPosition.column },
194
196
  };
195
197
  }
196
198
  return nodeRange(pair.namedChildren[1]);
@@ -236,10 +238,10 @@ export class TreeYaml extends TreeBase {
236
238
  let extendedMatch = null;
237
239
  for (const mapping of candidates) {
238
240
  const pastEnd = position.line > mapping.endPosition.row ||
239
- (position.line === mapping.endPosition.row && position.column >= mapping.endPosition.column);
241
+ (position.line === mapping.endPosition.row && position.character >= mapping.endPosition.column);
240
242
  if (!pastEnd)
241
243
  continue;
242
- if (position.column < mapping.startPosition.column)
244
+ if (position.character < mapping.startPosition.column)
243
245
  continue;
244
246
  // Don't extend across sibling statement items. If a sibling block_sequence_item
245
247
  // starts between this mapping's end and the cursor, the cursor is in a different statement.
@@ -284,12 +286,13 @@ export class TreeYaml extends TreeBase {
284
286
  const resolved = this.#resolveWithinMapping(statementMapping, position);
285
287
  if (!resolved)
286
288
  return null;
287
- const { partial, value } = this.#extractPartialAndValue(cursorNode, position);
289
+ const { partial, value, range } = this.#extractPartialAndValue(cursorNode, position);
288
290
  return {
289
291
  keys: resolved.keys,
290
292
  role: resolved.role,
291
293
  partial,
292
294
  value,
295
+ range,
293
296
  policyFormat: 'standard',
294
297
  };
295
298
  }
@@ -413,7 +416,7 @@ export class TreeYaml extends TreeBase {
413
416
  const keyColumn = ancestorMapping
414
417
  ? ancestorMapping.startPosition.column
415
418
  : statementMapping.startPosition.column;
416
- if (position.column > keyColumn)
419
+ if (position.character > keyColumn)
417
420
  return null;
418
421
  }
419
422
  }
@@ -443,7 +446,7 @@ export class TreeYaml extends TreeBase {
443
446
  const pairOnLine = current.namedChildren.find((child) => child.type === 'block_mapping_pair' &&
444
447
  child.startPosition.row === position.line &&
445
448
  child.namedChildren.length === 1 &&
446
- position.column > child.endPosition.column);
449
+ position.character > child.endPosition.column);
447
450
  if (pairOnLine) {
448
451
  const pairKey = this.#getPairKeyText(pairOnLine);
449
452
  if (pairKey) {
@@ -457,7 +460,7 @@ export class TreeYaml extends TreeBase {
457
460
  // When cursor lands on an inner block_mapping (not the statement mapping),
458
461
  // check if the cursor is actually outside this mapping (column < key column).
459
462
  // If so, skip it — the cursor belongs to a parent mapping level.
460
- if (current.id !== statementMapping.id && position.column < current.startPosition.column) {
463
+ if (current.id !== statementMapping.id && position.character < current.startPosition.column) {
461
464
  previous = current;
462
465
  current = current.parent;
463
466
  continue;
@@ -500,7 +503,7 @@ export class TreeYaml extends TreeBase {
500
503
  // If the cursor column matches the parent mapping's key column, the user
501
504
  // is typing a new sibling key, not editing this pair's value.
502
505
  const parentMapping = current.parent;
503
- const isAtParentKeyColumn = parentMapping?.type === 'block_mapping' && position.column === parentMapping.startPosition.column;
506
+ const isAtParentKeyColumn = parentMapping?.type === 'block_mapping' && position.character === parentMapping.startPosition.column;
504
507
  if (isOnKey || isAtParentKeyColumn) {
505
508
  role = 'key';
506
509
  }
@@ -532,10 +535,10 @@ export class TreeYaml extends TreeBase {
532
535
  }
533
536
  if (role === null)
534
537
  role = 'key';
535
- const { partial: extractedPartial, value: extractedValue } = this.#extractPartialAndValue(cursorNode, position);
538
+ const { partial: extractedPartial, value: extractedValue, range, } = this.#extractPartialAndValue(cursorNode, position);
536
539
  const partial = colonPartial || extractedPartial;
537
540
  const value = colonPartial ? colonPartial : extractedValue;
538
- return { keys, role, partial, value };
541
+ return { keys, role, partial, value, range };
539
542
  }
540
543
  /**
541
544
  * Resolve the cursor's position within a block_mapping by finding the pair covering
@@ -543,9 +546,9 @@ export class TreeYaml extends TreeBase {
543
546
  */
544
547
  #resolveWithinMapping(mapping, position) {
545
548
  const keyColumn = mapping.startPosition.column;
546
- if (position.column < keyColumn)
549
+ if (position.character < keyColumn)
547
550
  return null;
548
- if (position.column === keyColumn)
551
+ if (position.character === keyColumn)
549
552
  return { keys: [], role: 'key' };
550
553
  let pairBeforeCursor = null;
551
554
  for (const child of mapping.namedChildren) {
@@ -582,7 +585,7 @@ export class TreeYaml extends TreeBase {
582
585
  const valueSequence = this.#findValueBlockSequence(pairBeforeCursor);
583
586
  if (valueSequence &&
584
587
  position.line <= valueSequence.endPosition.row &&
585
- position.column >= valueSequence.startPosition.column) {
588
+ position.character >= valueSequence.startPosition.column) {
586
589
  return { keys: [pairKey], role: 'value' };
587
590
  }
588
591
  return null;
@@ -737,10 +740,10 @@ export class TreeYaml extends TreeBase {
737
740
  let current = node;
738
741
  while (current) {
739
742
  if (current.type === 'string_scalar') {
740
- return this.#sliceToPositionAndValue(current.text, current.startPosition.column, position, node);
743
+ return this.#sliceToPositionAndValue(current.text, current.startPosition.column, position, node, current);
741
744
  }
742
745
  if (current.type === 'double_quote_scalar' || current.type === 'single_quote_scalar') {
743
- return this.#sliceToPositionAndValue(current.text.slice(1, -1), current.startPosition.column + 1, position, node);
746
+ return this.#sliceToPositionAndValue(current.text.slice(1, -1), current.startPosition.column + 1, position, node, current);
744
747
  }
745
748
  if (current.type === 'block_mapping' || current.type === 'block_mapping_pair')
746
749
  break;
@@ -748,11 +751,11 @@ export class TreeYaml extends TreeBase {
748
751
  }
749
752
  return { partial: '', value: '' };
750
753
  }
751
- #sliceToPositionAndValue(text, startColumn, position, node) {
754
+ #sliceToPositionAndValue(text, startColumn, position, node, scalarNode) {
752
755
  if (position.line === node.startPosition.row) {
753
- return { partial: text.slice(0, position.column - startColumn), value: text };
756
+ return { partial: text.slice(0, position.character - startColumn), value: text, range: nodeRange(scalarNode) };
754
757
  }
755
- return { partial: text, value: text };
758
+ return { partial: text, value: text, range: nodeRange(scalarNode) };
756
759
  }
757
760
  /**
758
761
  * When tree-sitter produces a root-level ERROR (e.g., unterminated quote in
@@ -796,8 +799,8 @@ export class TreeYaml extends TreeBase {
796
799
  if (!keyText)
797
800
  continue;
798
801
  // Cursor within the key text — still typing the key
799
- if (position.column < child.endPosition.column) {
800
- const partial = keyText.slice(0, position.column - child.startPosition.column);
802
+ if (position.character < child.endPosition.column) {
803
+ const partial = keyText.slice(0, position.character - child.startPosition.column);
801
804
  return {
802
805
  keys: [],
803
806
  role: 'key',
@@ -807,7 +810,7 @@ export class TreeYaml extends TreeBase {
807
810
  };
808
811
  }
809
812
  // Cursor at key end — key is complete but ":" hasn't been typed yet
810
- if (position.column === child.endPosition.column) {
813
+ if (position.character === child.endPosition.column) {
811
814
  return null;
812
815
  }
813
816
  return {
@@ -826,7 +829,7 @@ export class TreeYaml extends TreeBase {
826
829
  continue;
827
830
  const valueText = this.#getPairValueText(child) ?? '';
828
831
  // If cursor is past the ERROR end (colon continuation), append ":"
829
- const colonSuffix = errorNode.endPosition.row === position.line && position.column > errorNode.endPosition.column ? ':' : '';
832
+ const colonSuffix = errorNode.endPosition.row === position.line && position.character > errorNode.endPosition.column ? ':' : '';
830
833
  const fullValue = valueText + colonSuffix;
831
834
  return {
832
835
  keys: [pairKey],
@@ -873,10 +876,10 @@ export class TreeYaml extends TreeBase {
873
876
  for (const child of errorNode.children) {
874
877
  if (child.startPosition.row !== position.line)
875
878
  continue;
876
- if (child.endPosition.column <= position.column) {
879
+ if (child.endPosition.column <= position.character) {
877
880
  afterColumn = child.endPosition.column;
878
881
  }
879
- else if (nextChildColumn === null && child.startPosition.column > position.column) {
882
+ else if (nextChildColumn === null && child.startPosition.column > position.character) {
880
883
  nextChildColumn = child.startPosition.column;
881
884
  }
882
885
  }
@@ -887,7 +890,7 @@ export class TreeYaml extends TreeBase {
887
890
  return { partial: '', value: '' };
888
891
  const line = lines[lineIndex];
889
892
  const startColumn = lineIndex === 0 ? errorNode.startPosition.column : 0;
890
- const partial = line.slice(afterColumn - startColumn, position.column - startColumn);
893
+ const partial = line.slice(afterColumn - startColumn, position.character - startColumn);
891
894
  const valueEnd = nextChildColumn !== null ? nextChildColumn - startColumn : line.length;
892
895
  const value = line.slice(afterColumn - startColumn, valueEnd);
893
896
  return { partial, value };
package/src/server.js CHANGED
@@ -1,11 +1,12 @@
1
1
  #!/usr/bin/env node
2
- import { createConnection, ProposedFeatures, TextDocumentSyncKind, TextDocuments } from 'vscode-languageserver/node.js';
2
+ import { createConnection, TextDocumentSyncKind, TextDocuments } from 'vscode-languageserver/node.js';
3
3
  import { TextDocument } from 'vscode-languageserver-textdocument';
4
4
  import { handleCompletionRequest } from "./handlers/completion/index.js";
5
5
  import { diagnosticsHandler } from "./handlers/diagnostics/diagnostics.js";
6
6
  import { documentLinkHandler } from "./handlers/document-link/document-link.js";
7
+ import { hoverHandler } from "./handlers/hover/index.js";
7
8
  import { TreeManager } from "./lib/treesitter/manager.js";
8
- const connection = createConnection(ProposedFeatures.all);
9
+ const connection = createConnection();
9
10
  const documents = new TextDocuments(TextDocument);
10
11
  const treeManager = new TreeManager(connection);
11
12
  connection.onInitialize(async () => {
@@ -16,7 +17,7 @@ connection.onInitialize(async () => {
16
17
  completionProvider: {
17
18
  triggerCharacters: ['"', ':', '*'],
18
19
  },
19
- hoverProvider: false,
20
+ hoverProvider: true,
20
21
  documentLinkProvider: {},
21
22
  },
22
23
  };
@@ -34,5 +35,6 @@ documents.onDidClose(async ({ document }) => {
34
35
  });
35
36
  connection.onCompletion((params) => handleCompletionRequest(params, documents, treeManager, connection));
36
37
  connection.onDocumentLinks((params) => documentLinkHandler(params, documents, treeManager, connection));
38
+ connection.onHover((params) => hoverHandler(params, treeManager, connection));
37
39
  documents.listen(connection);
38
40
  connection.listen();