@marko/language-server 0.12.9 → 0.12.10

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,143 @@ function AttrName({
856
856
  return completions;
857
857
  }
858
858
 
859
+ // src/service/marko/complete/AttrValue.ts
860
+ import path4 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 path3 from "path";
894
+ import fs from "fs/promises";
895
+ import { FileType } from "vscode-css-languageservice";
896
+ var file_system_default = {
897
+ stat,
898
+ readDirectory
899
+ };
900
+ async function stat(fileName) {
901
+ const stat2 = await fs.stat(fileName).catch(() => null);
902
+ let type = FileType.Unknown;
903
+ let ctime = 0;
904
+ let mtime = 0;
905
+ let size = 0;
906
+ if (stat2) {
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
+ }
915
+ return {
916
+ type,
917
+ ctime,
918
+ mtime,
919
+ size
920
+ };
921
+ }
922
+ async function readDirectory(dir) {
923
+ return (await Promise.all((await fs.readdir(dir).catch(() => [])).map(async (entry) => [entry, (await stat(path3.join(dir, entry))).type]))).filter(([, type]) => type !== FileType.Unknown);
924
+ }
925
+
926
+ // src/utils/resolve-url.ts
927
+ function resolveUrl(to, base) {
928
+ try {
929
+ const baseUrl = new URL(base, "file://");
930
+ const resolved = new URL(to, baseUrl);
931
+ const { origin, protocol } = baseUrl;
932
+ if (resolved.origin === origin && resolved.protocol === protocol) {
933
+ return resolved.pathname + resolved.search + resolved.hash;
934
+ }
935
+ return resolved.toString();
936
+ } catch {
937
+ return void 0;
938
+ }
939
+ }
940
+
941
+ // src/service/marko/complete/AttrValue.ts
942
+ async function AttrValue({
943
+ document,
944
+ offset,
945
+ node,
946
+ parsed,
947
+ code
948
+ }) {
949
+ const attr = node.parent;
950
+ if (isDocumentLinkAttr(document, attr.parent, attr)) {
951
+ const start = node.value.start + 1;
952
+ if (code[start] !== ".")
953
+ return;
954
+ const end = node.value.end - 1;
955
+ const relativeOffset = offset - start;
956
+ const rawValue = parsed.read({
957
+ start,
958
+ end
959
+ });
960
+ let segmentStart = rawValue.lastIndexOf("/", relativeOffset);
961
+ if (segmentStart === -1)
962
+ segmentStart = relativeOffset;
963
+ const resolveRequest = rawValue.slice(0, segmentStart) || ".";
964
+ const dir = resolveUrl(resolveRequest, document.uri);
965
+ if ((dir == null ? void 0 : dir[0]) === "/") {
966
+ const result = [];
967
+ const curDir = resolveRequest === "." ? dir : resolveUrl(".", document.uri);
968
+ const curFile = curDir === dir ? path4.basename(document.uri) : void 0;
969
+ const replaceRange = Range2.create(document.positionAt(start + segmentStart + 1), document.positionAt(start + rawValue.length));
970
+ for (const [entry, type] of await file_system_default.readDirectory(dir)) {
971
+ if (entry[0] !== "." && entry !== curFile) {
972
+ const isDir = type === FileType.Directory;
973
+ const label = isDir ? `${entry}/` : entry;
974
+ result.push({
975
+ label,
976
+ kind: isDir ? CompletionItemKind4.Folder : CompletionItemKind4.File,
977
+ textEdit: TextEdit4.replace(replaceRange, label),
978
+ command: isDir ? {
979
+ title: "Suggest",
980
+ command: "editor.action.triggerSuggest"
981
+ } : void 0
982
+ });
983
+ }
984
+ }
985
+ return result;
986
+ }
987
+ }
988
+ }
989
+
859
990
  // src/service/marko/complete/index.ts
860
991
  var handlers = {
861
992
  Tag,
862
993
  OpenTagName,
863
- AttrName
994
+ AttrName,
995
+ AttrValue
864
996
  };
865
997
  var doComplete = async (doc, params) => {
866
998
  var _a;
@@ -879,15 +1011,15 @@ var doComplete = async (doc, params) => {
879
1011
  };
880
1012
 
881
1013
  // src/service/marko/validate.ts
882
- import { Diagnostic, DiagnosticSeverity, Range as Range2 } from "vscode-languageserver";
1014
+ import { Diagnostic, DiagnosticSeverity, Range as Range3 } from "vscode-languageserver";
883
1015
  var markoErrorRegExp = /^(.+?)(?:\((\d+)(?:\s*,\s*(\d+))?\))?: (.*)$/gm;
884
1016
  var doValidate = (doc) => {
885
1017
  const fsPath = getDocFile(doc);
886
1018
  const diagnostics = [];
887
- const { compiler, translator, cache: cache2 } = getCompilerInfo(doc);
1019
+ const { compiler, translator, cache: cache3 } = getCompilerInfo(doc);
888
1020
  try {
889
1021
  compiler.compileSync(doc.getText(), fsPath || "untitled.marko", {
890
- cache: cache2,
1022
+ cache: cache3,
891
1023
  translator,
892
1024
  code: false,
893
1025
  output: "source",
@@ -899,16 +1031,16 @@ var doValidate = (doc) => {
899
1031
  const [, fileName, rawLine, rawCol, msg] = match;
900
1032
  const line = (parseInt(rawLine, 10) || 1) - 1;
901
1033
  const col = (parseInt(rawCol, 10) || 1) - 1;
902
- diagnostics.push(Diagnostic.create(Range2.create(line, col, line, col), msg, DiagnosticSeverity.Error, void 0, fileName));
1034
+ diagnostics.push(Diagnostic.create(Range3.create(line, col, line, col), msg, DiagnosticSeverity.Error, void 0, fileName));
903
1035
  }
904
1036
  }
905
1037
  return diagnostics;
906
1038
  };
907
1039
 
908
1040
  // src/service/marko/definition/OpenTagName.ts
909
- import path3 from "path";
1041
+ import path5 from "path";
910
1042
  import { URI as URI4 } from "vscode-uri";
911
- import { Range as Range4, LocationLink } from "vscode-languageserver";
1043
+ import { Range as Range5, LocationLink } from "vscode-languageserver";
912
1044
 
913
1045
  // src/utils/regexp-builder.ts
914
1046
  function RegExpBuilder(strings, ...expressions) {
@@ -935,14 +1067,14 @@ function escape(val) {
935
1067
  }
936
1068
 
937
1069
  // src/utils/utils.ts
938
- import fs from "fs";
1070
+ import fs2 from "fs";
939
1071
  import { URI as URI3 } from "vscode-uri";
940
- import { Position, Range as Range3 } from "vscode-languageserver";
1072
+ import { Position, Range as Range4 } from "vscode-languageserver";
941
1073
  import { TextDocument } from "vscode-languageserver-textdocument";
942
- var START_OF_FILE = Range3.create(Position.create(0, 0), Position.create(0, 0));
1074
+ var START_OF_FILE = Range4.create(Position.create(0, 0), Position.create(0, 0));
943
1075
  function createTextDocument(filename) {
944
1076
  const uri = URI3.file(filename).toString();
945
- const content = fs.readFileSync(filename, "utf-8");
1077
+ const content = fs2.readFileSync(filename, "utf-8");
946
1078
  return TextDocument.create(uri, "plaintext", 0, content);
947
1079
  }
948
1080
 
@@ -967,14 +1099,14 @@ function OpenTagName2({
967
1099
  return;
968
1100
  }
969
1101
  const tagEntryFile = tagDef.template || tagDef.renderer || tagDef.filePath;
970
- if (!path3.isAbsolute(tagEntryFile)) {
1102
+ if (!path5.isAbsolute(tagEntryFile)) {
971
1103
  return;
972
1104
  }
973
1105
  if (/\/marko(?:-tag)?\.json$/.test(tagEntryFile)) {
974
1106
  const tagDefDoc = createTextDocument(tagEntryFile);
975
1107
  const match = RegExpBuilder`/"(?:<${tag.nameText}>|${tag.nameText})"\s*:\s*[^\r\n,]+/g`.exec(tagDefDoc.getText());
976
1108
  if (match && match.index) {
977
- range = Range4.create(tagDefDoc.positionAt(match.index), tagDefDoc.positionAt(match.index + match[0].length));
1109
+ range = Range5.create(tagDefDoc.positionAt(match.index), tagDefDoc.positionAt(match.index + match[0].length));
978
1110
  }
979
1111
  }
980
1112
  return [
@@ -984,7 +1116,7 @@ function OpenTagName2({
984
1116
 
985
1117
  // src/service/marko/definition/AttrName.ts
986
1118
  import { URI as URI5 } from "vscode-uri";
987
- import { Range as Range5, LocationLink as LocationLink2 } from "vscode-languageserver";
1119
+ import { Range as Range6, LocationLink as LocationLink2 } from "vscode-languageserver";
988
1120
  function AttrName2({
989
1121
  lookup,
990
1122
  parsed,
@@ -1008,7 +1140,7 @@ function AttrName2({
1008
1140
  const tagDefDoc = createTextDocument(attrEntryFile);
1009
1141
  const match = RegExpBuilder`/"@${attrName}"\s*:\s*[^\r\n,]+/g`.exec(tagDefDoc.getText());
1010
1142
  if (match && match.index) {
1011
- range = Range5.create(tagDefDoc.positionAt(match.index), tagDefDoc.positionAt(match.index + match[0].length));
1143
+ range = Range6.create(tagDefDoc.positionAt(match.index), tagDefDoc.positionAt(match.index + match[0].length));
1012
1144
  }
1013
1145
  }
1014
1146
  return [
@@ -1037,14 +1169,83 @@ var findDefinition = async (doc, params) => {
1037
1169
  })) || [];
1038
1170
  };
1039
1171
 
1040
- // src/service/marko/format.ts
1041
- import { Range as Range6, TextEdit as TextEdit4 } from "vscode-languageserver";
1172
+ // src/service/marko/document-links/extract.ts
1173
+ import { DocumentLink } from "vscode-languageserver";
1042
1174
  import { URI as URI6 } from "vscode-uri";
1175
+ var importTagReg = /(['"])<((?:[^\1\\>]+|\\.)*)>?\1/g;
1176
+ function extractDocumentLinks(doc, parsed, lookup) {
1177
+ if (URI6.parse(doc.uri).scheme === "untitled") {
1178
+ return [];
1179
+ }
1180
+ const links = [];
1181
+ const { program } = parsed;
1182
+ const code = doc.getText();
1183
+ const read = (range) => code.slice(range.start, range.end);
1184
+ const visit = (node) => {
1185
+ switch (node.type) {
1186
+ case 1 /* Tag */:
1187
+ if (node.attrs && node.nameText) {
1188
+ for (const attr of node.attrs) {
1189
+ if (isDocumentLinkAttr(doc, node, attr)) {
1190
+ links.push(DocumentLink.create({
1191
+ start: parsed.positionAt(attr.value.value.start),
1192
+ end: parsed.positionAt(attr.value.value.end)
1193
+ }, resolveUrl(read(attr.value.value).slice(1, -1), doc.uri)));
1194
+ }
1195
+ }
1196
+ }
1197
+ if (node.body) {
1198
+ for (const child of node.body) {
1199
+ visit(child);
1200
+ }
1201
+ }
1202
+ break;
1203
+ }
1204
+ };
1205
+ for (const item of program.static) {
1206
+ if (item.type === 20 /* Statement */ && code[item.start] === "i") {
1207
+ importTagReg.lastIndex = 0;
1208
+ const value = parsed.read(item);
1209
+ const match = importTagReg.exec(value);
1210
+ if (match) {
1211
+ const [{ length }, , tagName] = match;
1212
+ const tagDef = lookup.getTag(tagName);
1213
+ const fileForTag = tagDef && (tagDef.template || tagDef.renderer);
1214
+ if (fileForTag) {
1215
+ links.push(DocumentLink.create({
1216
+ start: parsed.positionAt(item.start + match.index),
1217
+ end: parsed.positionAt(item.start + match.index + length)
1218
+ }, fileForTag));
1219
+ }
1220
+ }
1221
+ }
1222
+ }
1223
+ for (const item of program.body) {
1224
+ visit(item);
1225
+ }
1226
+ return links;
1227
+ }
1228
+
1229
+ // src/service/marko/document-links/index.ts
1230
+ var cache = /* @__PURE__ */ new WeakMap();
1231
+ var findDocumentLinks = async (doc) => {
1232
+ const parsed = parse2(doc);
1233
+ let result = cache.get(parsed);
1234
+ if (!result) {
1235
+ result = extractDocumentLinks(doc, parsed, getCompilerInfo(doc).lookup);
1236
+ cache.set(parsed, result);
1237
+ }
1238
+ return result;
1239
+ };
1240
+
1241
+ // src/service/marko/format.ts
1242
+ import { Range as Range7, TextEdit as TextEdit5 } from "vscode-languageserver";
1243
+ import { URI as URI7 } from "vscode-uri";
1043
1244
  import * as prettier from "prettier";
1044
1245
  import * as markoPrettier from "prettier-plugin-marko";
1045
1246
  var format2 = async (doc, params, cancel) => {
1046
1247
  try {
1047
- const { fsPath, scheme } = URI6.parse(doc.uri);
1248
+ const { fsPath, scheme } = URI7.parse(doc.uri);
1048
1249
  const text = doc.getText();
1049
1250
  const options = {
1050
1251
  parser: "marko",
@@ -1059,7 +1260,7 @@ var format2 = async (doc, params, cancel) => {
1059
1260
  if (cancel.isCancellationRequested)
1060
1261
  return;
1061
1262
  return [
1062
- TextEdit4.replace(Range6.create(doc.positionAt(0), doc.positionAt(text.length)), prettier.format(text, options))
1263
+ TextEdit5.replace(Range7.create(doc.positionAt(0), doc.positionAt(text.length)), prettier.format(text, options))
1063
1264
  ];
1064
1265
  } catch (e) {
1065
1266
  displayError(e);
@@ -1071,13 +1272,14 @@ var marko_default = {
1071
1272
  doComplete,
1072
1273
  doValidate,
1073
1274
  findDefinition,
1275
+ findDocumentLinks,
1074
1276
  format: format2
1075
1277
  };
1076
1278
 
1077
1279
  // src/service/stylesheet/index.ts
1078
1280
  import {
1079
1281
  CompletionList as CompletionList2,
1080
- Range as Range8,
1282
+ Range as Range9,
1081
1283
  TextDocumentEdit
1082
1284
  } from "vscode-languageserver";
1083
1285
  import {
@@ -1223,7 +1425,7 @@ function extractStyleSheets(code, program, lookup) {
1223
1425
  for (const attr of node.attrs) {
1224
1426
  if (attr.type === 8 /* AttrNamed */ && ((_a = attr.value) == null ? void 0 : _a.type) === 11 /* AttrValue */ && /^['"]$/.test(code[attr.value.value.start])) {
1225
1427
  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)) {
1428
+ if (name === "#style" || name === "style" && node.nameText && name === "style" && ((_b = lookup.getTag(node.nameText)) == null ? void 0 : _b.html)) {
1227
1429
  getExtractor("css").write`:root{${{
1228
1430
  start: attr.value.value.start + 1,
1229
1431
  end: attr.value.value.end - 1
@@ -1245,13 +1447,17 @@ function extractStyleSheets(code, program, lookup) {
1245
1447
  }
1246
1448
 
1247
1449
  // src/service/stylesheet/index.ts
1248
- var cache = /* @__PURE__ */ new WeakMap();
1450
+ var cache2 = /* @__PURE__ */ new WeakMap();
1249
1451
  var services = {
1250
1452
  css: getCSSLanguageService,
1251
1453
  less: getLESSLanguageService,
1252
1454
  scss: getSCSSLanguageService
1253
1455
  };
1456
+ var clientCapabilities;
1254
1457
  var StyleSheetService = {
1458
+ initialize(params) {
1459
+ clientCapabilities = params.capabilities;
1460
+ },
1255
1461
  async doComplete(doc, params) {
1256
1462
  const infoByExt = getStyleSheetInfo(doc);
1257
1463
  const sourceOffset = doc.offsetAt(params.position);
@@ -1261,28 +1467,31 @@ var StyleSheetService = {
1261
1467
  if (generatedOffset === void 0)
1262
1468
  continue;
1263
1469
  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);
1470
+ const result = await service2.doComplete2(virtualDoc, virtualDoc.positionAt(generatedOffset), info.parsed, { resolveReference: resolveUrl });
1471
+ if (result.itemDefaults) {
1472
+ const { editRange } = result.itemDefaults;
1473
+ if (editRange) {
1474
+ if ("start" in editRange) {
1475
+ result.itemDefaults.editRange = getSourceRange(doc, info, editRange);
1476
+ } else {
1477
+ editRange.insert = getSourceRange(doc, info, editRange.insert);
1478
+ editRange.replace = getSourceRange(doc, info, editRange.replace);
1269
1479
  }
1270
1480
  }
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
- }
1481
+ }
1482
+ for (const item of result.items) {
1483
+ if (item.textEdit) {
1484
+ item.textEdit = getSourceInsertReplaceEdit(doc, info, item.textEdit);
1485
+ }
1486
+ if (item.additionalTextEdits) {
1487
+ item.additionalTextEdits = getSourceEdits(doc, info, item.additionalTextEdits);
1279
1488
  }
1280
1489
  }
1281
1490
  return result;
1282
1491
  }
1283
1492
  return CompletionList2.create([], true);
1284
1493
  },
1285
- async findDefinition(doc, params) {
1494
+ findDefinition(doc, params) {
1286
1495
  const infoByExt = getStyleSheetInfo(doc);
1287
1496
  const sourceOffset = doc.offsetAt(params.position);
1288
1497
  for (const ext in infoByExt) {
@@ -1292,13 +1501,19 @@ var StyleSheetService = {
1292
1501
  continue;
1293
1502
  const { service: service2, virtualDoc } = info;
1294
1503
  const result = service2.findDefinition(virtualDoc, virtualDoc.positionAt(generatedOffset), info.parsed);
1295
- if (result && updateRange(doc, info, result.range)) {
1296
- return result;
1504
+ if (result) {
1505
+ const range = getSourceRange(doc, info, result.range);
1506
+ if (range) {
1507
+ return {
1508
+ range,
1509
+ uri: doc.uri
1510
+ };
1511
+ }
1297
1512
  }
1298
1513
  break;
1299
1514
  }
1300
1515
  },
1301
- async findReferences(doc, params) {
1516
+ findReferences(doc, params) {
1302
1517
  const infoByExt = getStyleSheetInfo(doc);
1303
1518
  const sourceOffset = doc.offsetAt(params.position);
1304
1519
  for (const ext in infoByExt) {
@@ -1309,14 +1524,40 @@ var StyleSheetService = {
1309
1524
  const { service: service2, virtualDoc } = info;
1310
1525
  const result = [];
1311
1526
  for (const location of service2.findReferences(virtualDoc, virtualDoc.positionAt(generatedOffset), info.parsed)) {
1312
- if (updateRange(doc, info, location.range)) {
1313
- result.push(location);
1527
+ const range = getSourceRange(doc, info, location.range);
1528
+ if (range) {
1529
+ result.push({
1530
+ range,
1531
+ uri: location.uri
1532
+ });
1314
1533
  }
1315
1534
  }
1316
1535
  return result.length ? result : void 0;
1317
1536
  }
1318
1537
  },
1319
- async findDocumentHighlights(doc, params) {
1538
+ findDocumentLinks(doc) {
1539
+ const infoByExt = getStyleSheetInfo(doc);
1540
+ const result = [];
1541
+ for (const ext in infoByExt) {
1542
+ const info = infoByExt[ext];
1543
+ const { service: service2, virtualDoc } = info;
1544
+ for (const link of service2.findDocumentLinks(virtualDoc, info.parsed, {
1545
+ resolveReference: resolveUrl
1546
+ })) {
1547
+ const range = getSourceRange(doc, info, link.range);
1548
+ if (range) {
1549
+ result.push({
1550
+ range,
1551
+ target: link.target,
1552
+ tooltip: link.tooltip,
1553
+ data: link.data
1554
+ });
1555
+ }
1556
+ }
1557
+ }
1558
+ return result.length ? result : void 0;
1559
+ },
1560
+ findDocumentHighlights(doc, params) {
1320
1561
  const infoByExt = getStyleSheetInfo(doc);
1321
1562
  const sourceOffset = doc.offsetAt(params.position);
1322
1563
  for (const ext in infoByExt) {
@@ -1327,30 +1568,36 @@ var StyleSheetService = {
1327
1568
  const { service: service2, virtualDoc } = info;
1328
1569
  const result = [];
1329
1570
  for (const highlight of service2.findDocumentHighlights(virtualDoc, virtualDoc.positionAt(generatedOffset), info.parsed)) {
1330
- if (updateRange(doc, info, highlight.range)) {
1331
- result.push(highlight);
1571
+ const range = getSourceRange(doc, info, highlight.range);
1572
+ if (range) {
1573
+ result.push({
1574
+ range,
1575
+ kind: highlight.kind
1576
+ });
1332
1577
  }
1333
1578
  }
1334
1579
  return result.length ? result : void 0;
1335
1580
  }
1336
1581
  },
1337
- async findDocumentColors(doc) {
1582
+ findDocumentColors(doc) {
1338
1583
  const infoByExt = getStyleSheetInfo(doc);
1339
1584
  const result = [];
1340
1585
  for (const ext in infoByExt) {
1341
1586
  const info = infoByExt[ext];
1342
1587
  const { service: service2, virtualDoc } = info;
1343
1588
  for (const colorInfo of service2.findDocumentColors(virtualDoc, info.parsed)) {
1344
- if (updateRange(doc, info, colorInfo.range)) {
1345
- result.push(colorInfo);
1589
+ const range = getSourceRange(doc, info, colorInfo.range);
1590
+ if (range) {
1591
+ result.push({
1592
+ range,
1593
+ color: colorInfo.color
1594
+ });
1346
1595
  }
1347
1596
  }
1348
1597
  }
1349
- if (result.length) {
1350
- return result;
1351
- }
1598
+ return result.length ? result : void 0;
1352
1599
  },
1353
- async getColorPresentations(doc, params) {
1600
+ getColorPresentations(doc, params) {
1354
1601
  const infoByExt = getStyleSheetInfo(doc);
1355
1602
  const sourceOffset = doc.offsetAt(params.range.start);
1356
1603
  for (const ext in infoByExt) {
@@ -1362,21 +1609,22 @@ var StyleSheetService = {
1362
1609
  if (generatedOffsetEnd === void 0)
1363
1610
  continue;
1364
1611
  const { service: service2, virtualDoc } = info;
1365
- const result = service2.getColorPresentations(virtualDoc, info.parsed, params.color, Range8.create(virtualDoc.positionAt(generatedOffsetStart), virtualDoc.positionAt(generatedOffsetEnd)));
1366
- for (const colorPresentation of result) {
1367
- if (colorPresentation.textEdit) {
1368
- updateTextEdit(doc, info, colorPresentation.textEdit);
1369
- }
1370
- if (colorPresentation.additionalTextEdits) {
1371
- for (const textEdit of colorPresentation.additionalTextEdits) {
1372
- updateTextEdit(doc, info, textEdit);
1373
- }
1612
+ const result = [];
1613
+ for (const colorPresentation of service2.getColorPresentations(virtualDoc, info.parsed, params.color, Range9.create(virtualDoc.positionAt(generatedOffsetStart), virtualDoc.positionAt(generatedOffsetEnd)))) {
1614
+ const textEdit = colorPresentation.textEdit && getSourceEdit(doc, info, colorPresentation.textEdit);
1615
+ const additionalTextEdits = colorPresentation.additionalTextEdits && getSourceEdits(doc, info, colorPresentation.additionalTextEdits);
1616
+ if (textEdit || additionalTextEdits) {
1617
+ result.push({
1618
+ label: colorPresentation.label,
1619
+ textEdit,
1620
+ additionalTextEdits
1621
+ });
1374
1622
  }
1375
1623
  }
1376
- return result;
1624
+ return result.length ? result : void 0;
1377
1625
  }
1378
1626
  },
1379
- async doHover(doc, params) {
1627
+ doHover(doc, params) {
1380
1628
  const infoByExt = getStyleSheetInfo(doc);
1381
1629
  const sourceOffset = doc.offsetAt(params.position);
1382
1630
  for (const ext in infoByExt) {
@@ -1386,8 +1634,18 @@ var StyleSheetService = {
1386
1634
  continue;
1387
1635
  const { service: service2, virtualDoc } = info;
1388
1636
  const result = service2.doHover(virtualDoc, virtualDoc.positionAt(generatedOffset), info.parsed);
1389
- if (result && (!result.range || updateRange(doc, info, result.range))) {
1390
- return result;
1637
+ if (result) {
1638
+ if (result.range) {
1639
+ const range = getSourceRange(doc, info, result.range);
1640
+ if (range) {
1641
+ return {
1642
+ range,
1643
+ contents: result.contents
1644
+ };
1645
+ }
1646
+ } else {
1647
+ return result;
1648
+ }
1391
1649
  }
1392
1650
  }
1393
1651
  },
@@ -1404,9 +1662,7 @@ var StyleSheetService = {
1404
1662
  if (result.changes) {
1405
1663
  for (const uri in result.changes) {
1406
1664
  if (uri === doc.uri) {
1407
- for (const textEdit of result.changes[uri]) {
1408
- updateTextEdit(doc, info, textEdit);
1409
- }
1665
+ result.changes[uri] = getSourceEdits(doc, info, result.changes[uri]) || [];
1410
1666
  }
1411
1667
  }
1412
1668
  }
@@ -1414,9 +1670,7 @@ var StyleSheetService = {
1414
1670
  for (const change of result.documentChanges) {
1415
1671
  if (TextDocumentEdit.is(change)) {
1416
1672
  if (change.textDocument.uri === doc.uri) {
1417
- for (const textEdit of change.edits) {
1418
- updateTextEdit(doc, info, textEdit);
1419
- }
1673
+ change.edits = getSourceEdits(doc, info, change.edits) || [];
1420
1674
  }
1421
1675
  }
1422
1676
  }
@@ -1424,7 +1678,7 @@ var StyleSheetService = {
1424
1678
  return result;
1425
1679
  }
1426
1680
  },
1427
- async doCodeActions(doc, params) {
1681
+ doCodeActions(doc, params) {
1428
1682
  var _a;
1429
1683
  const infoByExt = getStyleSheetInfo(doc);
1430
1684
  const sourceOffset = doc.offsetAt(params.range.start);
@@ -1437,65 +1691,100 @@ var StyleSheetService = {
1437
1691
  if (generatedOffsetEnd === void 0)
1438
1692
  continue;
1439
1693
  const { service: service2, virtualDoc } = info;
1440
- const result = service2.doCodeActions(virtualDoc, Range8.create(virtualDoc.positionAt(generatedOffsetStart), virtualDoc.positionAt(generatedOffsetEnd)), params.context, info.parsed);
1441
- if (result) {
1442
- for (const command of result) {
1443
- const edits = (_a = command.arguments) == null ? void 0 : _a[2];
1444
- if (edits) {
1445
- for (const textEdit of edits) {
1446
- updateTextEdit(doc, info, textEdit);
1447
- }
1448
- }
1694
+ const result = service2.doCodeActions(virtualDoc, Range9.create(virtualDoc.positionAt(generatedOffsetStart), virtualDoc.positionAt(generatedOffsetEnd)), params.context, info.parsed);
1695
+ for (const command of result) {
1696
+ const edits = (_a = command.arguments) == null ? void 0 : _a[2];
1697
+ if (edits && Array.isArray(edits) && isTextEdit(edits[0])) {
1698
+ command.arguments[2] = getSourceEdits(doc, info, edits);
1449
1699
  }
1450
- return result;
1451
1700
  }
1701
+ return result;
1452
1702
  }
1453
1703
  },
1454
- async doValidate(doc) {
1704
+ doValidate(doc) {
1455
1705
  const infoByExt = getStyleSheetInfo(doc);
1456
1706
  const result = [];
1457
1707
  for (const ext in infoByExt) {
1458
1708
  const info = infoByExt[ext];
1459
1709
  for (const diag of info.service.doValidation(info.virtualDoc, info.parsed)) {
1460
- if (updateRange(doc, info, diag.range)) {
1710
+ const range = getSourceRange(doc, info, diag.range);
1711
+ if (range) {
1712
+ diag.range = range;
1461
1713
  result.push(diag);
1462
1714
  }
1463
1715
  }
1464
1716
  }
1465
- return result;
1717
+ return result.length ? result : void 0;
1466
1718
  }
1467
1719
  };
1468
- function updateTextEdit(doc, info, textEdit) {
1469
- if (!updateRange(doc, info, textEdit.range)) {
1470
- textEdit.newText = "";
1471
- textEdit.range = START_OF_FILE;
1720
+ function getSourceEdits(doc, info, edits) {
1721
+ const result = [];
1722
+ for (const edit of edits) {
1723
+ const sourceEdit = getSourceEdit(doc, info, edit);
1724
+ if (sourceEdit) {
1725
+ result.push(sourceEdit);
1726
+ }
1727
+ }
1728
+ return result.length ? result : void 0;
1729
+ }
1730
+ function getSourceEdit(doc, info, textEdit) {
1731
+ const range = getSourceRange(doc, info, textEdit.range);
1732
+ if (range) {
1733
+ return {
1734
+ newText: textEdit.newText,
1735
+ range
1736
+ };
1472
1737
  }
1473
1738
  }
1474
- function updateInsertReplaceEdit(doc, info, insertReplaceEdit) {
1475
- if (!updateRange(doc, info, insertReplaceEdit.insert)) {
1476
- insertReplaceEdit.newText = "";
1477
- insertReplaceEdit.insert = START_OF_FILE;
1739
+ function getSourceInsertReplaceEdit(doc, info, textEdit) {
1740
+ if (isTextEdit(textEdit)) {
1741
+ return getSourceEdit(doc, info, textEdit);
1742
+ } else if (textEdit.replace) {
1743
+ const range = getSourceRange(doc, info, textEdit.replace);
1744
+ if (range) {
1745
+ return {
1746
+ newText: textEdit.newText,
1747
+ replace: range
1748
+ };
1749
+ }
1750
+ } else {
1751
+ const range = getSourceRange(doc, info, textEdit.insert);
1752
+ if (range) {
1753
+ return {
1754
+ newText: textEdit.newText,
1755
+ insert: range
1756
+ };
1757
+ }
1478
1758
  }
1479
1759
  }
1480
- function updateRange(doc, info, range) {
1760
+ function getSourceRange(doc, info, range) {
1481
1761
  const start = info.sourceOffsetAt(info.virtualDoc.offsetAt(range.start));
1482
- const end = info.sourceOffsetAt(info.virtualDoc.offsetAt(range.end));
1483
- if (start !== void 0 || end !== void 0) {
1484
- range.start = doc.positionAt(start ?? end);
1485
- range.end = doc.positionAt(end ?? start);
1486
- return true;
1762
+ if (start === void 0)
1763
+ return;
1764
+ let end = start;
1765
+ if (range.start.line !== range.end.line || range.start.character !== range.end.character) {
1766
+ end = info.sourceOffsetAt(info.virtualDoc.offsetAt(range.end));
1767
+ if (end === void 0)
1768
+ return;
1487
1769
  }
1488
- return false;
1770
+ const pos = doc.positionAt(start);
1771
+ return {
1772
+ start: pos,
1773
+ end: start === end ? pos : doc.positionAt(end)
1774
+ };
1489
1775
  }
1490
1776
  function getStyleSheetInfo(doc) {
1491
1777
  var _a;
1492
1778
  const parsed = parse2(doc);
1493
- let cached = cache.get(parsed);
1779
+ let cached = cache2.get(parsed);
1494
1780
  if (!cached) {
1495
1781
  const results = extractStyleSheets(doc.getText(), parsed.program, getCompilerInfo(doc).lookup);
1496
1782
  cached = {};
1497
1783
  for (const ext in results) {
1498
- const service2 = (_a = services[ext]) == null ? void 0 : _a.call(services);
1784
+ const service2 = (_a = services[ext]) == null ? void 0 : _a.call(services, {
1785
+ fileSystemProvider: file_system_default,
1786
+ clientCapabilities
1787
+ });
1499
1788
  if (!service2)
1500
1789
  continue;
1501
1790
  const { generated, sourceOffsetAt, generatedOffsetAt } = results[ext];
@@ -1508,14 +1797,23 @@ function getStyleSheetInfo(doc) {
1508
1797
  parsed: service2.parseStylesheet(virtualDoc)
1509
1798
  };
1510
1799
  }
1511
- cache.set(parsed, cached);
1800
+ cache2.set(parsed, cached);
1512
1801
  }
1513
1802
  return cached;
1514
1803
  }
1804
+ function isTextEdit(edit) {
1805
+ return edit.range !== void 0;
1806
+ }
1515
1807
 
1516
1808
  // src/service/index.ts
1517
1809
  var plugins = [marko_default, StyleSheetService];
1518
1810
  var service = {
1811
+ async initialize(params) {
1812
+ await Promise.all(plugins.map((plugin) => {
1813
+ var _a;
1814
+ return (_a = plugin.initialize) == null ? void 0 : _a.call(plugin, params);
1815
+ }));
1816
+ },
1519
1817
  async doComplete(doc, params, cancel) {
1520
1818
  const result = CompletionList3.create([], false);
1521
1819
  try {
@@ -1592,6 +1890,30 @@ var service = {
1592
1890
  }
1593
1891
  return result;
1594
1892
  },
1893
+ async findDocumentLinks(doc, params, cancel) {
1894
+ let result;
1895
+ try {
1896
+ const requests = plugins.map((plugin) => {
1897
+ var _a;
1898
+ return (_a = plugin.findDocumentLinks) == null ? void 0 : _a.call(plugin, doc, params, cancel);
1899
+ });
1900
+ for (const pending of requests) {
1901
+ const cur = await pending;
1902
+ if (cancel.isCancellationRequested)
1903
+ return;
1904
+ if (cur) {
1905
+ if (result) {
1906
+ result.push(...cur);
1907
+ } else {
1908
+ result = cur;
1909
+ }
1910
+ }
1911
+ }
1912
+ } catch (err) {
1913
+ displayError(err);
1914
+ }
1915
+ return result;
1916
+ },
1595
1917
  async findDocumentHighlights(doc, params, cancel) {
1596
1918
  let result;
1597
1919
  try {
@@ -1789,8 +2111,9 @@ console.error = (...args) => {
1789
2111
  };
1790
2112
  process.on("uncaughtException", console.error);
1791
2113
  process.on("unhandledRejection", console.error);
1792
- connection2.onInitialize(() => {
2114
+ connection2.onInitialize(async (params) => {
1793
2115
  setup(connection2);
2116
+ await service.initialize(params);
1794
2117
  return {
1795
2118
  capabilities: {
1796
2119
  textDocumentSync: TextDocumentSyncKind.Incremental,
@@ -1800,6 +2123,7 @@ connection2.onInitialize(() => {
1800
2123
  renameProvider: true,
1801
2124
  codeActionProvider: true,
1802
2125
  referencesProvider: true,
2126
+ documentLinkProvider: { resolveProvider: false },
1803
2127
  colorProvider: true,
1804
2128
  documentHighlightProvider: true,
1805
2129
  completionProvider: {
@@ -1844,6 +2168,9 @@ connection2.onDefinition(async (params, cancel) => {
1844
2168
  connection2.onReferences(async (params, cancel) => {
1845
2169
  return await service.findReferences(documents.get(params.textDocument.uri), params, cancel) || null;
1846
2170
  });
2171
+ connection2.onDocumentLinks(async (params, cancel) => {
2172
+ return await service.findDocumentLinks(documents.get(params.textDocument.uri), params, cancel) || null;
2173
+ });
1847
2174
  connection2.onDocumentHighlight(async (params, cancel) => {
1848
2175
  return await service.findDocumentHighlights(documents.get(params.textDocument.uri), params, cancel) || null;
1849
2176
  });