@marko/language-server 0.12.8 → 0.12.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -571,7 +571,7 @@ function loadCompilerInfo(dir) {
571
571
  const rootDir = lassoPackageRoot.getRootDir(dir);
572
572
  const pkgPath = rootDir && resolveFrom.silent(rootDir, "@marko/compiler/package.json");
573
573
  const pkg = pkgPath && __require(pkgPath);
574
- const cache2 = /* @__PURE__ */ new Map();
574
+ const cache3 = /* @__PURE__ */ new Map();
575
575
  let translator = builtinTranslator;
576
576
  let compiler = builtinCompiler;
577
577
  if (pkg && /^5\./.test(pkg.version)) {
@@ -588,16 +588,16 @@ function loadCompilerInfo(dir) {
588
588
  }
589
589
  }
590
590
  return {
591
- cache: cache2,
591
+ cache: cache3,
592
592
  get lookup() {
593
- let lookup = cache2.get(lookupKey);
593
+ let lookup = cache3.get(lookupKey);
594
594
  if (lookup === void 0) {
595
595
  try {
596
596
  lookup = compiler.taglib.buildLookup(dir, translator);
597
597
  } catch {
598
598
  lookup = builtinInfo.lookup;
599
599
  }
600
- cache2.set(lookupKey, lookup);
600
+ cache3.set(lookupKey, lookup);
601
601
  }
602
602
  return lookup;
603
603
  },
@@ -856,11 +856,147 @@ function AttrName({
856
856
  return completions;
857
857
  }
858
858
 
859
+ // src/service/marko/complete/AttrValue.ts
860
+ import path3 from "path";
861
+ import {
862
+ CompletionItemKind as CompletionItemKind4,
863
+ Range as Range2,
864
+ TextEdit as TextEdit4
865
+ } from "vscode-languageserver";
866
+
867
+ // src/service/marko/util/is-document-link-attr.ts
868
+ var linkedAttrs = /* @__PURE__ */ new Map([
869
+ [
870
+ "src",
871
+ /* @__PURE__ */ new Set([
872
+ "audio",
873
+ "embed",
874
+ "iframe",
875
+ "img",
876
+ "input",
877
+ "script",
878
+ "source",
879
+ "track",
880
+ "video"
881
+ ])
882
+ ],
883
+ ["href", /* @__PURE__ */ new Set(["a", "area", "link"])],
884
+ ["data", /* @__PURE__ */ new Set(["object"])],
885
+ ["poster", /* @__PURE__ */ new Set(["video"])]
886
+ ]);
887
+ function isDocumentLinkAttr(doc, tag, attr) {
888
+ var _a, _b;
889
+ return tag.nameText && attr.type === 8 /* AttrNamed */ && ((_a = attr.value) == null ? void 0 : _a.type) === 11 /* AttrValue */ && /^['"]$/.test(doc.getText()[attr.value.value.start]) && ((_b = linkedAttrs.get(doc.getText().slice(attr.name.start, attr.name.end))) == null ? void 0 : _b.has(tag.nameText)) || false;
890
+ }
891
+
892
+ // src/utils/file-system.ts
893
+ import fs from "fs/promises";
894
+ import { FileType } from "vscode-css-languageservice";
895
+ import { fileURLToPath } from "url";
896
+ var file_system_default = {
897
+ stat,
898
+ readDirectory
899
+ };
900
+ async function stat(uri) {
901
+ let type = FileType.Unknown;
902
+ let ctime = -1;
903
+ let mtime = -1;
904
+ let size = -1;
905
+ try {
906
+ const stat2 = await fs.stat(fileURLToPath(uri));
907
+ if (stat2.isDirectory())
908
+ type = FileType.Directory;
909
+ else if (stat2.isFile())
910
+ type = FileType.File;
911
+ ctime = stat2.ctimeMs;
912
+ mtime = stat2.mtimeMs;
913
+ size = stat2.size;
914
+ } catch {
915
+ }
916
+ return {
917
+ type,
918
+ ctime,
919
+ mtime,
920
+ size
921
+ };
922
+ }
923
+ async function readDirectory(uri) {
924
+ try {
925
+ const entries = await fs.readdir(fileURLToPath(uri));
926
+ const base = uri.at(-1) === "/" ? uri : `${uri}/`;
927
+ return (await Promise.all(entries.map(async (entry) => [entry, (await stat(new URL(entry, base).toString())).type]))).filter(([, type]) => type !== FileType.Unknown);
928
+ } catch {
929
+ return [];
930
+ }
931
+ }
932
+
933
+ // src/utils/resolve-url.ts
934
+ function resolveUrl(to, base) {
935
+ try {
936
+ const url = new URL(to, base);
937
+ if (url.protocol === "file:")
938
+ return url.toString();
939
+ } catch {
940
+ return void 0;
941
+ }
942
+ }
943
+
944
+ // src/service/marko/complete/AttrValue.ts
945
+ async function AttrValue({
946
+ document,
947
+ offset,
948
+ node,
949
+ parsed,
950
+ code
951
+ }) {
952
+ const attr = node.parent;
953
+ if (isDocumentLinkAttr(document, attr.parent, attr)) {
954
+ const start = node.value.start + 1;
955
+ if (code[start] !== ".")
956
+ return;
957
+ const end = node.value.end - 1;
958
+ const relativeOffset = offset - start;
959
+ const rawValue = parsed.read({
960
+ start,
961
+ end
962
+ });
963
+ const segmentStart = rawValue.lastIndexOf("/", relativeOffset);
964
+ if (segmentStart === -1)
965
+ return;
966
+ const req = rawValue.slice(0, segmentStart);
967
+ const uri = resolveUrl(req, document.uri);
968
+ if (uri) {
969
+ const result = [];
970
+ const curFile = req === "." ? path3.basename(document.uri) : void 0;
971
+ const replaceRange = Range2.create(document.positionAt(start + segmentStart + 1), document.positionAt(start + rawValue.length));
972
+ for (const [entry, type] of await file_system_default.readDirectory(uri)) {
973
+ if (entry[0] !== "." && entry !== curFile) {
974
+ result.push(type === FileType.Directory ? {
975
+ label: `${entry}/`,
976
+ kind: CompletionItemKind4.Folder,
977
+ textEdit: TextEdit4.replace(replaceRange, `${entry}/`),
978
+ command: {
979
+ title: "Suggest",
980
+ command: "editor.action.triggerSuggest"
981
+ }
982
+ } : {
983
+ label: entry,
984
+ kind: CompletionItemKind4.File,
985
+ textEdit: TextEdit4.replace(replaceRange, entry)
986
+ });
987
+ }
988
+ }
989
+ return result;
990
+ }
991
+ }
992
+ }
993
+
859
994
  // src/service/marko/complete/index.ts
860
995
  var handlers = {
861
996
  Tag,
862
997
  OpenTagName,
863
- AttrName
998
+ AttrName,
999
+ AttrValue
864
1000
  };
865
1001
  var doComplete = async (doc, params) => {
866
1002
  var _a;
@@ -879,15 +1015,15 @@ var doComplete = async (doc, params) => {
879
1015
  };
880
1016
 
881
1017
  // src/service/marko/validate.ts
882
- import { Diagnostic, DiagnosticSeverity, Range as Range2 } from "vscode-languageserver";
1018
+ import { Diagnostic, DiagnosticSeverity, Range as Range3 } from "vscode-languageserver";
883
1019
  var markoErrorRegExp = /^(.+?)(?:\((\d+)(?:\s*,\s*(\d+))?\))?: (.*)$/gm;
884
1020
  var doValidate = (doc) => {
885
1021
  const fsPath = getDocFile(doc);
886
1022
  const diagnostics = [];
887
- const { compiler, translator, cache: cache2 } = getCompilerInfo(doc);
1023
+ const { compiler, translator, cache: cache3 } = getCompilerInfo(doc);
888
1024
  try {
889
1025
  compiler.compileSync(doc.getText(), fsPath || "untitled.marko", {
890
- cache: cache2,
1026
+ cache: cache3,
891
1027
  translator,
892
1028
  code: false,
893
1029
  output: "source",
@@ -899,16 +1035,16 @@ var doValidate = (doc) => {
899
1035
  const [, fileName, rawLine, rawCol, msg] = match;
900
1036
  const line = (parseInt(rawLine, 10) || 1) - 1;
901
1037
  const col = (parseInt(rawCol, 10) || 1) - 1;
902
- diagnostics.push(Diagnostic.create(Range2.create(line, col, line, col), msg, DiagnosticSeverity.Error, void 0, fileName));
1038
+ diagnostics.push(Diagnostic.create(Range3.create(line, col, line, col), msg, DiagnosticSeverity.Error, void 0, fileName));
903
1039
  }
904
1040
  }
905
1041
  return diagnostics;
906
1042
  };
907
1043
 
908
1044
  // src/service/marko/definition/OpenTagName.ts
909
- import path3 from "path";
1045
+ import path4 from "path";
910
1046
  import { URI as URI4 } from "vscode-uri";
911
- import { Range as Range4, LocationLink } from "vscode-languageserver";
1047
+ import { Range as Range5, LocationLink } from "vscode-languageserver";
912
1048
 
913
1049
  // src/utils/regexp-builder.ts
914
1050
  function RegExpBuilder(strings, ...expressions) {
@@ -935,14 +1071,14 @@ function escape(val) {
935
1071
  }
936
1072
 
937
1073
  // src/utils/utils.ts
938
- import fs from "fs";
1074
+ import fs2 from "fs";
939
1075
  import { URI as URI3 } from "vscode-uri";
940
- import { Position, Range as Range3 } from "vscode-languageserver";
1076
+ import { Position, Range as Range4 } from "vscode-languageserver";
941
1077
  import { TextDocument } from "vscode-languageserver-textdocument";
942
- var START_OF_FILE = Range3.create(Position.create(0, 0), Position.create(0, 0));
1078
+ var START_OF_FILE = Range4.create(Position.create(0, 0), Position.create(0, 0));
943
1079
  function createTextDocument(filename) {
944
1080
  const uri = URI3.file(filename).toString();
945
- const content = fs.readFileSync(filename, "utf-8");
1081
+ const content = fs2.readFileSync(filename, "utf-8");
946
1082
  return TextDocument.create(uri, "plaintext", 0, content);
947
1083
  }
948
1084
 
@@ -967,14 +1103,14 @@ function OpenTagName2({
967
1103
  return;
968
1104
  }
969
1105
  const tagEntryFile = tagDef.template || tagDef.renderer || tagDef.filePath;
970
- if (!path3.isAbsolute(tagEntryFile)) {
1106
+ if (!path4.isAbsolute(tagEntryFile)) {
971
1107
  return;
972
1108
  }
973
1109
  if (/\/marko(?:-tag)?\.json$/.test(tagEntryFile)) {
974
1110
  const tagDefDoc = createTextDocument(tagEntryFile);
975
1111
  const match = RegExpBuilder`/"(?:<${tag.nameText}>|${tag.nameText})"\s*:\s*[^\r\n,]+/g`.exec(tagDefDoc.getText());
976
1112
  if (match && match.index) {
977
- range = Range4.create(tagDefDoc.positionAt(match.index), tagDefDoc.positionAt(match.index + match[0].length));
1113
+ range = Range5.create(tagDefDoc.positionAt(match.index), tagDefDoc.positionAt(match.index + match[0].length));
978
1114
  }
979
1115
  }
980
1116
  return [
@@ -984,7 +1120,7 @@ function OpenTagName2({
984
1120
 
985
1121
  // src/service/marko/definition/AttrName.ts
986
1122
  import { URI as URI5 } from "vscode-uri";
987
- import { Range as Range5, LocationLink as LocationLink2 } from "vscode-languageserver";
1123
+ import { Range as Range6, LocationLink as LocationLink2 } from "vscode-languageserver";
988
1124
  function AttrName2({
989
1125
  lookup,
990
1126
  parsed,
@@ -1008,7 +1144,7 @@ function AttrName2({
1008
1144
  const tagDefDoc = createTextDocument(attrEntryFile);
1009
1145
  const match = RegExpBuilder`/"@${attrName}"\s*:\s*[^\r\n,]+/g`.exec(tagDefDoc.getText());
1010
1146
  if (match && match.index) {
1011
- range = Range5.create(tagDefDoc.positionAt(match.index), tagDefDoc.positionAt(match.index + match[0].length));
1147
+ range = Range6.create(tagDefDoc.positionAt(match.index), tagDefDoc.positionAt(match.index + match[0].length));
1012
1148
  }
1013
1149
  }
1014
1150
  return [
@@ -1037,14 +1173,83 @@ var findDefinition = async (doc, params) => {
1037
1173
  })) || [];
1038
1174
  };
1039
1175
 
1040
- // src/service/marko/format.ts
1041
- import { Range as Range6, TextEdit as TextEdit4 } from "vscode-languageserver";
1176
+ // src/service/marko/document-links/extract.ts
1177
+ import { DocumentLink } from "vscode-languageserver";
1042
1178
  import { URI as URI6 } from "vscode-uri";
1179
+ var importTagReg = /(['"])<((?:[^\1\\>]+|\\.)*)>?\1/g;
1180
+ function extractDocumentLinks(doc, parsed, lookup) {
1181
+ if (URI6.parse(doc.uri).scheme === "untitled") {
1182
+ return [];
1183
+ }
1184
+ const links = [];
1185
+ const { program } = parsed;
1186
+ const code = doc.getText();
1187
+ const read = (range) => code.slice(range.start, range.end);
1188
+ const visit = (node) => {
1189
+ switch (node.type) {
1190
+ case 1 /* Tag */:
1191
+ if (node.attrs && node.nameText) {
1192
+ for (const attr of node.attrs) {
1193
+ if (isDocumentLinkAttr(doc, node, attr)) {
1194
+ links.push(DocumentLink.create({
1195
+ start: parsed.positionAt(attr.value.value.start),
1196
+ end: parsed.positionAt(attr.value.value.end)
1197
+ }, resolveUrl(read(attr.value.value).slice(1, -1), doc.uri)));
1198
+ }
1199
+ }
1200
+ }
1201
+ if (node.body) {
1202
+ for (const child of node.body) {
1203
+ visit(child);
1204
+ }
1205
+ }
1206
+ break;
1207
+ }
1208
+ };
1209
+ for (const item of program.static) {
1210
+ if (item.type === 20 /* Statement */ && code[item.start] === "i") {
1211
+ importTagReg.lastIndex = 0;
1212
+ const value = parsed.read(item);
1213
+ const match = importTagReg.exec(value);
1214
+ if (match) {
1215
+ const [{ length }, , tagName] = match;
1216
+ const tagDef = lookup.getTag(tagName);
1217
+ const fileForTag = tagDef && (tagDef.template || tagDef.renderer);
1218
+ if (fileForTag) {
1219
+ links.push(DocumentLink.create({
1220
+ start: parsed.positionAt(item.start + match.index),
1221
+ end: parsed.positionAt(item.start + match.index + length)
1222
+ }, fileForTag));
1223
+ }
1224
+ }
1225
+ }
1226
+ }
1227
+ for (const item of program.body) {
1228
+ visit(item);
1229
+ }
1230
+ return links;
1231
+ }
1232
+
1233
+ // src/service/marko/document-links/index.ts
1234
+ var cache = /* @__PURE__ */ new WeakMap();
1235
+ var findDocumentLinks = async (doc) => {
1236
+ const parsed = parse2(doc);
1237
+ let result = cache.get(parsed);
1238
+ if (!result) {
1239
+ result = extractDocumentLinks(doc, parsed, getCompilerInfo(doc).lookup);
1240
+ cache.set(parsed, result);
1241
+ }
1242
+ return result;
1243
+ };
1244
+
1245
+ // src/service/marko/format.ts
1246
+ import { Range as Range7, TextEdit as TextEdit5 } from "vscode-languageserver";
1247
+ import { URI as URI7 } from "vscode-uri";
1043
1248
  import * as prettier from "prettier";
1044
1249
  import * as markoPrettier from "prettier-plugin-marko";
1045
1250
  var format2 = async (doc, params, cancel) => {
1046
1251
  try {
1047
- const { fsPath, scheme } = URI6.parse(doc.uri);
1252
+ const { fsPath, scheme } = URI7.parse(doc.uri);
1048
1253
  const text = doc.getText();
1049
1254
  const options = {
1050
1255
  parser: "marko",
@@ -1059,7 +1264,7 @@ var format2 = async (doc, params, cancel) => {
1059
1264
  if (cancel.isCancellationRequested)
1060
1265
  return;
1061
1266
  return [
1062
- TextEdit4.replace(Range6.create(doc.positionAt(0), doc.positionAt(text.length)), prettier.format(text, options))
1267
+ TextEdit5.replace(Range7.create(doc.positionAt(0), doc.positionAt(text.length)), prettier.format(text, options))
1063
1268
  ];
1064
1269
  } catch (e) {
1065
1270
  displayError(e);
@@ -1071,13 +1276,14 @@ var marko_default = {
1071
1276
  doComplete,
1072
1277
  doValidate,
1073
1278
  findDefinition,
1279
+ findDocumentLinks,
1074
1280
  format: format2
1075
1281
  };
1076
1282
 
1077
1283
  // src/service/stylesheet/index.ts
1078
1284
  import {
1079
1285
  CompletionList as CompletionList2,
1080
- Range as Range8,
1286
+ Range as Range9,
1081
1287
  TextDocumentEdit
1082
1288
  } from "vscode-languageserver";
1083
1289
  import {
@@ -1223,7 +1429,7 @@ function extractStyleSheets(code, program, lookup) {
1223
1429
  for (const attr of node.attrs) {
1224
1430
  if (attr.type === 8 /* AttrNamed */ && ((_a = attr.value) == null ? void 0 : _a.type) === 11 /* AttrValue */ && /^['"]$/.test(code[attr.value.value.start])) {
1225
1431
  const name = read(attr.name);
1226
- if (name === "#style" || name === "style" && lookup && node.nameText && name === "style" && ((_b = lookup.getTag(node.nameText)) == null ? void 0 : _b.html)) {
1432
+ if (name === "#style" || name === "style" && node.nameText && name === "style" && ((_b = lookup.getTag(node.nameText)) == null ? void 0 : _b.html)) {
1227
1433
  getExtractor("css").write`:root{${{
1228
1434
  start: attr.value.value.start + 1,
1229
1435
  end: attr.value.value.end - 1
@@ -1245,13 +1451,17 @@ function extractStyleSheets(code, program, lookup) {
1245
1451
  }
1246
1452
 
1247
1453
  // src/service/stylesheet/index.ts
1248
- var cache = /* @__PURE__ */ new WeakMap();
1454
+ var cache2 = /* @__PURE__ */ new WeakMap();
1249
1455
  var services = {
1250
1456
  css: getCSSLanguageService,
1251
1457
  less: getLESSLanguageService,
1252
1458
  scss: getSCSSLanguageService
1253
1459
  };
1460
+ var clientCapabilities;
1254
1461
  var StyleSheetService = {
1462
+ initialize(params) {
1463
+ clientCapabilities = params.capabilities;
1464
+ },
1255
1465
  async doComplete(doc, params) {
1256
1466
  const infoByExt = getStyleSheetInfo(doc);
1257
1467
  const sourceOffset = doc.offsetAt(params.position);
@@ -1261,28 +1471,31 @@ var StyleSheetService = {
1261
1471
  if (generatedOffset === void 0)
1262
1472
  continue;
1263
1473
  const { service: service2, virtualDoc } = info;
1264
- const result = service2.doComplete(virtualDoc, virtualDoc.positionAt(generatedOffset), info.parsed);
1265
- for (const item of result.items) {
1266
- if (item.additionalTextEdits) {
1267
- for (const textEdit2 of item.additionalTextEdits) {
1268
- updateTextEdit(doc, info, textEdit2);
1474
+ const result = await service2.doComplete2(virtualDoc, virtualDoc.positionAt(generatedOffset), info.parsed, { resolveReference: resolveUrl });
1475
+ if (result.itemDefaults) {
1476
+ const { editRange } = result.itemDefaults;
1477
+ if (editRange) {
1478
+ if ("start" in editRange) {
1479
+ result.itemDefaults.editRange = getSourceRange(doc, info, editRange);
1480
+ } else {
1481
+ editRange.insert = getSourceRange(doc, info, editRange.insert);
1482
+ editRange.replace = getSourceRange(doc, info, editRange.replace);
1269
1483
  }
1270
1484
  }
1271
- const { textEdit } = item;
1272
- if (textEdit) {
1273
- if (textEdit.range) {
1274
- updateTextEdit(doc, info, textEdit);
1275
- }
1276
- if (textEdit.insert) {
1277
- updateInsertReplaceEdit(doc, info, textEdit);
1278
- }
1485
+ }
1486
+ for (const item of result.items) {
1487
+ if (item.textEdit) {
1488
+ item.textEdit = getSourceInsertReplaceEdit(doc, info, item.textEdit);
1489
+ }
1490
+ if (item.additionalTextEdits) {
1491
+ item.additionalTextEdits = getSourceEdits(doc, info, item.additionalTextEdits);
1279
1492
  }
1280
1493
  }
1281
1494
  return result;
1282
1495
  }
1283
1496
  return CompletionList2.create([], true);
1284
1497
  },
1285
- async findDefinition(doc, params) {
1498
+ findDefinition(doc, params) {
1286
1499
  const infoByExt = getStyleSheetInfo(doc);
1287
1500
  const sourceOffset = doc.offsetAt(params.position);
1288
1501
  for (const ext in infoByExt) {
@@ -1292,29 +1505,101 @@ var StyleSheetService = {
1292
1505
  continue;
1293
1506
  const { service: service2, virtualDoc } = info;
1294
1507
  const result = service2.findDefinition(virtualDoc, virtualDoc.positionAt(generatedOffset), info.parsed);
1295
- if (result && updateRange(doc, info, result.range)) {
1296
- return result;
1508
+ if (result) {
1509
+ const range = getSourceRange(doc, info, result.range);
1510
+ if (range) {
1511
+ return {
1512
+ range,
1513
+ uri: doc.uri
1514
+ };
1515
+ }
1297
1516
  }
1298
1517
  break;
1299
1518
  }
1300
1519
  },
1301
- async findDocumentColors(doc) {
1520
+ findReferences(doc, params) {
1521
+ const infoByExt = getStyleSheetInfo(doc);
1522
+ const sourceOffset = doc.offsetAt(params.position);
1523
+ for (const ext in infoByExt) {
1524
+ const info = infoByExt[ext];
1525
+ const generatedOffset = info.generatedOffsetAt(sourceOffset);
1526
+ if (generatedOffset === void 0)
1527
+ continue;
1528
+ const { service: service2, virtualDoc } = info;
1529
+ const result = [];
1530
+ for (const location of service2.findReferences(virtualDoc, virtualDoc.positionAt(generatedOffset), info.parsed)) {
1531
+ const range = getSourceRange(doc, info, location.range);
1532
+ if (range) {
1533
+ result.push({
1534
+ range,
1535
+ uri: location.uri
1536
+ });
1537
+ }
1538
+ }
1539
+ return result.length ? result : void 0;
1540
+ }
1541
+ },
1542
+ async findDocumentLinks(doc) {
1302
1543
  const infoByExt = getStyleSheetInfo(doc);
1303
1544
  const result = [];
1304
1545
  for (const ext in infoByExt) {
1305
1546
  const info = infoByExt[ext];
1306
1547
  const { service: service2, virtualDoc } = info;
1307
- for (const colorInfo of service2.findDocumentColors(virtualDoc, info.parsed)) {
1308
- if (updateRange(doc, info, colorInfo.range)) {
1309
- result.push(colorInfo);
1548
+ for (const link of await service2.findDocumentLinks2(virtualDoc, info.parsed, { resolveReference: resolveUrl })) {
1549
+ const range = getSourceRange(doc, info, link.range);
1550
+ if (range) {
1551
+ result.push({
1552
+ range,
1553
+ target: link.target,
1554
+ tooltip: link.tooltip,
1555
+ data: link.data
1556
+ });
1310
1557
  }
1311
1558
  }
1312
1559
  }
1313
- if (result.length) {
1314
- return result;
1560
+ return result.length ? result : void 0;
1561
+ },
1562
+ findDocumentHighlights(doc, params) {
1563
+ const infoByExt = getStyleSheetInfo(doc);
1564
+ const sourceOffset = doc.offsetAt(params.position);
1565
+ for (const ext in infoByExt) {
1566
+ const info = infoByExt[ext];
1567
+ const generatedOffset = info.generatedOffsetAt(sourceOffset);
1568
+ if (generatedOffset === void 0)
1569
+ continue;
1570
+ const { service: service2, virtualDoc } = info;
1571
+ const result = [];
1572
+ for (const highlight of service2.findDocumentHighlights(virtualDoc, virtualDoc.positionAt(generatedOffset), info.parsed)) {
1573
+ const range = getSourceRange(doc, info, highlight.range);
1574
+ if (range) {
1575
+ result.push({
1576
+ range,
1577
+ kind: highlight.kind
1578
+ });
1579
+ }
1580
+ }
1581
+ return result.length ? result : void 0;
1582
+ }
1583
+ },
1584
+ findDocumentColors(doc) {
1585
+ const infoByExt = getStyleSheetInfo(doc);
1586
+ const result = [];
1587
+ for (const ext in infoByExt) {
1588
+ const info = infoByExt[ext];
1589
+ const { service: service2, virtualDoc } = info;
1590
+ for (const colorInfo of service2.findDocumentColors(virtualDoc, info.parsed)) {
1591
+ const range = getSourceRange(doc, info, colorInfo.range);
1592
+ if (range) {
1593
+ result.push({
1594
+ range,
1595
+ color: colorInfo.color
1596
+ });
1597
+ }
1598
+ }
1315
1599
  }
1600
+ return result.length ? result : void 0;
1316
1601
  },
1317
- async getColorPresentations(doc, params) {
1602
+ getColorPresentations(doc, params) {
1318
1603
  const infoByExt = getStyleSheetInfo(doc);
1319
1604
  const sourceOffset = doc.offsetAt(params.range.start);
1320
1605
  for (const ext in infoByExt) {
@@ -1326,21 +1611,22 @@ var StyleSheetService = {
1326
1611
  if (generatedOffsetEnd === void 0)
1327
1612
  continue;
1328
1613
  const { service: service2, virtualDoc } = info;
1329
- const result = service2.getColorPresentations(virtualDoc, info.parsed, params.color, Range8.create(virtualDoc.positionAt(generatedOffsetStart), virtualDoc.positionAt(generatedOffsetEnd)));
1330
- for (const colorPresentation of result) {
1331
- if (colorPresentation.textEdit) {
1332
- updateTextEdit(doc, info, colorPresentation.textEdit);
1333
- }
1334
- if (colorPresentation.additionalTextEdits) {
1335
- for (const textEdit of colorPresentation.additionalTextEdits) {
1336
- updateTextEdit(doc, info, textEdit);
1337
- }
1614
+ const result = [];
1615
+ for (const colorPresentation of service2.getColorPresentations(virtualDoc, info.parsed, params.color, Range9.create(virtualDoc.positionAt(generatedOffsetStart), virtualDoc.positionAt(generatedOffsetEnd)))) {
1616
+ const textEdit = colorPresentation.textEdit && getSourceEdit(doc, info, colorPresentation.textEdit);
1617
+ const additionalTextEdits = colorPresentation.additionalTextEdits && getSourceEdits(doc, info, colorPresentation.additionalTextEdits);
1618
+ if (textEdit || additionalTextEdits) {
1619
+ result.push({
1620
+ label: colorPresentation.label,
1621
+ textEdit,
1622
+ additionalTextEdits
1623
+ });
1338
1624
  }
1339
1625
  }
1340
- return result;
1626
+ return result.length ? result : void 0;
1341
1627
  }
1342
1628
  },
1343
- async doHover(doc, params) {
1629
+ doHover(doc, params) {
1344
1630
  const infoByExt = getStyleSheetInfo(doc);
1345
1631
  const sourceOffset = doc.offsetAt(params.position);
1346
1632
  for (const ext in infoByExt) {
@@ -1350,8 +1636,18 @@ var StyleSheetService = {
1350
1636
  continue;
1351
1637
  const { service: service2, virtualDoc } = info;
1352
1638
  const result = service2.doHover(virtualDoc, virtualDoc.positionAt(generatedOffset), info.parsed);
1353
- if (result && (!result.range || updateRange(doc, info, result.range))) {
1354
- return result;
1639
+ if (result) {
1640
+ if (result.range) {
1641
+ const range = getSourceRange(doc, info, result.range);
1642
+ if (range) {
1643
+ return {
1644
+ range,
1645
+ contents: result.contents
1646
+ };
1647
+ }
1648
+ } else {
1649
+ return result;
1650
+ }
1355
1651
  }
1356
1652
  }
1357
1653
  },
@@ -1368,9 +1664,7 @@ var StyleSheetService = {
1368
1664
  if (result.changes) {
1369
1665
  for (const uri in result.changes) {
1370
1666
  if (uri === doc.uri) {
1371
- for (const textEdit of result.changes[uri]) {
1372
- updateTextEdit(doc, info, textEdit);
1373
- }
1667
+ result.changes[uri] = getSourceEdits(doc, info, result.changes[uri]) || [];
1374
1668
  }
1375
1669
  }
1376
1670
  }
@@ -1378,9 +1672,7 @@ var StyleSheetService = {
1378
1672
  for (const change of result.documentChanges) {
1379
1673
  if (TextDocumentEdit.is(change)) {
1380
1674
  if (change.textDocument.uri === doc.uri) {
1381
- for (const textEdit of change.edits) {
1382
- updateTextEdit(doc, info, textEdit);
1383
- }
1675
+ change.edits = getSourceEdits(doc, info, change.edits) || [];
1384
1676
  }
1385
1677
  }
1386
1678
  }
@@ -1388,7 +1680,7 @@ var StyleSheetService = {
1388
1680
  return result;
1389
1681
  }
1390
1682
  },
1391
- async doCodeActions(doc, params) {
1683
+ doCodeActions(doc, params) {
1392
1684
  var _a;
1393
1685
  const infoByExt = getStyleSheetInfo(doc);
1394
1686
  const sourceOffset = doc.offsetAt(params.range.start);
@@ -1401,65 +1693,100 @@ var StyleSheetService = {
1401
1693
  if (generatedOffsetEnd === void 0)
1402
1694
  continue;
1403
1695
  const { service: service2, virtualDoc } = info;
1404
- const result = service2.doCodeActions(virtualDoc, Range8.create(virtualDoc.positionAt(generatedOffsetStart), virtualDoc.positionAt(generatedOffsetEnd)), params.context, info.parsed);
1405
- if (result) {
1406
- for (const command of result) {
1407
- const edits = (_a = command.arguments) == null ? void 0 : _a[2];
1408
- if (edits) {
1409
- for (const textEdit of edits) {
1410
- updateTextEdit(doc, info, textEdit);
1411
- }
1412
- }
1696
+ const result = service2.doCodeActions(virtualDoc, Range9.create(virtualDoc.positionAt(generatedOffsetStart), virtualDoc.positionAt(generatedOffsetEnd)), params.context, info.parsed);
1697
+ for (const command of result) {
1698
+ const edits = (_a = command.arguments) == null ? void 0 : _a[2];
1699
+ if (edits && Array.isArray(edits) && isTextEdit(edits[0])) {
1700
+ command.arguments[2] = getSourceEdits(doc, info, edits);
1413
1701
  }
1414
- return result;
1415
1702
  }
1703
+ return result;
1416
1704
  }
1417
1705
  },
1418
- async doValidate(doc) {
1706
+ doValidate(doc) {
1419
1707
  const infoByExt = getStyleSheetInfo(doc);
1420
1708
  const result = [];
1421
1709
  for (const ext in infoByExt) {
1422
1710
  const info = infoByExt[ext];
1423
1711
  for (const diag of info.service.doValidation(info.virtualDoc, info.parsed)) {
1424
- if (updateRange(doc, info, diag.range)) {
1712
+ const range = getSourceRange(doc, info, diag.range);
1713
+ if (range) {
1714
+ diag.range = range;
1425
1715
  result.push(diag);
1426
1716
  }
1427
1717
  }
1428
1718
  }
1429
- return result;
1719
+ return result.length ? result : void 0;
1430
1720
  }
1431
1721
  };
1432
- function updateTextEdit(doc, info, textEdit) {
1433
- if (!updateRange(doc, info, textEdit.range)) {
1434
- textEdit.newText = "";
1435
- textEdit.range = START_OF_FILE;
1722
+ function getSourceEdits(doc, info, edits) {
1723
+ const result = [];
1724
+ for (const edit of edits) {
1725
+ const sourceEdit = getSourceEdit(doc, info, edit);
1726
+ if (sourceEdit) {
1727
+ result.push(sourceEdit);
1728
+ }
1436
1729
  }
1730
+ return result.length ? result : void 0;
1437
1731
  }
1438
- function updateInsertReplaceEdit(doc, info, insertReplaceEdit) {
1439
- if (!updateRange(doc, info, insertReplaceEdit.insert)) {
1440
- insertReplaceEdit.newText = "";
1441
- insertReplaceEdit.insert = START_OF_FILE;
1732
+ function getSourceEdit(doc, info, textEdit) {
1733
+ const range = getSourceRange(doc, info, textEdit.range);
1734
+ if (range) {
1735
+ return {
1736
+ newText: textEdit.newText,
1737
+ range
1738
+ };
1442
1739
  }
1443
1740
  }
1444
- function updateRange(doc, info, range) {
1741
+ function getSourceInsertReplaceEdit(doc, info, textEdit) {
1742
+ if (isTextEdit(textEdit)) {
1743
+ return getSourceEdit(doc, info, textEdit);
1744
+ } else if (textEdit.replace) {
1745
+ const range = getSourceRange(doc, info, textEdit.replace);
1746
+ if (range) {
1747
+ return {
1748
+ newText: textEdit.newText,
1749
+ replace: range
1750
+ };
1751
+ }
1752
+ } else {
1753
+ const range = getSourceRange(doc, info, textEdit.insert);
1754
+ if (range) {
1755
+ return {
1756
+ newText: textEdit.newText,
1757
+ insert: range
1758
+ };
1759
+ }
1760
+ }
1761
+ }
1762
+ function getSourceRange(doc, info, range) {
1445
1763
  const start = info.sourceOffsetAt(info.virtualDoc.offsetAt(range.start));
1446
- const end = info.sourceOffsetAt(info.virtualDoc.offsetAt(range.end));
1447
- if (start !== void 0 || end !== void 0) {
1448
- range.start = doc.positionAt(start ?? end);
1449
- range.end = doc.positionAt(end ?? start);
1450
- return true;
1764
+ if (start === void 0)
1765
+ return;
1766
+ let end = start;
1767
+ if (range.start.line !== range.end.line || range.start.character !== range.end.character) {
1768
+ end = info.sourceOffsetAt(info.virtualDoc.offsetAt(range.end));
1769
+ if (end === void 0)
1770
+ return;
1451
1771
  }
1452
- return false;
1772
+ const pos = doc.positionAt(start);
1773
+ return {
1774
+ start: pos,
1775
+ end: start === end ? pos : doc.positionAt(end)
1776
+ };
1453
1777
  }
1454
1778
  function getStyleSheetInfo(doc) {
1455
1779
  var _a;
1456
1780
  const parsed = parse2(doc);
1457
- let cached = cache.get(parsed);
1781
+ let cached = cache2.get(parsed);
1458
1782
  if (!cached) {
1459
1783
  const results = extractStyleSheets(doc.getText(), parsed.program, getCompilerInfo(doc).lookup);
1460
1784
  cached = {};
1461
1785
  for (const ext in results) {
1462
- const service2 = (_a = services[ext]) == null ? void 0 : _a.call(services);
1786
+ const service2 = (_a = services[ext]) == null ? void 0 : _a.call(services, {
1787
+ fileSystemProvider: file_system_default,
1788
+ clientCapabilities
1789
+ });
1463
1790
  if (!service2)
1464
1791
  continue;
1465
1792
  const { generated, sourceOffsetAt, generatedOffsetAt } = results[ext];
@@ -1472,14 +1799,23 @@ function getStyleSheetInfo(doc) {
1472
1799
  parsed: service2.parseStylesheet(virtualDoc)
1473
1800
  };
1474
1801
  }
1475
- cache.set(parsed, cached);
1802
+ cache2.set(parsed, cached);
1476
1803
  }
1477
1804
  return cached;
1478
1805
  }
1806
+ function isTextEdit(edit) {
1807
+ return edit.range !== void 0;
1808
+ }
1479
1809
 
1480
1810
  // src/service/index.ts
1481
1811
  var plugins = [marko_default, StyleSheetService];
1482
1812
  var service = {
1813
+ async initialize(params) {
1814
+ await Promise.all(plugins.map((plugin) => {
1815
+ var _a;
1816
+ return (_a = plugin.initialize) == null ? void 0 : _a.call(plugin, params);
1817
+ }));
1818
+ },
1483
1819
  async doComplete(doc, params, cancel) {
1484
1820
  const result = CompletionList3.create([], false);
1485
1821
  try {
@@ -1532,6 +1868,78 @@ var service = {
1532
1868
  }
1533
1869
  return result;
1534
1870
  },
1871
+ async findReferences(doc, params, cancel) {
1872
+ let result;
1873
+ try {
1874
+ const requests = plugins.map((plugin) => {
1875
+ var _a;
1876
+ return (_a = plugin.findReferences) == null ? void 0 : _a.call(plugin, doc, params, cancel);
1877
+ });
1878
+ for (const pending of requests) {
1879
+ const cur = await pending;
1880
+ if (cancel.isCancellationRequested)
1881
+ return;
1882
+ if (cur) {
1883
+ if (result) {
1884
+ result.push(...cur);
1885
+ } else {
1886
+ result = cur;
1887
+ }
1888
+ }
1889
+ }
1890
+ } catch (err) {
1891
+ displayError(err);
1892
+ }
1893
+ return result;
1894
+ },
1895
+ async findDocumentLinks(doc, params, cancel) {
1896
+ let result;
1897
+ try {
1898
+ const requests = plugins.map((plugin) => {
1899
+ var _a;
1900
+ return (_a = plugin.findDocumentLinks) == null ? void 0 : _a.call(plugin, doc, params, cancel);
1901
+ });
1902
+ for (const pending of requests) {
1903
+ const cur = await pending;
1904
+ if (cancel.isCancellationRequested)
1905
+ return;
1906
+ if (cur) {
1907
+ if (result) {
1908
+ result.push(...cur);
1909
+ } else {
1910
+ result = cur;
1911
+ }
1912
+ }
1913
+ }
1914
+ } catch (err) {
1915
+ displayError(err);
1916
+ }
1917
+ return result;
1918
+ },
1919
+ async findDocumentHighlights(doc, params, cancel) {
1920
+ let result;
1921
+ try {
1922
+ const requests = plugins.map((plugin) => {
1923
+ var _a;
1924
+ return (_a = plugin.findDocumentHighlights) == null ? void 0 : _a.call(plugin, doc, params, cancel);
1925
+ });
1926
+ for (const pending of requests) {
1927
+ const cur = await pending;
1928
+ if (cancel.isCancellationRequested)
1929
+ return;
1930
+ if (cur) {
1931
+ if (result) {
1932
+ result.push(...cur);
1933
+ } else {
1934
+ result = cur;
1935
+ }
1936
+ }
1937
+ }
1938
+ } catch (err) {
1939
+ displayError(err);
1940
+ }
1941
+ return result;
1942
+ },
1535
1943
  async findDocumentColors(doc, params, cancel) {
1536
1944
  let result;
1537
1945
  try {
@@ -1705,8 +2113,9 @@ console.error = (...args) => {
1705
2113
  };
1706
2114
  process.on("uncaughtException", console.error);
1707
2115
  process.on("unhandledRejection", console.error);
1708
- connection2.onInitialize(() => {
2116
+ connection2.onInitialize(async (params) => {
1709
2117
  setup(connection2);
2118
+ await service.initialize(params);
1710
2119
  return {
1711
2120
  capabilities: {
1712
2121
  textDocumentSync: TextDocumentSyncKind.Incremental,
@@ -1715,7 +2124,10 @@ connection2.onInitialize(() => {
1715
2124
  hoverProvider: true,
1716
2125
  renameProvider: true,
1717
2126
  codeActionProvider: true,
2127
+ referencesProvider: true,
2128
+ documentLinkProvider: { resolveProvider: false },
1718
2129
  colorProvider: true,
2130
+ documentHighlightProvider: true,
1719
2131
  completionProvider: {
1720
2132
  triggerCharacters: [
1721
2133
  ".",
@@ -1755,6 +2167,15 @@ connection2.onCompletion(async (params, cancel) => {
1755
2167
  connection2.onDefinition(async (params, cancel) => {
1756
2168
  return await service.findDefinition(documents.get(params.textDocument.uri), params, cancel) || null;
1757
2169
  });
2170
+ connection2.onReferences(async (params, cancel) => {
2171
+ return await service.findReferences(documents.get(params.textDocument.uri), params, cancel) || null;
2172
+ });
2173
+ connection2.onDocumentLinks(async (params, cancel) => {
2174
+ return await service.findDocumentLinks(documents.get(params.textDocument.uri), params, cancel) || null;
2175
+ });
2176
+ connection2.onDocumentHighlight(async (params, cancel) => {
2177
+ return await service.findDocumentHighlights(documents.get(params.textDocument.uri), params, cancel) || null;
2178
+ });
1758
2179
  connection2.onDocumentColor(async (params, cancel) => {
1759
2180
  return await service.findDocumentColors(documents.get(params.textDocument.uri), params, cancel) || null;
1760
2181
  });