@marko/language-server 0.12.4 → 0.12.7

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.js CHANGED
@@ -30,7 +30,8 @@ var builtinTranslator = __toESM(require("@marko/translator-default"));
30
30
  var import_path = __toESM(require("path"));
31
31
  var import_vscode_uri = require("vscode-uri");
32
32
  function getDocDir(doc) {
33
- return import_path.default.dirname(getDocFile(doc));
33
+ const filename = getDocFile(doc);
34
+ return filename ? import_path.default.dirname(filename) : void 0;
34
35
  }
35
36
  function getDocFile(doc) {
36
37
  return import_vscode_uri.URI.parse(doc.uri).fsPath;
@@ -533,6 +534,12 @@ function isTransparentTag(node) {
533
534
  // src/utils/compiler.ts
534
535
  var lookupKey = Symbol("lookup");
535
536
  var compilerInfoByDir = /* @__PURE__ */ new Map();
537
+ var builtinInfo = {
538
+ cache: /* @__PURE__ */ new Map(),
539
+ lookup: builtinCompiler.taglib.buildLookup(__dirname, builtinTranslator),
540
+ compiler: builtinCompiler,
541
+ translator: builtinTranslator
542
+ };
536
543
  builtinCompiler.configure({ translator: builtinTranslator });
537
544
  function parse2(doc) {
538
545
  const compilerInfo = getCompilerInfo(doc);
@@ -545,6 +552,8 @@ function parse2(doc) {
545
552
  }
546
553
  function getCompilerInfo(doc) {
547
554
  const dir = getDocDir(doc);
555
+ if (!dir)
556
+ return builtinInfo;
548
557
  let info = compilerInfoByDir.get(dir);
549
558
  if (!info) {
550
559
  info = loadCompilerInfo(dir);
@@ -552,25 +561,14 @@ function getCompilerInfo(doc) {
552
561
  }
553
562
  return info;
554
563
  }
555
- function setup(connection3, documents2) {
556
- connection3.onDidChangeWatchedFiles(() => {
557
- clearAllCaches();
558
- });
559
- documents2.onDidChangeContent(({ document }) => {
560
- var _a;
561
- if (document.version > 1) {
562
- if (document.uri.endsWith(".marko")) {
563
- (_a = getCompilerInfo(document)) == null ? void 0 : _a.cache.delete(document);
564
- } else if (/[./\\]marko(?:-tag)?\.json$/.test(document.uri)) {
565
- clearAllCaches();
566
- }
564
+ function clearCompilerCache(doc) {
565
+ if (doc) {
566
+ getCompilerInfo(doc).cache.delete(doc);
567
+ } else {
568
+ for (const [, info] of compilerInfoByDir) {
569
+ info.cache.clear();
570
+ info.compiler.taglib.clearCaches();
567
571
  }
568
- });
569
- }
570
- function clearAllCaches() {
571
- for (const [, info] of compilerInfoByDir) {
572
- info.cache.clear();
573
- info.compiler.taglib.clearCaches();
574
572
  }
575
573
  }
576
574
  function loadCompilerInfo(dir) {
@@ -601,7 +599,7 @@ function loadCompilerInfo(dir) {
601
599
  try {
602
600
  lookup = compiler.taglib.buildLookup(dir, translator);
603
601
  } catch {
604
- lookup = null;
602
+ lookup = builtinInfo.lookup;
605
603
  }
606
604
  cache2.set(lookupKey, lookup);
607
605
  }
@@ -615,7 +613,7 @@ function loadCompilerInfo(dir) {
615
613
  // src/utils/messages.ts
616
614
  var import_util = require("util");
617
615
  var connection;
618
- function setup2(_) {
616
+ function setup(_) {
619
617
  connection = _;
620
618
  }
621
619
  function displayError(data) {
@@ -682,8 +680,6 @@ function OpenTagName({
682
680
  parsed,
683
681
  node
684
682
  }) {
685
- if (!lookup)
686
- return;
687
683
  const currentTemplateFilePath = getDocFile(document);
688
684
  const tag = node.parent;
689
685
  const tagNameLocation = parsed.locationAt(node);
@@ -708,7 +704,7 @@ function OpenTagName({
708
704
  kind: import_vscode_languageserver2.MarkupKind.Markdown,
709
705
  value: it.html ? `Built in [<${it.name}>](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/${it.name}) HTML tag.` : nodeModuleName ? isCoreTag ? `Core Marko [<${it.name}>](${fileURIForTag}) tag.` : `Custom Marko tag discovered from the ["${nodeModuleName}"](${fileURIForTag}) npm package.` : `Custom Marko tag discovered from:
710
706
 
711
- [${import_path2.default.relative(currentTemplateFilePath, fileForTag)}](${fileURIForTag})`
707
+ [${currentTemplateFilePath ? import_path2.default.relative(currentTemplateFilePath, fileForTag) : currentTemplateFilePath}](${fileURIForTag})`
712
708
  };
713
709
  if (it.description) {
714
710
  documentation.value += `
@@ -772,8 +768,6 @@ function AttrName({
772
768
  name = name.slice(0, modifierIndex);
773
769
  }
774
770
  }
775
- if (!lookup)
776
- return;
777
771
  const completions = [];
778
772
  const attrNameLoc = parsed.locationAt(hasModifier ? {
779
773
  start: node.start,
@@ -871,31 +865,27 @@ var doComplete = async (doc, params) => {
871
865
  };
872
866
 
873
867
  // src/service/marko/validate.ts
874
- var import_vscode_uri3 = require("vscode-uri");
875
868
  var import_vscode_languageserver5 = require("vscode-languageserver");
876
869
  var markoErrorRegExp = /^(.+?)(?:\((\d+)(?:\s*,\s*(\d+))?\))?: (.*)$/gm;
877
870
  var doValidate = (doc) => {
878
- const { fsPath, scheme } = import_vscode_uri3.URI.parse(doc.uri);
871
+ const fsPath = getDocFile(doc);
879
872
  const diagnostics = [];
880
- if (scheme === "file") {
881
- const { compiler, translator, cache: cache2, lookup } = getCompilerInfo(doc);
882
- if (lookup) {
883
- try {
884
- compiler.compileSync(doc.getText(), fsPath, {
885
- cache: cache2,
886
- output: "source",
887
- code: false,
888
- translator
889
- });
890
- } catch (e) {
891
- let match;
892
- while (match = markoErrorRegExp.exec(e.message)) {
893
- const [, fileName, rawLine, rawCol, msg] = match;
894
- const line = (parseInt(rawLine, 10) || 1) - 1;
895
- const col = (parseInt(rawCol, 10) || 1) - 1;
896
- diagnostics.push(import_vscode_languageserver5.Diagnostic.create(import_vscode_languageserver5.Range.create(line, col, line, col), msg, import_vscode_languageserver5.DiagnosticSeverity.Error, void 0, fileName));
897
- }
898
- }
873
+ const { compiler, translator, cache: cache2 } = getCompilerInfo(doc);
874
+ try {
875
+ compiler.compileSync(doc.getText(), fsPath || "untitled.marko", {
876
+ cache: cache2,
877
+ translator,
878
+ code: false,
879
+ output: "source",
880
+ sourceMaps: false
881
+ });
882
+ } catch (e) {
883
+ let match;
884
+ while (match = markoErrorRegExp.exec(e.message)) {
885
+ const [, fileName, rawLine, rawCol, msg] = match;
886
+ const line = (parseInt(rawLine, 10) || 1) - 1;
887
+ const col = (parseInt(rawCol, 10) || 1) - 1;
888
+ diagnostics.push(import_vscode_languageserver5.Diagnostic.create(import_vscode_languageserver5.Range.create(line, col, line, col), msg, import_vscode_languageserver5.DiagnosticSeverity.Error, void 0, fileName));
899
889
  }
900
890
  }
901
891
  return diagnostics;
@@ -903,7 +893,7 @@ var doValidate = (doc) => {
903
893
 
904
894
  // src/service/marko/definition/OpenTagName.ts
905
895
  var import_path3 = __toESM(require("path"));
906
- var import_vscode_uri5 = require("vscode-uri");
896
+ var import_vscode_uri4 = require("vscode-uri");
907
897
  var import_vscode_languageserver7 = require("vscode-languageserver");
908
898
 
909
899
  // src/utils/regexp-builder.ts
@@ -932,12 +922,12 @@ function escape(val) {
932
922
 
933
923
  // src/utils/utils.ts
934
924
  var import_fs = __toESM(require("fs"));
935
- var import_vscode_uri4 = require("vscode-uri");
925
+ var import_vscode_uri3 = require("vscode-uri");
936
926
  var import_vscode_languageserver6 = require("vscode-languageserver");
937
927
  var import_vscode_languageserver_textdocument = require("vscode-languageserver-textdocument");
938
928
  var START_OF_FILE = import_vscode_languageserver6.Range.create(import_vscode_languageserver6.Position.create(0, 0), import_vscode_languageserver6.Position.create(0, 0));
939
929
  function createTextDocument(filename) {
940
- const uri = import_vscode_uri4.URI.file(filename).toString();
930
+ const uri = import_vscode_uri3.URI.file(filename).toString();
941
931
  const content = import_fs.default.readFileSync(filename, "utf-8");
942
932
  return import_vscode_languageserver_textdocument.TextDocument.create(uri, "plaintext", 0, content);
943
933
  }
@@ -948,8 +938,6 @@ function OpenTagName2({
948
938
  parsed,
949
939
  node
950
940
  }) {
951
- if (!lookup)
952
- return;
953
941
  const tag = node.parent;
954
942
  let tagDef;
955
943
  let range = START_OF_FILE;
@@ -976,20 +964,18 @@ function OpenTagName2({
976
964
  }
977
965
  }
978
966
  return [
979
- import_vscode_languageserver7.LocationLink.create(import_vscode_uri5.URI.file(tagEntryFile).toString(), range, range, parsed.locationAt(node))
967
+ import_vscode_languageserver7.LocationLink.create(import_vscode_uri4.URI.file(tagEntryFile).toString(), range, range, parsed.locationAt(node))
980
968
  ];
981
969
  }
982
970
 
983
971
  // src/service/marko/definition/AttrName.ts
984
- var import_vscode_uri6 = require("vscode-uri");
972
+ var import_vscode_uri5 = require("vscode-uri");
985
973
  var import_vscode_languageserver8 = require("vscode-languageserver");
986
974
  function AttrName2({
987
975
  lookup,
988
976
  parsed,
989
977
  node
990
978
  }) {
991
- if (!lookup)
992
- return;
993
979
  const tagName = node.parent.parent.nameText;
994
980
  const attrName = parsed.read(node);
995
981
  if (attrName[0] === "{")
@@ -1012,7 +998,7 @@ function AttrName2({
1012
998
  }
1013
999
  }
1014
1000
  return [
1015
- import_vscode_languageserver8.LocationLink.create(import_vscode_uri6.URI.file(attrEntryFile).toString(), range, range, parsed.locationAt(node))
1001
+ import_vscode_languageserver8.LocationLink.create(import_vscode_uri5.URI.file(attrEntryFile).toString(), range, range, parsed.locationAt(node))
1016
1002
  ];
1017
1003
  }
1018
1004
 
@@ -1039,7 +1025,7 @@ var findDefinition = async (doc, params) => {
1039
1025
 
1040
1026
  // src/service/marko/format.ts
1041
1027
  var import_vscode_languageserver9 = require("vscode-languageserver");
1042
- var import_vscode_uri7 = require("vscode-uri");
1028
+ var import_vscode_uri6 = require("vscode-uri");
1043
1029
  var prettier = __toESM(require("prettier"));
1044
1030
  var markoPrettier = __toESM(require("prettier-plugin-marko"));
1045
1031
  var NO_EDIT = [
@@ -1047,7 +1033,7 @@ var NO_EDIT = [
1047
1033
  ];
1048
1034
  var format2 = async (doc, params, token) => {
1049
1035
  try {
1050
- const { fsPath, scheme } = import_vscode_uri7.URI.parse(doc.uri);
1036
+ const { fsPath, scheme } = import_vscode_uri6.URI.parse(doc.uri);
1051
1037
  const text = doc.getText();
1052
1038
  const options = {
1053
1039
  parser: "marko",
@@ -1255,7 +1241,7 @@ var stylesheet_default = {
1255
1241
  if (generatedOffset === void 0)
1256
1242
  continue;
1257
1243
  const { service: service2, virtualDoc } = info;
1258
- const result = service2.doComplete(virtualDoc, virtualDoc.positionAt(generatedOffset), service2.parseStylesheet(virtualDoc));
1244
+ const result = service2.doComplete(virtualDoc, virtualDoc.positionAt(generatedOffset), info.parsed);
1259
1245
  for (const item of result.items) {
1260
1246
  if (item.additionalTextEdits) {
1261
1247
  for (const edit of item.additionalTextEdits) {
@@ -1294,13 +1280,28 @@ var stylesheet_default = {
1294
1280
  if (generatedOffset === void 0)
1295
1281
  continue;
1296
1282
  const { service: service2, virtualDoc } = info;
1297
- const result = service2.findDefinition(virtualDoc, virtualDoc.positionAt(generatedOffset), service2.parseStylesheet(virtualDoc));
1283
+ const result = service2.findDefinition(virtualDoc, virtualDoc.positionAt(generatedOffset), info.parsed);
1298
1284
  if (result && updateRange(doc, info, result.range)) {
1299
1285
  return result;
1300
1286
  }
1301
1287
  break;
1302
1288
  }
1303
1289
  },
1290
+ async doHover(doc, params) {
1291
+ const infoByExt = getStyleSheetInfo(doc);
1292
+ const sourceOffset = doc.offsetAt(params.position);
1293
+ for (const ext in infoByExt) {
1294
+ const info = infoByExt[ext];
1295
+ const generatedOffset = info.generatedOffsetAt(sourceOffset);
1296
+ if (generatedOffset === void 0)
1297
+ continue;
1298
+ const { service: service2, virtualDoc } = info;
1299
+ const result = service2.doHover(virtualDoc, virtualDoc.positionAt(generatedOffset), service2.parseStylesheet(virtualDoc));
1300
+ if (result && (!result.range || updateRange(doc, info, result.range))) {
1301
+ return result;
1302
+ }
1303
+ }
1304
+ },
1304
1305
  async doValidate(doc) {
1305
1306
  const infoByExt = getStyleSheetInfo(doc);
1306
1307
  const result = [];
@@ -1406,6 +1407,20 @@ var service = {
1406
1407
  }
1407
1408
  return result;
1408
1409
  },
1410
+ async doHover(doc, params, cancel) {
1411
+ var _a;
1412
+ try {
1413
+ for (const plugin of plugins) {
1414
+ const result = await ((_a = plugin.doHover) == null ? void 0 : _a.call(plugin, doc, params, cancel));
1415
+ if (cancel.isCancellationRequested)
1416
+ return;
1417
+ if (result)
1418
+ return result;
1419
+ }
1420
+ } catch (err) {
1421
+ displayError(err);
1422
+ }
1423
+ },
1409
1424
  async doValidate(doc) {
1410
1425
  const result = [];
1411
1426
  try {
@@ -1432,8 +1447,9 @@ if (typeof require !== "undefined" && require.extensions && !(".ts" in require.e
1432
1447
  }
1433
1448
  var documents = new import_node.TextDocuments(import_vscode_languageserver_textdocument3.TextDocument);
1434
1449
  var connection2 = (0, import_node.createConnection)(import_node.ProposedFeatures.all);
1435
- var prevDiagnostics = /* @__PURE__ */ new WeakMap();
1436
- var diagnosticTimeouts = /* @__PURE__ */ new WeakMap();
1450
+ var prevDiags = /* @__PURE__ */ new WeakMap();
1451
+ var pendingDiags = /* @__PURE__ */ new WeakSet();
1452
+ var diagnosticTimeout;
1437
1453
  console.log = (...args) => {
1438
1454
  connection2.console.log(args.map((v) => (0, import_util2.inspect)(v)).join(" "));
1439
1455
  };
@@ -1443,13 +1459,13 @@ console.error = (...args) => {
1443
1459
  process.on("uncaughtException", console.error);
1444
1460
  process.on("unhandledRejection", console.error);
1445
1461
  connection2.onInitialize(() => {
1446
- setup2(connection2);
1447
- setup(connection2, documents);
1462
+ setup(connection2);
1448
1463
  return {
1449
1464
  capabilities: {
1450
1465
  textDocumentSync: import_node.TextDocumentSyncKind.Incremental,
1451
1466
  documentFormattingProvider: true,
1452
1467
  definitionProvider: true,
1468
+ hoverProvider: true,
1453
1469
  completionProvider: {
1454
1470
  triggerCharacters: [
1455
1471
  ".",
@@ -1476,11 +1492,12 @@ connection2.onInitialize(() => {
1476
1492
  }
1477
1493
  };
1478
1494
  });
1479
- connection2.onInitialized(() => {
1480
- documents.all().forEach((doc) => queueValidation(doc));
1481
- });
1482
- documents.onDidChangeContent((change) => {
1483
- queueValidation(change.document);
1495
+ connection2.onDidChangeConfiguration(validateDocs);
1496
+ connection2.onDidChangeWatchedFiles(validateDocs);
1497
+ documents.onDidChangeContent(({ document }) => {
1498
+ queueDiagnostic();
1499
+ pendingDiags.add(document);
1500
+ clearCompilerCache(document);
1484
1501
  });
1485
1502
  connection2.onCompletion(async (params, cancel) => {
1486
1503
  return await service.doComplete(documents.get(params.textDocument.uri), params, cancel) || null;
@@ -1488,24 +1505,44 @@ connection2.onCompletion(async (params, cancel) => {
1488
1505
  connection2.onDefinition(async (params, cancel) => {
1489
1506
  return await service.findDefinition(documents.get(params.textDocument.uri), params, cancel) || null;
1490
1507
  });
1508
+ connection2.onHover(async (params, cancel) => {
1509
+ return await service.doHover(documents.get(params.textDocument.uri), params, cancel) || null;
1510
+ });
1491
1511
  connection2.onDocumentFormatting(async (params, cancel) => {
1492
1512
  return await service.format(documents.get(params.textDocument.uri), params, cancel) || null;
1493
1513
  });
1494
- function queueValidation(doc) {
1495
- clearTimeout(diagnosticTimeouts.get(doc));
1496
- const id = setTimeout(async () => {
1497
- const prevDiag = prevDiagnostics.get(doc);
1498
- const nextDiag = await service.doValidate(doc) || [];
1499
- if (diagnosticTimeouts.get(doc) !== id || prevDiag && (0, import_util2.isDeepStrictEqual)(prevDiag, nextDiag)) {
1500
- return;
1514
+ function validateDocs() {
1515
+ queueDiagnostic();
1516
+ clearCompilerCache();
1517
+ for (const doc of documents.all()) {
1518
+ pendingDiags.add(doc);
1519
+ }
1520
+ }
1521
+ function queueDiagnostic() {
1522
+ clearTimeout(diagnosticTimeout);
1523
+ const id = diagnosticTimeout = setTimeout(async () => {
1524
+ const results = await Promise.all(documents.all().map(async (doc) => {
1525
+ if (!pendingDiags.delete(doc))
1526
+ return;
1527
+ const prevDiag = prevDiags.get(doc) || [];
1528
+ const nextDiag = await service.doValidate(doc) || [];
1529
+ if ((0, import_util2.isDeepStrictEqual)(prevDiag, nextDiag))
1530
+ return;
1531
+ return [doc, nextDiag];
1532
+ }));
1533
+ if (id === diagnosticTimeout) {
1534
+ for (const result of results) {
1535
+ if (result) {
1536
+ const [doc, diag] = result;
1537
+ prevDiags.set(doc, diag);
1538
+ connection2.sendDiagnostics({
1539
+ uri: doc.uri,
1540
+ diagnostics: diag
1541
+ });
1542
+ }
1543
+ }
1501
1544
  }
1502
- prevDiagnostics.set(doc, nextDiag);
1503
- connection2.sendDiagnostics({
1504
- uri: doc.uri,
1505
- diagnostics: nextDiag
1506
- });
1507
1545
  }, 400);
1508
- diagnosticTimeouts.set(doc, id);
1509
1546
  }
1510
1547
  documents.listen(connection2);
1511
1548
  connection2.listen();