@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.mjs CHANGED
@@ -1,4 +1,3 @@
1
- "use strict";
2
1
  var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
3
2
  get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
4
3
  }) : x)(function(x) {
@@ -27,7 +26,8 @@ import * as builtinTranslator from "@marko/translator-default";
27
26
  import path from "path";
28
27
  import { URI } from "vscode-uri";
29
28
  function getDocDir(doc) {
30
- return path.dirname(getDocFile(doc));
29
+ const filename = getDocFile(doc);
30
+ return filename ? path.dirname(filename) : void 0;
31
31
  }
32
32
  function getDocFile(doc) {
33
33
  return URI.parse(doc.uri).fsPath;
@@ -530,6 +530,12 @@ function isTransparentTag(node) {
530
530
  // src/utils/compiler.ts
531
531
  var lookupKey = Symbol("lookup");
532
532
  var compilerInfoByDir = /* @__PURE__ */ new Map();
533
+ var builtinInfo = {
534
+ cache: /* @__PURE__ */ new Map(),
535
+ lookup: builtinCompiler.taglib.buildLookup(__dirname, builtinTranslator),
536
+ compiler: builtinCompiler,
537
+ translator: builtinTranslator
538
+ };
533
539
  builtinCompiler.configure({ translator: builtinTranslator });
534
540
  function parse2(doc) {
535
541
  const compilerInfo = getCompilerInfo(doc);
@@ -542,6 +548,8 @@ function parse2(doc) {
542
548
  }
543
549
  function getCompilerInfo(doc) {
544
550
  const dir = getDocDir(doc);
551
+ if (!dir)
552
+ return builtinInfo;
545
553
  let info = compilerInfoByDir.get(dir);
546
554
  if (!info) {
547
555
  info = loadCompilerInfo(dir);
@@ -549,25 +557,14 @@ function getCompilerInfo(doc) {
549
557
  }
550
558
  return info;
551
559
  }
552
- function setup(connection3, documents2) {
553
- connection3.onDidChangeWatchedFiles(() => {
554
- clearAllCaches();
555
- });
556
- documents2.onDidChangeContent(({ document }) => {
557
- var _a;
558
- if (document.version > 1) {
559
- if (document.uri.endsWith(".marko")) {
560
- (_a = getCompilerInfo(document)) == null ? void 0 : _a.cache.delete(document);
561
- } else if (/[./\\]marko(?:-tag)?\.json$/.test(document.uri)) {
562
- clearAllCaches();
563
- }
560
+ function clearCompilerCache(doc) {
561
+ if (doc) {
562
+ getCompilerInfo(doc).cache.delete(doc);
563
+ } else {
564
+ for (const [, info] of compilerInfoByDir) {
565
+ info.cache.clear();
566
+ info.compiler.taglib.clearCaches();
564
567
  }
565
- });
566
- }
567
- function clearAllCaches() {
568
- for (const [, info] of compilerInfoByDir) {
569
- info.cache.clear();
570
- info.compiler.taglib.clearCaches();
571
568
  }
572
569
  }
573
570
  function loadCompilerInfo(dir) {
@@ -598,7 +595,7 @@ function loadCompilerInfo(dir) {
598
595
  try {
599
596
  lookup = compiler.taglib.buildLookup(dir, translator);
600
597
  } catch {
601
- lookup = null;
598
+ lookup = builtinInfo.lookup;
602
599
  }
603
600
  cache2.set(lookupKey, lookup);
604
601
  }
@@ -612,7 +609,7 @@ function loadCompilerInfo(dir) {
612
609
  // src/utils/messages.ts
613
610
  import { inspect } from "util";
614
611
  var connection;
615
- function setup2(_) {
612
+ function setup(_) {
616
613
  connection = _;
617
614
  }
618
615
  function displayError(data) {
@@ -692,8 +689,6 @@ function OpenTagName({
692
689
  parsed,
693
690
  node
694
691
  }) {
695
- if (!lookup)
696
- return;
697
692
  const currentTemplateFilePath = getDocFile(document);
698
693
  const tag = node.parent;
699
694
  const tagNameLocation = parsed.locationAt(node);
@@ -718,7 +713,7 @@ function OpenTagName({
718
713
  kind: MarkupKind.Markdown,
719
714
  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:
720
715
 
721
- [${path2.relative(currentTemplateFilePath, fileForTag)}](${fileURIForTag})`
716
+ [${currentTemplateFilePath ? path2.relative(currentTemplateFilePath, fileForTag) : currentTemplateFilePath}](${fileURIForTag})`
722
717
  };
723
718
  if (it.description) {
724
719
  documentation.value += `
@@ -787,8 +782,6 @@ function AttrName({
787
782
  name = name.slice(0, modifierIndex);
788
783
  }
789
784
  }
790
- if (!lookup)
791
- return;
792
785
  const completions = [];
793
786
  const attrNameLoc = parsed.locationAt(hasModifier ? {
794
787
  start: node.start,
@@ -886,31 +879,27 @@ var doComplete = async (doc, params) => {
886
879
  };
887
880
 
888
881
  // src/service/marko/validate.ts
889
- import { URI as URI3 } from "vscode-uri";
890
882
  import { Diagnostic, DiagnosticSeverity, Range as Range2 } from "vscode-languageserver";
891
883
  var markoErrorRegExp = /^(.+?)(?:\((\d+)(?:\s*,\s*(\d+))?\))?: (.*)$/gm;
892
884
  var doValidate = (doc) => {
893
- const { fsPath, scheme } = URI3.parse(doc.uri);
885
+ const fsPath = getDocFile(doc);
894
886
  const diagnostics = [];
895
- if (scheme === "file") {
896
- const { compiler, translator, cache: cache2, lookup } = getCompilerInfo(doc);
897
- if (lookup) {
898
- try {
899
- compiler.compileSync(doc.getText(), fsPath, {
900
- cache: cache2,
901
- output: "source",
902
- code: false,
903
- translator
904
- });
905
- } catch (e) {
906
- let match;
907
- while (match = markoErrorRegExp.exec(e.message)) {
908
- const [, fileName, rawLine, rawCol, msg] = match;
909
- const line = (parseInt(rawLine, 10) || 1) - 1;
910
- const col = (parseInt(rawCol, 10) || 1) - 1;
911
- diagnostics.push(Diagnostic.create(Range2.create(line, col, line, col), msg, DiagnosticSeverity.Error, void 0, fileName));
912
- }
913
- }
887
+ const { compiler, translator, cache: cache2 } = getCompilerInfo(doc);
888
+ try {
889
+ compiler.compileSync(doc.getText(), fsPath || "untitled.marko", {
890
+ cache: cache2,
891
+ translator,
892
+ code: false,
893
+ output: "source",
894
+ sourceMaps: false
895
+ });
896
+ } catch (e) {
897
+ let match;
898
+ while (match = markoErrorRegExp.exec(e.message)) {
899
+ const [, fileName, rawLine, rawCol, msg] = match;
900
+ const line = (parseInt(rawLine, 10) || 1) - 1;
901
+ const col = (parseInt(rawCol, 10) || 1) - 1;
902
+ diagnostics.push(Diagnostic.create(Range2.create(line, col, line, col), msg, DiagnosticSeverity.Error, void 0, fileName));
914
903
  }
915
904
  }
916
905
  return diagnostics;
@@ -918,7 +907,7 @@ var doValidate = (doc) => {
918
907
 
919
908
  // src/service/marko/definition/OpenTagName.ts
920
909
  import path3 from "path";
921
- import { URI as URI5 } from "vscode-uri";
910
+ import { URI as URI4 } from "vscode-uri";
922
911
  import { Range as Range4, LocationLink } from "vscode-languageserver";
923
912
 
924
913
  // src/utils/regexp-builder.ts
@@ -947,12 +936,12 @@ function escape(val) {
947
936
 
948
937
  // src/utils/utils.ts
949
938
  import fs from "fs";
950
- import { URI as URI4 } from "vscode-uri";
939
+ import { URI as URI3 } from "vscode-uri";
951
940
  import { Position, Range as Range3 } from "vscode-languageserver";
952
941
  import { TextDocument } from "vscode-languageserver-textdocument";
953
942
  var START_OF_FILE = Range3.create(Position.create(0, 0), Position.create(0, 0));
954
943
  function createTextDocument(filename) {
955
- const uri = URI4.file(filename).toString();
944
+ const uri = URI3.file(filename).toString();
956
945
  const content = fs.readFileSync(filename, "utf-8");
957
946
  return TextDocument.create(uri, "plaintext", 0, content);
958
947
  }
@@ -963,8 +952,6 @@ function OpenTagName2({
963
952
  parsed,
964
953
  node
965
954
  }) {
966
- if (!lookup)
967
- return;
968
955
  const tag = node.parent;
969
956
  let tagDef;
970
957
  let range = START_OF_FILE;
@@ -991,20 +978,18 @@ function OpenTagName2({
991
978
  }
992
979
  }
993
980
  return [
994
- LocationLink.create(URI5.file(tagEntryFile).toString(), range, range, parsed.locationAt(node))
981
+ LocationLink.create(URI4.file(tagEntryFile).toString(), range, range, parsed.locationAt(node))
995
982
  ];
996
983
  }
997
984
 
998
985
  // src/service/marko/definition/AttrName.ts
999
- import { URI as URI6 } from "vscode-uri";
986
+ import { URI as URI5 } from "vscode-uri";
1000
987
  import { Range as Range5, LocationLink as LocationLink2 } from "vscode-languageserver";
1001
988
  function AttrName2({
1002
989
  lookup,
1003
990
  parsed,
1004
991
  node
1005
992
  }) {
1006
- if (!lookup)
1007
- return;
1008
993
  const tagName = node.parent.parent.nameText;
1009
994
  const attrName = parsed.read(node);
1010
995
  if (attrName[0] === "{")
@@ -1027,7 +1012,7 @@ function AttrName2({
1027
1012
  }
1028
1013
  }
1029
1014
  return [
1030
- LocationLink2.create(URI6.file(attrEntryFile).toString(), range, range, parsed.locationAt(node))
1015
+ LocationLink2.create(URI5.file(attrEntryFile).toString(), range, range, parsed.locationAt(node))
1031
1016
  ];
1032
1017
  }
1033
1018
 
@@ -1054,7 +1039,7 @@ var findDefinition = async (doc, params) => {
1054
1039
 
1055
1040
  // src/service/marko/format.ts
1056
1041
  import { Position as Position2, Range as Range6, TextEdit as TextEdit4 } from "vscode-languageserver";
1057
- import { URI as URI7 } from "vscode-uri";
1042
+ import { URI as URI6 } from "vscode-uri";
1058
1043
  import * as prettier from "prettier";
1059
1044
  import * as markoPrettier from "prettier-plugin-marko";
1060
1045
  var NO_EDIT = [
@@ -1062,7 +1047,7 @@ var NO_EDIT = [
1062
1047
  ];
1063
1048
  var format2 = async (doc, params, token) => {
1064
1049
  try {
1065
- const { fsPath, scheme } = URI7.parse(doc.uri);
1050
+ const { fsPath, scheme } = URI6.parse(doc.uri);
1066
1051
  const text = doc.getText();
1067
1052
  const options = {
1068
1053
  parser: "marko",
@@ -1276,7 +1261,7 @@ var stylesheet_default = {
1276
1261
  if (generatedOffset === void 0)
1277
1262
  continue;
1278
1263
  const { service: service2, virtualDoc } = info;
1279
- const result = service2.doComplete(virtualDoc, virtualDoc.positionAt(generatedOffset), service2.parseStylesheet(virtualDoc));
1264
+ const result = service2.doComplete(virtualDoc, virtualDoc.positionAt(generatedOffset), info.parsed);
1280
1265
  for (const item of result.items) {
1281
1266
  if (item.additionalTextEdits) {
1282
1267
  for (const edit of item.additionalTextEdits) {
@@ -1315,13 +1300,28 @@ var stylesheet_default = {
1315
1300
  if (generatedOffset === void 0)
1316
1301
  continue;
1317
1302
  const { service: service2, virtualDoc } = info;
1318
- const result = service2.findDefinition(virtualDoc, virtualDoc.positionAt(generatedOffset), service2.parseStylesheet(virtualDoc));
1303
+ const result = service2.findDefinition(virtualDoc, virtualDoc.positionAt(generatedOffset), info.parsed);
1319
1304
  if (result && updateRange(doc, info, result.range)) {
1320
1305
  return result;
1321
1306
  }
1322
1307
  break;
1323
1308
  }
1324
1309
  },
1310
+ async doHover(doc, params) {
1311
+ const infoByExt = getStyleSheetInfo(doc);
1312
+ const sourceOffset = doc.offsetAt(params.position);
1313
+ for (const ext in infoByExt) {
1314
+ const info = infoByExt[ext];
1315
+ const generatedOffset = info.generatedOffsetAt(sourceOffset);
1316
+ if (generatedOffset === void 0)
1317
+ continue;
1318
+ const { service: service2, virtualDoc } = info;
1319
+ const result = service2.doHover(virtualDoc, virtualDoc.positionAt(generatedOffset), service2.parseStylesheet(virtualDoc));
1320
+ if (result && (!result.range || updateRange(doc, info, result.range))) {
1321
+ return result;
1322
+ }
1323
+ }
1324
+ },
1325
1325
  async doValidate(doc) {
1326
1326
  const infoByExt = getStyleSheetInfo(doc);
1327
1327
  const result = [];
@@ -1427,6 +1427,20 @@ var service = {
1427
1427
  }
1428
1428
  return result;
1429
1429
  },
1430
+ async doHover(doc, params, cancel) {
1431
+ var _a;
1432
+ try {
1433
+ for (const plugin of plugins) {
1434
+ const result = await ((_a = plugin.doHover) == null ? void 0 : _a.call(plugin, doc, params, cancel));
1435
+ if (cancel.isCancellationRequested)
1436
+ return;
1437
+ if (result)
1438
+ return result;
1439
+ }
1440
+ } catch (err) {
1441
+ displayError(err);
1442
+ }
1443
+ },
1430
1444
  async doValidate(doc) {
1431
1445
  const result = [];
1432
1446
  try {
@@ -1453,8 +1467,9 @@ if (typeof __require !== "undefined" && __require.extensions && !(".ts" in __req
1453
1467
  }
1454
1468
  var documents = new TextDocuments(TextDocument3);
1455
1469
  var connection2 = createConnection(ProposedFeatures.all);
1456
- var prevDiagnostics = /* @__PURE__ */ new WeakMap();
1457
- var diagnosticTimeouts = /* @__PURE__ */ new WeakMap();
1470
+ var prevDiags = /* @__PURE__ */ new WeakMap();
1471
+ var pendingDiags = /* @__PURE__ */ new WeakSet();
1472
+ var diagnosticTimeout;
1458
1473
  console.log = (...args) => {
1459
1474
  connection2.console.log(args.map((v) => inspect2(v)).join(" "));
1460
1475
  };
@@ -1464,13 +1479,13 @@ console.error = (...args) => {
1464
1479
  process.on("uncaughtException", console.error);
1465
1480
  process.on("unhandledRejection", console.error);
1466
1481
  connection2.onInitialize(() => {
1467
- setup2(connection2);
1468
- setup(connection2, documents);
1482
+ setup(connection2);
1469
1483
  return {
1470
1484
  capabilities: {
1471
1485
  textDocumentSync: TextDocumentSyncKind.Incremental,
1472
1486
  documentFormattingProvider: true,
1473
1487
  definitionProvider: true,
1488
+ hoverProvider: true,
1474
1489
  completionProvider: {
1475
1490
  triggerCharacters: [
1476
1491
  ".",
@@ -1497,11 +1512,12 @@ connection2.onInitialize(() => {
1497
1512
  }
1498
1513
  };
1499
1514
  });
1500
- connection2.onInitialized(() => {
1501
- documents.all().forEach((doc) => queueValidation(doc));
1502
- });
1503
- documents.onDidChangeContent((change) => {
1504
- queueValidation(change.document);
1515
+ connection2.onDidChangeConfiguration(validateDocs);
1516
+ connection2.onDidChangeWatchedFiles(validateDocs);
1517
+ documents.onDidChangeContent(({ document }) => {
1518
+ queueDiagnostic();
1519
+ pendingDiags.add(document);
1520
+ clearCompilerCache(document);
1505
1521
  });
1506
1522
  connection2.onCompletion(async (params, cancel) => {
1507
1523
  return await service.doComplete(documents.get(params.textDocument.uri), params, cancel) || null;
@@ -1509,24 +1525,44 @@ connection2.onCompletion(async (params, cancel) => {
1509
1525
  connection2.onDefinition(async (params, cancel) => {
1510
1526
  return await service.findDefinition(documents.get(params.textDocument.uri), params, cancel) || null;
1511
1527
  });
1528
+ connection2.onHover(async (params, cancel) => {
1529
+ return await service.doHover(documents.get(params.textDocument.uri), params, cancel) || null;
1530
+ });
1512
1531
  connection2.onDocumentFormatting(async (params, cancel) => {
1513
1532
  return await service.format(documents.get(params.textDocument.uri), params, cancel) || null;
1514
1533
  });
1515
- function queueValidation(doc) {
1516
- clearTimeout(diagnosticTimeouts.get(doc));
1517
- const id = setTimeout(async () => {
1518
- const prevDiag = prevDiagnostics.get(doc);
1519
- const nextDiag = await service.doValidate(doc) || [];
1520
- if (diagnosticTimeouts.get(doc) !== id || prevDiag && isDeepStrictEqual(prevDiag, nextDiag)) {
1521
- return;
1534
+ function validateDocs() {
1535
+ queueDiagnostic();
1536
+ clearCompilerCache();
1537
+ for (const doc of documents.all()) {
1538
+ pendingDiags.add(doc);
1539
+ }
1540
+ }
1541
+ function queueDiagnostic() {
1542
+ clearTimeout(diagnosticTimeout);
1543
+ const id = diagnosticTimeout = setTimeout(async () => {
1544
+ const results = await Promise.all(documents.all().map(async (doc) => {
1545
+ if (!pendingDiags.delete(doc))
1546
+ return;
1547
+ const prevDiag = prevDiags.get(doc) || [];
1548
+ const nextDiag = await service.doValidate(doc) || [];
1549
+ if (isDeepStrictEqual(prevDiag, nextDiag))
1550
+ return;
1551
+ return [doc, nextDiag];
1552
+ }));
1553
+ if (id === diagnosticTimeout) {
1554
+ for (const result of results) {
1555
+ if (result) {
1556
+ const [doc, diag] = result;
1557
+ prevDiags.set(doc, diag);
1558
+ connection2.sendDiagnostics({
1559
+ uri: doc.uri,
1560
+ diagnostics: diag
1561
+ });
1562
+ }
1563
+ }
1522
1564
  }
1523
- prevDiagnostics.set(doc, nextDiag);
1524
- connection2.sendDiagnostics({
1525
- uri: doc.uri,
1526
- diagnostics: nextDiag
1527
- });
1528
1565
  }, 400);
1529
- diagnosticTimeouts.set(doc, id);
1530
1566
  }
1531
1567
  documents.listen(connection2);
1532
1568
  connection2.listen();