luaut-language-server 2.0.0 → 3.0.0

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/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  startServer
4
- } from "./chunk-SXRYJV32.js";
4
+ } from "./chunk-X2GHHRWT.js";
5
5
 
6
6
  // src/cli.ts
7
7
  startServer();
package/dist/index.cjs CHANGED
@@ -819,11 +819,28 @@ var import_luaut_parser4 = require("luaut-parser");
819
819
  function hover(analysis, position) {
820
820
  const path = pathAt(analysis.program, position, true);
821
821
  for (let i = path.length - 1; i >= 0; i--) {
822
+ if (UNNAMED.has(path[i].type)) return null;
822
823
  const text = describe(analysis, path, i);
823
824
  if (text) return { contents: { kind: "markdown", value: code(text) }, range: toRange(path[i]) };
824
825
  }
825
826
  return null;
826
827
  }
828
+ var UNNAMED = /* @__PURE__ */ new Set([
829
+ "BinaryExpression",
830
+ "UnaryExpression",
831
+ "CallExpression",
832
+ "MethodCallExpression",
833
+ "MemberExpression",
834
+ "IndexExpression",
835
+ "ParenthesizedExpression",
836
+ "IfElseExpression",
837
+ "TableExpression",
838
+ "ArrayExpression",
839
+ "TypeAssertionExpression",
840
+ "SatisfiesExpression",
841
+ "AsConstExpression",
842
+ "InterpolatedStringExpression"
843
+ ]);
827
844
  var PRIMITIVES = /* @__PURE__ */ new Set(["any", "unknown", "never", "nil", "boolean", "number", "string", "thread", "buffer"]);
828
845
  function describe(analysis, path, index) {
829
846
  const { types } = analysis;
@@ -865,6 +882,9 @@ function describe(analysis, path, index) {
865
882
  case "DeclareStatement":
866
883
  if (parent.id === node) return declareText(analysis, parent);
867
884
  break;
885
+ case "DeclareClassStatement":
886
+ if (parent.name === node) return classText(analysis, name);
887
+ break;
868
888
  case "TableTypeProperty":
869
889
  if (parent.key === node) {
870
890
  const type2 = typeOfNode(parent.valueType);
@@ -896,7 +916,7 @@ function describe(analysis, path, index) {
896
916
  const binding = bindingOfNode(analysis, identifier2);
897
917
  if (binding) {
898
918
  const type2 = types.bindingType.get(binding.id);
899
- if (type2) return `${keyword(binding)} ${binding.name}: ${pretty(type2)}`;
919
+ if (type2) return bindingText(binding, type2);
900
920
  }
901
921
  if (parent?.type === "MemberExpression" || parent?.type === "MethodCallExpression") {
902
922
  const type2 = types.typeOf.get(parent);
@@ -904,13 +924,13 @@ function describe(analysis, path, index) {
904
924
  }
905
925
  return void 0;
906
926
  }
907
- // Declarations: `const x`, a parameter, `const function f`.
927
+ // Declarations: `const x`, a parameter.
908
928
  case "IdentifierPattern":
909
929
  case "FunctionParameter":
910
930
  case "TypedIdentifier": {
911
931
  const binding = bindingOfNode(analysis, node);
912
932
  const type2 = binding && types.bindingType.get(binding.id);
913
- return type2 ? `${keyword(binding)} ${binding.name}: ${pretty(type2)}` : void 0;
933
+ return type2 ? bindingText(binding, type2) : void 0;
914
934
  }
915
935
  // A type written by name: `number`, `Shape`, `Partial<User>`, or a type
916
936
  // parameter in scope.
@@ -921,9 +941,11 @@ function describe(analysis, path, index) {
921
941
  if (parameter) return typeParameterText(analysis, parameter);
922
942
  if (PRIMITIVES.has(base)) return `type ${base}`;
923
943
  }
924
- if (!node.namespace && !node.typeArguments.length) {
925
- const alias = types.aliases.get(base);
926
- if (alias) return `type ${base} = ${pretty(alias)}`;
944
+ if (!node.typeArguments.length) {
945
+ const qualified = node.namespace ? `${node.namespace}.${base}` : base;
946
+ const alias = types.aliases.get(qualified);
947
+ if (alias && (0, import_luaut_parser4.isClassType)(alias)) return classText(analysis, qualified);
948
+ if (alias) return `type ${qualified} = ${pretty(alias)}`;
927
949
  }
928
950
  const type2 = typeOfNode(node);
929
951
  return type2 && `type ${referenceText(analysis, node)} = ${pretty(type2)}`;
@@ -952,6 +974,19 @@ function declareText(analysis, statement) {
952
974
  const overloads = others > 0 ? ` (+${others} overload${others > 1 ? "s" : ""})` : "";
953
975
  return `declare function ${name}${(0, import_luaut_parser4.formatType)(own)}${overloads}`;
954
976
  }
977
+ function classText(analysis, name) {
978
+ const type = analysis.types.aliases.get(name);
979
+ if (!type || !(0, import_luaut_parser4.isClassType)(type)) return void 0;
980
+ const superclass = type.class.superclass;
981
+ const inherited = superclass ? analysis.types.aliases.get(superclass) : void 0;
982
+ const own = [...type.properties].filter(([key, property]) => inherited?.kind !== "object" || inherited.properties.get(key) !== property);
983
+ const head = `declare class ${name}${superclass ? ` extends ${superclass}` : ""}`;
984
+ if (!own.length) return `${head} {}`;
985
+ const lines = own.map(([key, property]) => ` ${property.readonly ? "readonly " : ""}${key}${property.optional ? "?" : ""}: ${(0, import_luaut_parser4.formatType)(property.type)},`);
986
+ return `${head} {
987
+ ${lines.join("\n")}
988
+ }`;
989
+ }
955
990
  function typeParameterText(analysis, parameter) {
956
991
  return `(type parameter) ${typeParameterSignature(analysis, parameter)}`;
957
992
  }
@@ -1011,10 +1046,19 @@ ${lines.join("\n")}
1011
1046
  }
1012
1047
  return flat;
1013
1048
  }
1049
+ function bindingText(binding, type) {
1050
+ if (binding.declaredBy === "function" && type.kind === "function") {
1051
+ return `function ${binding.name}${(0, import_luaut_parser4.formatType)(type)}`;
1052
+ }
1053
+ return `${keyword(binding)} ${binding.name}: ${pretty(type)}`;
1054
+ }
1014
1055
  function keyword(binding) {
1015
1056
  if (binding.kind === "param" || binding.kind === "self") return "(parameter)";
1016
1057
  if (binding.kind === "global") return "(global)";
1017
1058
  if (binding.kind.startsWith("for-")) return "(loop variable)";
1059
+ if (binding.declaredBy === "import" || binding.declaredBy === "namespace") return "(import)";
1060
+ if (binding.declaredBy === "type") return "(type import)";
1061
+ if (binding.declaredBy === "function") return "function";
1018
1062
  return binding.isConst ? "const" : "let";
1019
1063
  }
1020
1064
  function code(text) {
@@ -1116,10 +1160,10 @@ function completion(analyzer, document, position) {
1116
1160
  }
1117
1161
  if (operator || !first) return [];
1118
1162
  if (inTypePosition(first.path)) {
1119
- const named = [...first.analysis.types.aliases.keys()].map((name) => ({
1163
+ const named = [...first.analysis.types.aliases].map(([name, type]) => ({
1120
1164
  label: name,
1121
- kind: import_vscode_languageserver4.CompletionItemKind.Interface,
1122
- detail: "type"
1165
+ kind: (0, import_luaut_parser5.isClassType)(type) ? import_vscode_languageserver4.CompletionItemKind.Class : import_vscode_languageserver4.CompletionItemKind.Interface,
1166
+ detail: (0, import_luaut_parser5.isClassType)(type) ? "class" : "type"
1123
1167
  }));
1124
1168
  const primitives = PRIMITIVES2.map((name) => ({
1125
1169
  label: name,
@@ -1210,6 +1254,7 @@ function valueItems(analysis, at) {
1210
1254
  const seen = /* @__PURE__ */ new Set();
1211
1255
  for (const binding of analysis.scopes.bindings.values()) {
1212
1256
  if (binding.name === PLACEHOLDER || seen.has(binding.name)) continue;
1257
+ if (binding.declaredBy === "type") continue;
1213
1258
  const declaration = binding.declarationNode;
1214
1259
  if (declaration && declaration.line.start - 1 > at.line) continue;
1215
1260
  seen.add(binding.name);
@@ -1251,7 +1296,7 @@ function kindOf(type, bindingKind) {
1251
1296
  }
1252
1297
  function inTypePosition(path) {
1253
1298
  return path.some(
1254
- (n) => !!n.type && (n.type.endsWith("TypeNode") || n.type === "TypeReference" || n.type === "TypeAliasStatement" || n.type === "ExportTypeAliasStatement")
1299
+ (n) => !!n.type && (n.type.endsWith("TypeNode") || n.type === "TypeReference" || n.type === "TypeAliasStatement" || n.type === "ExportTypeAliasStatement" || n.type === "DeclareClassStatement")
1255
1300
  );
1256
1301
  }
1257
1302
  var PRIMITIVES2 = [
@@ -1392,6 +1437,12 @@ function documentSymbols(analysis) {
1392
1437
  }
1393
1438
  break;
1394
1439
  }
1440
+ case "DeclareClassStatement": {
1441
+ const name = node.name.name;
1442
+ const superclass = node.superclass?.base;
1443
+ out.push(symbol(name, import_vscode_languageserver5.SymbolKind.Class, node, superclass && `extends ${superclass}`));
1444
+ break;
1445
+ }
1395
1446
  case "VariableDeclaration": {
1396
1447
  for (const target of node.names ?? []) {
1397
1448
  const name = target.name;
@@ -1433,6 +1484,7 @@ var import_luaut_parser7 = require("luaut-parser");
1433
1484
  var TOKEN_TYPES = [
1434
1485
  "namespace",
1435
1486
  "type",
1487
+ "class",
1436
1488
  "typeParameter",
1437
1489
  "parameter",
1438
1490
  "variable",
@@ -1449,6 +1501,7 @@ var semanticTokensLegend = {
1449
1501
  var SOFT_KEYWORDS = /* @__PURE__ */ new Set([
1450
1502
  "type",
1451
1503
  "declare",
1504
+ "class",
1452
1505
  "extends",
1453
1506
  "keyof",
1454
1507
  "infer",
@@ -1515,6 +1568,8 @@ function classify(analysis, spanned, ancestors, identifiers, add) {
1515
1568
  if (!baseToken) return;
1516
1569
  if (!namespace && typeParameterInScope2(ancestors, base)) {
1517
1570
  add(baseToken, base.length, "typeParameter");
1571
+ } else if ((0, import_luaut_parser7.isClassType)(analysis.types.aliases.get(namespace ? `${namespace}.${base}` : base) ?? import_luaut_parser7.unknownType)) {
1572
+ add(baseToken, base.length, "class");
1518
1573
  } else {
1519
1574
  add(baseToken, base.length, "type", PRIMITIVES3.has(base) ? ["defaultLibrary"] : []);
1520
1575
  }
@@ -1542,6 +1597,9 @@ function identifier(analysis, node, parent, add) {
1542
1597
  case "ExportTypeAliasStatement":
1543
1598
  if (parent.name === node) return as("type", ["declaration"]);
1544
1599
  break;
1600
+ case "DeclareClassStatement":
1601
+ if (parent.name === node) return as("class", ["declaration"]);
1602
+ break;
1545
1603
  case "DeclareStatement":
1546
1604
  if (parent.id === node) return as(isFunction(typeOfNode(parent.valueType)) ? "function" : "variable", ["declaration"]);
1547
1605
  break;
@@ -1565,10 +1623,14 @@ function identifier(analysis, node, parent, add) {
1565
1623
  break;
1566
1624
  case "ImportSpecifier": {
1567
1625
  const binding2 = bindingOfNode(analysis, node);
1626
+ if (binding2?.declaredBy === "type") return as("type", ["declaration"]);
1568
1627
  const value = binding2 && analysis.types.bindingType.get(binding2.id);
1569
1628
  if (analysis.types.aliases.has(name) && (!value || value.kind === "any")) return as("type", ["declaration"]);
1570
1629
  break;
1571
1630
  }
1631
+ case "ImportStatement":
1632
+ if (parent.namespaceImport === node) return as("namespace", ["declaration"]);
1633
+ break;
1572
1634
  case "ExportSpecifier":
1573
1635
  if (!bindingOfNode(analysis, node) && analysis.types.aliases.has(name)) return as("type");
1574
1636
  break;
@@ -1584,6 +1646,7 @@ function identifier(analysis, node, parent, add) {
1584
1646
  function valueKind(analysis, binding) {
1585
1647
  if (!binding) return "variable";
1586
1648
  if (binding.kind === "param" || binding.kind === "self") return "parameter";
1649
+ if (binding.declaredBy === "namespace") return "namespace";
1587
1650
  return isFunction(analysis.types.bindingType.get(binding.id)) ? "function" : "variable";
1588
1651
  }
1589
1652
  function modifiersOf(binding, isDeclaration) {