@marko/language-server 0.12.11 → 0.12.14

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 cache3 = /* @__PURE__ */ new Map();
574
+ const cache4 = /* @__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: cache3,
591
+ cache: cache4,
592
592
  get lookup() {
593
- let lookup = cache3.get(lookupKey);
593
+ let lookup = cache4.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
- cache3.set(lookupKey, lookup);
600
+ cache4.set(lookupKey, lookup);
601
601
  }
602
602
  return lookup;
603
603
  },
@@ -674,76 +674,113 @@ ${closingTagStr}`
674
674
  }
675
675
  }
676
676
 
677
- // src/service/marko/complete/OpenTagName.ts
677
+ // src/service/marko/util/get-tag-name-completion.ts
678
678
  import path2 from "path";
679
- import { URI as URI2 } from "vscode-uri";
680
679
  import {
681
680
  CompletionItemKind as CompletionItemKind2,
681
+ CompletionItemTag,
682
682
  InsertTextFormat as InsertTextFormat2,
683
683
  MarkupKind,
684
684
  TextEdit as TextEdit2
685
685
  } from "vscode-languageserver";
686
+ import { URI as URI2 } from "vscode-uri";
687
+ var deprecated = [CompletionItemTag.Deprecated];
688
+ function getTagNameCompletion({
689
+ tag,
690
+ range,
691
+ showAutoComplete,
692
+ importer
693
+ }) {
694
+ var _a;
695
+ let label = tag.isNestedTag ? `@${tag.name}` : tag.name;
696
+ const fileForTag = tag.template || tag.renderer || tag.filePath;
697
+ const fileURIForTag = URI2.file(fileForTag).toString();
698
+ const nodeModuleMatch = /\/node_modules\/((?:@[^/]+\/)?[^/]+)/.exec(fileForTag);
699
+ const nodeModuleName = nodeModuleMatch && nodeModuleMatch[1];
700
+ const isCoreTag = /^@?marko[/-]/.test(tag.taglibId) || nodeModuleName === "marko";
701
+ const documentation = {
702
+ kind: MarkupKind.Markdown,
703
+ value: tag.html ? `Built in [<${tag.name}>](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/${tag.name}) HTML tag.` : isCoreTag ? `Core Marko <${tag.name}> tag.` : nodeModuleName ? `Custom Marko tag discovered from the ["${nodeModuleName}"](${fileURIForTag}) npm package.` : `Custom Marko tag discovered from:
704
+
705
+ [${importer ? path2.relative(importer, fileForTag) : fileForTag}](${fileURIForTag})`
706
+ };
707
+ if (tag.description) {
708
+ documentation.value += `
709
+
710
+ ${tag.description}`;
711
+ }
712
+ const autocomplete = showAutoComplete ? (_a = tag.autocomplete) == null ? void 0 : _a[0] : void 0;
713
+ if (autocomplete) {
714
+ if (autocomplete.displayText) {
715
+ label = autocomplete.displayText;
716
+ }
717
+ if (autocomplete.description) {
718
+ documentation.value += `
719
+
720
+ ${autocomplete.description}`;
721
+ }
722
+ if (autocomplete.descriptionMoreURL) {
723
+ documentation.value += `
724
+
725
+ [More Info](${autocomplete.descriptionMoreURL})`;
726
+ }
727
+ }
728
+ return {
729
+ label,
730
+ documentation,
731
+ tags: tag.deprecated ? deprecated : void 0,
732
+ insertTextFormat: autocomplete ? InsertTextFormat2.Snippet : void 0,
733
+ kind: tag.html ? CompletionItemKind2.Property : CompletionItemKind2.Class,
734
+ textEdit: range && TextEdit2.replace(range, (autocomplete == null ? void 0 : autocomplete.snippet) || label)
735
+ };
736
+ }
737
+
738
+ // src/service/marko/complete/OpenTagName.ts
686
739
  function OpenTagName({
687
740
  document,
688
741
  lookup,
689
742
  parsed,
690
743
  node
691
744
  }) {
692
- const currentTemplateFilePath = getDocFile(document);
745
+ var _a;
746
+ const importer = getDocFile(document);
693
747
  const tag = node.parent;
694
- const tagNameLocation = parsed.locationAt(node);
695
- let tags;
696
- if (tag.type === 14 /* AttrTag */) {
748
+ const range = parsed.locationAt(node);
749
+ const isAttrTag = tag.type === 14 /* AttrTag */;
750
+ const result = [];
751
+ if (isAttrTag) {
697
752
  let parentTag = tag.owner;
698
753
  while ((parentTag == null ? void 0 : parentTag.type) === 14 /* AttrTag */)
699
754
  parentTag = parentTag.owner;
700
755
  const parentTagDef = parentTag && parentTag.nameText && lookup.getTag(parentTag.nameText);
701
- tags = parentTagDef && parentTagDef.nestedTags && Object.values(parentTagDef.nestedTags) || [];
702
- } else {
703
- tags = lookup.getTagsSorted().filter((it) => !it.isNestedTag);
704
- }
705
- return tags.filter((it) => !it.deprecated).filter((it) => it.name !== "*").filter((it) => /^[^_]/.test(it.name) || !/\/node_modules\//.test(it.filePath)).map((it) => {
706
- let label = it.isNestedTag ? `@${it.name}` : it.name;
707
- const fileForTag = it.template || it.renderer || it.filePath;
708
- const fileURIForTag = URI2.file(fileForTag).toString();
709
- const nodeModuleMatch = /\/node_modules\/((?:@[^/]+\/)?[^/]+)/.exec(fileForTag);
710
- const nodeModuleName = nodeModuleMatch && nodeModuleMatch[1];
711
- const isCoreTag = nodeModuleName === "marko";
712
- const documentation = {
713
- kind: MarkupKind.Markdown,
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:
715
-
716
- [${currentTemplateFilePath ? path2.relative(currentTemplateFilePath, fileForTag) : currentTemplateFilePath}](${fileURIForTag})`
717
- };
718
- if (it.description) {
719
- documentation.value += `
720
-
721
- ${it.description}`;
722
- }
723
- const autocomplete = it.autocomplete && it.autocomplete[0];
724
- if (autocomplete) {
725
- if (autocomplete.displayText) {
726
- label = autocomplete.displayText;
727
- }
728
- if (autocomplete.description) {
729
- documentation.value += `
730
-
731
- ${autocomplete.description}`;
756
+ if (parentTagDef) {
757
+ const { nestedTags } = parentTagDef;
758
+ for (const key in nestedTags) {
759
+ if (key !== "*") {
760
+ const tag2 = nestedTags[key];
761
+ result.push(getTagNameCompletion({
762
+ tag: tag2,
763
+ range,
764
+ importer,
765
+ showAutoComplete: true
766
+ }));
767
+ }
732
768
  }
733
- if (autocomplete.descriptionMoreURL) {
734
- documentation.value += `
735
-
736
- [More Info](${autocomplete.descriptionMoreURL})`;
769
+ }
770
+ } else {
771
+ const skipStatements = !(tag.concise && tag.parent.type === 0 /* Program */);
772
+ for (const tag2 of lookup.getTagsSorted()) {
773
+ if (!(tag2.name === "*" || tag2.isNestedTag || skipStatements && ((_a = tag2.parseOptions) == null ? void 0 : _a.statement) || tag2.name[0] === "_" && /^@?marko[/-]|[\\/]node_modules[\\/]/.test(tag2.filePath))) {
774
+ result.push(getTagNameCompletion({
775
+ tag: tag2,
776
+ range,
777
+ importer,
778
+ showAutoComplete: true
779
+ }));
737
780
  }
738
781
  }
739
- return {
740
- label,
741
- documentation,
742
- kind: CompletionItemKind2.Class,
743
- insertTextFormat: InsertTextFormat2.Snippet,
744
- textEdit: TextEdit2.replace(tagNameLocation, autocomplete && autocomplete.snippet || label)
745
- };
746
- });
782
+ }
783
+ return result;
747
784
  }
748
785
 
749
786
  // src/service/marko/complete/AttrName.ts
@@ -991,12 +1028,52 @@ async function AttrValue({
991
1028
  }
992
1029
  }
993
1030
 
1031
+ // src/service/marko/complete/Statement.ts
1032
+ import { TextEdit as TextEdit5 } from "vscode-languageserver";
1033
+ var importTagReg = /(['"])<((?:[^\1\\>]+|\\.)*)>?\1/g;
1034
+ function Statement({
1035
+ code,
1036
+ node,
1037
+ parsed,
1038
+ lookup,
1039
+ document
1040
+ }) {
1041
+ var _a;
1042
+ if (code[node.start] === "i") {
1043
+ importTagReg.lastIndex = 0;
1044
+ const value = parsed.read(node);
1045
+ const match = importTagReg.exec(value);
1046
+ if (match) {
1047
+ const importer = getDocFile(document);
1048
+ const [{ length }] = match;
1049
+ const range = parsed.locationAt({
1050
+ start: node.start + match.index + 1,
1051
+ end: node.start + match.index + length - 1
1052
+ });
1053
+ const result = [];
1054
+ for (const tag of lookup.getTagsSorted()) {
1055
+ if ((tag.template || tag.renderer) && !(tag.html || tag.parser || tag.translator || tag.isNestedTag || tag.name === "*" || ((_a = tag.parseOptions) == null ? void 0 : _a.statement) || /^@?marko[/-]/.test(tag.taglibId) || tag.name[0] === "_" && /[\\/]node_modules[\\/]/.test(tag.filePath))) {
1056
+ const completion = getTagNameCompletion({
1057
+ tag,
1058
+ importer
1059
+ });
1060
+ completion.label = `<${completion.label}>`;
1061
+ completion.textEdit = TextEdit5.replace(range, completion.label);
1062
+ result.push(completion);
1063
+ }
1064
+ }
1065
+ return result;
1066
+ }
1067
+ }
1068
+ }
1069
+
994
1070
  // src/service/marko/complete/index.ts
995
1071
  var handlers = {
996
1072
  Tag,
997
1073
  OpenTagName,
998
1074
  AttrName,
999
- AttrValue
1075
+ AttrValue,
1076
+ Statement
1000
1077
  };
1001
1078
  var doComplete = async (doc, params) => {
1002
1079
  var _a;
@@ -1020,10 +1097,10 @@ var markoErrorRegExp = /^(.+?)(?:\((\d+)(?:\s*,\s*(\d+))?\))?: (.*)$/gm;
1020
1097
  var doValidate = (doc) => {
1021
1098
  const fsPath = getDocFile(doc);
1022
1099
  const diagnostics = [];
1023
- const { compiler, translator, cache: cache3 } = getCompilerInfo(doc);
1100
+ const { compiler, translator, cache: cache4 } = getCompilerInfo(doc);
1024
1101
  try {
1025
1102
  compiler.compileSync(doc.getText(), fsPath || "untitled.marko", {
1026
- cache: cache3,
1103
+ cache: cache4,
1027
1104
  translator,
1028
1105
  code: false,
1029
1106
  output: "source",
@@ -1041,6 +1118,62 @@ var doValidate = (doc) => {
1041
1118
  return diagnostics;
1042
1119
  };
1043
1120
 
1121
+ // src/utils/utils.ts
1122
+ import fs2 from "fs";
1123
+ import { URI as URI3 } from "vscode-uri";
1124
+ import { Position, Range as Range4 } from "vscode-languageserver";
1125
+ import { TextDocument } from "vscode-languageserver-textdocument";
1126
+ var START_OF_FILE = Range4.create(Position.create(0, 0), Position.create(0, 0));
1127
+ function createTextDocument(filename) {
1128
+ const uri = URI3.file(filename).toString();
1129
+ const content = fs2.readFileSync(filename, "utf-8");
1130
+ return TextDocument.create(uri, "plaintext", 0, content);
1131
+ }
1132
+
1133
+ // src/service/marko/hover/OpenTagName.ts
1134
+ function OpenTagName2({
1135
+ document,
1136
+ lookup,
1137
+ parsed,
1138
+ node
1139
+ }) {
1140
+ const importer = getDocFile(document);
1141
+ const tag = node.parent;
1142
+ const range = parsed.locationAt(node);
1143
+ const tagDef = tag.nameText && lookup.getTag(tag.nameText);
1144
+ if (tagDef) {
1145
+ const completion = getTagNameCompletion({
1146
+ tag: tagDef,
1147
+ range: START_OF_FILE,
1148
+ importer
1149
+ });
1150
+ return {
1151
+ range,
1152
+ contents: completion.documentation
1153
+ };
1154
+ }
1155
+ }
1156
+
1157
+ // src/service/marko/hover/index.ts
1158
+ var handlers2 = {
1159
+ OpenTagName: OpenTagName2
1160
+ };
1161
+ var doHover = async (doc, params) => {
1162
+ var _a;
1163
+ const parsed = parse2(doc);
1164
+ const offset = doc.offsetAt(params.position);
1165
+ const node = parsed.nodeAt(offset);
1166
+ return await ((_a = handlers2[NodeType[node.type]]) == null ? void 0 : _a.call(handlers2, {
1167
+ document: doc,
1168
+ params,
1169
+ parsed,
1170
+ offset,
1171
+ node,
1172
+ code: doc.getText(),
1173
+ ...getCompilerInfo(doc)
1174
+ }));
1175
+ };
1176
+
1044
1177
  // src/service/marko/definition/OpenTagName.ts
1045
1178
  import path4 from "path";
1046
1179
  import { URI as URI4 } from "vscode-uri";
@@ -1070,20 +1203,8 @@ function escape(val) {
1070
1203
  return String(val).replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
1071
1204
  }
1072
1205
 
1073
- // src/utils/utils.ts
1074
- import fs2 from "fs";
1075
- import { URI as URI3 } from "vscode-uri";
1076
- import { Position, Range as Range4 } from "vscode-languageserver";
1077
- import { TextDocument } from "vscode-languageserver-textdocument";
1078
- var START_OF_FILE = Range4.create(Position.create(0, 0), Position.create(0, 0));
1079
- function createTextDocument(filename) {
1080
- const uri = URI3.file(filename).toString();
1081
- const content = fs2.readFileSync(filename, "utf-8");
1082
- return TextDocument.create(uri, "plaintext", 0, content);
1083
- }
1084
-
1085
1206
  // src/service/marko/definition/OpenTagName.ts
1086
- function OpenTagName2({
1207
+ function OpenTagName3({
1087
1208
  lookup,
1088
1209
  parsed,
1089
1210
  node
@@ -1153,8 +1274,8 @@ function AttrName2({
1153
1274
  }
1154
1275
 
1155
1276
  // src/service/marko/definition/index.ts
1156
- var handlers2 = {
1157
- OpenTagName: OpenTagName2,
1277
+ var handlers3 = {
1278
+ OpenTagName: OpenTagName3,
1158
1279
  AttrName: AttrName2
1159
1280
  };
1160
1281
  var findDefinition = async (doc, params) => {
@@ -1162,7 +1283,7 @@ var findDefinition = async (doc, params) => {
1162
1283
  const parsed = parse2(doc);
1163
1284
  const offset = doc.offsetAt(params.position);
1164
1285
  const node = parsed.nodeAt(offset);
1165
- return await ((_a = handlers2[NodeType[node.type]]) == null ? void 0 : _a.call(handlers2, {
1286
+ return await ((_a = handlers3[NodeType[node.type]]) == null ? void 0 : _a.call(handlers3, {
1166
1287
  document: doc,
1167
1288
  params,
1168
1289
  parsed,
@@ -1173,10 +1294,20 @@ var findDefinition = async (doc, params) => {
1173
1294
  })) || [];
1174
1295
  };
1175
1296
 
1176
- // src/service/marko/document-links/extract.ts
1297
+ // src/service/marko/document-links.ts
1177
1298
  import { DocumentLink } from "vscode-languageserver";
1178
1299
  import { URI as URI6 } from "vscode-uri";
1179
- var importTagReg = /(['"])<((?:[^\1\\>]+|\\.)*)>?\1/g;
1300
+ var importTagReg2 = /(['"])<((?:[^\1\\>]+|\\.)*)>?\1/g;
1301
+ var cache = /* @__PURE__ */ new WeakMap();
1302
+ var findDocumentLinks = async (doc) => {
1303
+ const parsed = parse2(doc);
1304
+ let result = cache.get(parsed);
1305
+ if (!result) {
1306
+ result = extractDocumentLinks(doc, parsed, getCompilerInfo(doc).lookup);
1307
+ cache.set(parsed, result);
1308
+ }
1309
+ return result;
1310
+ };
1180
1311
  function extractDocumentLinks(doc, parsed, lookup) {
1181
1312
  if (URI6.parse(doc.uri).scheme === "untitled") {
1182
1313
  return [];
@@ -1187,14 +1318,21 @@ function extractDocumentLinks(doc, parsed, lookup) {
1187
1318
  const read = (range) => code.slice(range.start, range.end);
1188
1319
  const visit = (node) => {
1189
1320
  switch (node.type) {
1321
+ case 14 /* AttrTag */:
1322
+ if (node.body) {
1323
+ for (const child of node.body) {
1324
+ visit(child);
1325
+ }
1326
+ }
1327
+ break;
1190
1328
  case 1 /* Tag */:
1191
1329
  if (node.attrs && node.nameText) {
1192
1330
  for (const attr of node.attrs) {
1193
1331
  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)));
1332
+ const resolved = resolveUrl(read(attr.value.value).slice(1, -1), doc.uri);
1333
+ if (resolved) {
1334
+ links.push(DocumentLink.create(parsed.locationAt(attr.value.value), resolveUrl(read(attr.value.value).slice(1, -1), doc.uri)));
1335
+ }
1198
1336
  }
1199
1337
  }
1200
1338
  }
@@ -1208,18 +1346,18 @@ function extractDocumentLinks(doc, parsed, lookup) {
1208
1346
  };
1209
1347
  for (const item of program.static) {
1210
1348
  if (item.type === 20 /* Statement */ && code[item.start] === "i") {
1211
- importTagReg.lastIndex = 0;
1349
+ importTagReg2.lastIndex = 0;
1212
1350
  const value = parsed.read(item);
1213
- const match = importTagReg.exec(value);
1351
+ const match = importTagReg2.exec(value);
1214
1352
  if (match) {
1215
1353
  const [{ length }, , tagName] = match;
1216
1354
  const tagDef = lookup.getTag(tagName);
1217
1355
  const fileForTag = tagDef && (tagDef.template || tagDef.renderer);
1218
1356
  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));
1357
+ links.push(DocumentLink.create(parsed.locationAt({
1358
+ start: item.start + match.index,
1359
+ end: item.start + match.index + length
1360
+ }), fileForTag));
1223
1361
  }
1224
1362
  }
1225
1363
  }
@@ -1230,26 +1368,53 @@ function extractDocumentLinks(doc, parsed, lookup) {
1230
1368
  return links;
1231
1369
  }
1232
1370
 
1233
- // src/service/marko/document-links/index.ts
1234
- var cache = /* @__PURE__ */ new WeakMap();
1235
- var findDocumentLinks = async (doc) => {
1371
+ // src/service/marko/document-symbols.ts
1372
+ import { URI as URI7 } from "vscode-uri";
1373
+ import { SymbolInformation, SymbolKind } from "vscode-languageserver";
1374
+ var cache2 = /* @__PURE__ */ new WeakMap();
1375
+ var findDocumentSymbols = async (doc) => {
1236
1376
  const parsed = parse2(doc);
1237
- let result = cache.get(parsed);
1377
+ let result = cache2.get(parsed);
1238
1378
  if (!result) {
1239
- result = extractDocumentLinks(doc, parsed, getCompilerInfo(doc).lookup);
1240
- cache.set(parsed, result);
1379
+ result = extractDocumentSymbols(doc, parsed, getCompilerInfo(doc).lookup);
1380
+ cache2.set(parsed, result);
1241
1381
  }
1242
1382
  return result;
1243
1383
  };
1384
+ function extractDocumentSymbols(doc, parsed, lookup) {
1385
+ if (URI7.parse(doc.uri).scheme === "untitled") {
1386
+ return [];
1387
+ }
1388
+ const symbols = [];
1389
+ const { program } = parsed;
1390
+ const visit = (node) => {
1391
+ var _a, _b;
1392
+ switch (node.type) {
1393
+ case 1 /* Tag */:
1394
+ case 14 /* AttrTag */:
1395
+ symbols.push(SymbolInformation.create((node.type === 14 /* AttrTag */ ? (_a = node.nameText) == null ? void 0 : _a.slice(node.nameText.indexOf("@")) : node.nameText) || "<${...}>", node.nameText && ((_b = lookup.getTag(node.nameText)) == null ? void 0 : _b.html) && SymbolKind.Property || SymbolKind.Class, parsed.locationAt(node), doc.uri));
1396
+ if (node.body) {
1397
+ for (const child of node.body) {
1398
+ visit(child);
1399
+ }
1400
+ }
1401
+ break;
1402
+ }
1403
+ };
1404
+ for (const item of program.body) {
1405
+ visit(item);
1406
+ }
1407
+ return symbols;
1408
+ }
1244
1409
 
1245
1410
  // src/service/marko/format.ts
1246
- import { Range as Range7, TextEdit as TextEdit5 } from "vscode-languageserver";
1247
- import { URI as URI7 } from "vscode-uri";
1411
+ import { Range as Range7, TextEdit as TextEdit6 } from "vscode-languageserver";
1412
+ import { URI as URI8 } from "vscode-uri";
1248
1413
  import * as prettier from "prettier";
1249
1414
  import * as markoPrettier from "prettier-plugin-marko";
1250
1415
  var format2 = async (doc, params, cancel) => {
1251
1416
  try {
1252
- const { fsPath, scheme } = URI7.parse(doc.uri);
1417
+ const { fsPath, scheme } = URI8.parse(doc.uri);
1253
1418
  const text = doc.getText();
1254
1419
  const options = {
1255
1420
  parser: "marko",
@@ -1264,7 +1429,7 @@ var format2 = async (doc, params, cancel) => {
1264
1429
  if (cancel.isCancellationRequested)
1265
1430
  return;
1266
1431
  return [
1267
- TextEdit5.replace(Range7.create(doc.positionAt(0), doc.positionAt(text.length)), prettier.format(text, options))
1432
+ TextEdit6.replace(Range7.create(doc.positionAt(0), doc.positionAt(text.length)), prettier.format(text, options))
1268
1433
  ];
1269
1434
  } catch (e) {
1270
1435
  displayError(e);
@@ -1275,8 +1440,10 @@ var format2 = async (doc, params, cancel) => {
1275
1440
  var marko_default = {
1276
1441
  doComplete,
1277
1442
  doValidate,
1443
+ doHover,
1278
1444
  findDefinition,
1279
1445
  findDocumentLinks,
1446
+ findDocumentSymbols,
1280
1447
  format: format2
1281
1448
  };
1282
1449
 
@@ -1395,6 +1562,13 @@ function extractStyleSheets(code, program, lookup) {
1395
1562
  const visit = (node) => {
1396
1563
  var _a, _b;
1397
1564
  switch (node.type) {
1565
+ case 14 /* AttrTag */:
1566
+ if (node.body) {
1567
+ for (const child of node.body) {
1568
+ visit(child);
1569
+ }
1570
+ }
1571
+ break;
1398
1572
  case 1 /* Tag */:
1399
1573
  if (node.nameText === "style" && node.concise && node.attrs) {
1400
1574
  const block = node.attrs.at(-1);
@@ -1451,7 +1625,7 @@ function extractStyleSheets(code, program, lookup) {
1451
1625
  }
1452
1626
 
1453
1627
  // src/service/stylesheet/index.ts
1454
- var cache2 = /* @__PURE__ */ new WeakMap();
1628
+ var cache3 = /* @__PURE__ */ new WeakMap();
1455
1629
  var services = {
1456
1630
  css: getCSSLanguageService,
1457
1631
  less: getLESSLanguageService,
@@ -1539,6 +1713,32 @@ var StyleSheetService = {
1539
1713
  return result.length ? result : void 0;
1540
1714
  }
1541
1715
  },
1716
+ findDocumentSymbols(doc) {
1717
+ const infoByExt = getStyleSheetInfo(doc);
1718
+ const result = [];
1719
+ for (const ext in infoByExt) {
1720
+ const info = infoByExt[ext];
1721
+ const { service: service2, virtualDoc } = info;
1722
+ for (const symbol of service2.findDocumentSymbols(virtualDoc, info.parsed)) {
1723
+ if (symbol.location.uri === doc.uri) {
1724
+ const range = getSourceRange(doc, info, symbol.location.range);
1725
+ if (range) {
1726
+ result.push({
1727
+ kind: symbol.kind,
1728
+ name: symbol.name,
1729
+ tags: symbol.tags,
1730
+ deprecated: symbol.deprecated,
1731
+ containerName: symbol.containerName,
1732
+ location: { uri: doc.uri, range }
1733
+ });
1734
+ }
1735
+ } else {
1736
+ result.push(symbol);
1737
+ }
1738
+ }
1739
+ }
1740
+ return result.length ? result : void 0;
1741
+ },
1542
1742
  async findDocumentLinks(doc) {
1543
1743
  const infoByExt = getStyleSheetInfo(doc);
1544
1744
  const result = [];
@@ -1778,7 +1978,7 @@ function getSourceRange(doc, info, range) {
1778
1978
  function getStyleSheetInfo(doc) {
1779
1979
  var _a;
1780
1980
  const parsed = parse2(doc);
1781
- let cached = cache2.get(parsed);
1981
+ let cached = cache3.get(parsed);
1782
1982
  if (!cached) {
1783
1983
  const results = extractStyleSheets(doc.getText(), parsed.program, getCompilerInfo(doc).lookup);
1784
1984
  cached = {};
@@ -1799,7 +1999,7 @@ function getStyleSheetInfo(doc) {
1799
1999
  parsed: service2.parseStylesheet(virtualDoc)
1800
2000
  };
1801
2001
  }
1802
- cache2.set(parsed, cached);
2002
+ cache3.set(parsed, cached);
1803
2003
  }
1804
2004
  return cached;
1805
2005
  }
@@ -1817,51 +2017,47 @@ var service = {
1817
2017
  }));
1818
2018
  },
1819
2019
  async doComplete(doc, params, cancel) {
1820
- const result = CompletionList3.create([], false);
2020
+ let items;
2021
+ let isIncomplete = false;
1821
2022
  try {
1822
- const requests = plugins.map((plugin) => {
2023
+ for (const pending of plugins.map((plugin) => {
1823
2024
  var _a;
1824
2025
  return (_a = plugin.doComplete) == null ? void 0 : _a.call(plugin, doc, params, cancel);
1825
- });
1826
- for (const pending of requests) {
2026
+ })) {
1827
2027
  const cur = await pending;
1828
2028
  if (cancel.isCancellationRequested)
1829
2029
  return;
1830
2030
  if (cur) {
1831
- let items;
2031
+ let curItems;
1832
2032
  if (Array.isArray(cur)) {
1833
- items = cur;
2033
+ curItems = cur;
1834
2034
  } else {
1835
- items = cur.items;
1836
- result.isIncomplete || (result.isIncomplete = cur.isIncomplete);
2035
+ curItems = cur.items;
2036
+ isIncomplete || (isIncomplete = cur.isIncomplete);
1837
2037
  }
1838
- result.items.push(...items);
2038
+ items = items ? items.concat(curItems) : curItems;
1839
2039
  }
1840
2040
  }
1841
2041
  } catch (err) {
1842
- result.isIncomplete = true;
2042
+ isIncomplete = true;
1843
2043
  displayError(err);
1844
2044
  }
1845
- return result;
2045
+ if (items) {
2046
+ return CompletionList3.create(items, isIncomplete);
2047
+ }
1846
2048
  },
1847
2049
  async findDefinition(doc, params, cancel) {
1848
- const result = [];
2050
+ let result;
1849
2051
  try {
1850
- const requests = plugins.map((plugin) => {
2052
+ for (const pending of plugins.map((plugin) => {
1851
2053
  var _a;
1852
2054
  return (_a = plugin.findDefinition) == null ? void 0 : _a.call(plugin, doc, params, cancel);
1853
- });
1854
- for (const pending of requests) {
2055
+ })) {
1855
2056
  const cur = await pending;
1856
2057
  if (cancel.isCancellationRequested)
1857
2058
  return;
1858
- if (cur) {
1859
- if (Array.isArray(cur)) {
1860
- result.push(...cur);
1861
- } else {
1862
- result.push(cur);
1863
- }
1864
- }
2059
+ if (cur)
2060
+ result = (result || []).concat(cur);
1865
2061
  }
1866
2062
  } catch (err) {
1867
2063
  displayError(err);
@@ -1871,21 +2067,33 @@ var service = {
1871
2067
  async findReferences(doc, params, cancel) {
1872
2068
  let result;
1873
2069
  try {
1874
- const requests = plugins.map((plugin) => {
2070
+ for (const pending of plugins.map((plugin) => {
1875
2071
  var _a;
1876
2072
  return (_a = plugin.findReferences) == null ? void 0 : _a.call(plugin, doc, params, cancel);
1877
- });
1878
- for (const pending of requests) {
2073
+ })) {
1879
2074
  const cur = await pending;
1880
2075
  if (cancel.isCancellationRequested)
1881
2076
  return;
1882
- if (cur) {
1883
- if (result) {
1884
- result.push(...cur);
1885
- } else {
1886
- result = cur;
1887
- }
1888
- }
2077
+ if (cur)
2078
+ result = result ? result.concat(cur) : cur;
2079
+ }
2080
+ } catch (err) {
2081
+ displayError(err);
2082
+ }
2083
+ return result;
2084
+ },
2085
+ async findDocumentSymbols(doc, params, cancel) {
2086
+ let result;
2087
+ try {
2088
+ for (const pending of plugins.map((plugin) => {
2089
+ var _a;
2090
+ return (_a = plugin.findDocumentSymbols) == null ? void 0 : _a.call(plugin, doc, params, cancel);
2091
+ })) {
2092
+ const cur = await pending;
2093
+ if (cancel.isCancellationRequested)
2094
+ return;
2095
+ if (cur)
2096
+ result = result ? result.concat(cur) : cur;
1889
2097
  }
1890
2098
  } catch (err) {
1891
2099
  displayError(err);
@@ -1895,21 +2103,15 @@ var service = {
1895
2103
  async findDocumentLinks(doc, params, cancel) {
1896
2104
  let result;
1897
2105
  try {
1898
- const requests = plugins.map((plugin) => {
2106
+ for (const pending of plugins.map((plugin) => {
1899
2107
  var _a;
1900
2108
  return (_a = plugin.findDocumentLinks) == null ? void 0 : _a.call(plugin, doc, params, cancel);
1901
- });
1902
- for (const pending of requests) {
2109
+ })) {
1903
2110
  const cur = await pending;
1904
2111
  if (cancel.isCancellationRequested)
1905
2112
  return;
1906
- if (cur) {
1907
- if (result) {
1908
- result.push(...cur);
1909
- } else {
1910
- result = cur;
1911
- }
1912
- }
2113
+ if (cur)
2114
+ result = result ? result.concat(cur) : cur;
1913
2115
  }
1914
2116
  } catch (err) {
1915
2117
  displayError(err);
@@ -1919,21 +2121,15 @@ var service = {
1919
2121
  async findDocumentHighlights(doc, params, cancel) {
1920
2122
  let result;
1921
2123
  try {
1922
- const requests = plugins.map((plugin) => {
2124
+ for (const pending of plugins.map((plugin) => {
1923
2125
  var _a;
1924
2126
  return (_a = plugin.findDocumentHighlights) == null ? void 0 : _a.call(plugin, doc, params, cancel);
1925
- });
1926
- for (const pending of requests) {
2127
+ })) {
1927
2128
  const cur = await pending;
1928
2129
  if (cancel.isCancellationRequested)
1929
2130
  return;
1930
- if (cur) {
1931
- if (result) {
1932
- result.push(...cur);
1933
- } else {
1934
- result = cur;
1935
- }
1936
- }
2131
+ if (cur)
2132
+ result = result ? result.concat(cur) : cur;
1937
2133
  }
1938
2134
  } catch (err) {
1939
2135
  displayError(err);
@@ -1943,21 +2139,15 @@ var service = {
1943
2139
  async findDocumentColors(doc, params, cancel) {
1944
2140
  let result;
1945
2141
  try {
1946
- const requests = plugins.map((plugin) => {
2142
+ for (const pending of plugins.map((plugin) => {
1947
2143
  var _a;
1948
2144
  return (_a = plugin.findDocumentColors) == null ? void 0 : _a.call(plugin, doc, params, cancel);
1949
- });
1950
- for (const pending of requests) {
2145
+ })) {
1951
2146
  const cur = await pending;
1952
2147
  if (cancel.isCancellationRequested)
1953
2148
  return;
1954
- if (cur) {
1955
- if (result) {
1956
- result.push(...cur);
1957
- } else {
1958
- result = cur;
1959
- }
1960
- }
2149
+ if (cur)
2150
+ result = result ? result.concat(cur) : cur;
1961
2151
  }
1962
2152
  } catch (err) {
1963
2153
  displayError(err);
@@ -1967,21 +2157,15 @@ var service = {
1967
2157
  async getColorPresentations(doc, params, cancel) {
1968
2158
  let result;
1969
2159
  try {
1970
- const requests = plugins.map((plugin) => {
2160
+ for (const pending of plugins.map((plugin) => {
1971
2161
  var _a;
1972
2162
  return (_a = plugin.getColorPresentations) == null ? void 0 : _a.call(plugin, doc, params, cancel);
1973
- });
1974
- for (const pending of requests) {
2163
+ })) {
1975
2164
  const cur = await pending;
1976
2165
  if (cancel.isCancellationRequested)
1977
2166
  return;
1978
- if (cur) {
1979
- if (result) {
1980
- result.push(...cur);
1981
- } else {
1982
- result = cur;
1983
- }
1984
- }
2167
+ if (cur)
2168
+ result = result ? result.concat(cur) : cur;
1985
2169
  }
1986
2170
  } catch (err) {
1987
2171
  displayError(err);
@@ -2007,41 +2191,32 @@ var service = {
2007
2191
  let changeAnnotations;
2008
2192
  let documentChanges;
2009
2193
  try {
2010
- const requests = plugins.map((plugin) => {
2194
+ for (const pending of plugins.map((plugin) => {
2011
2195
  var _a;
2012
2196
  return (_a = plugin.doRename) == null ? void 0 : _a.call(plugin, doc, params, cancel);
2013
- });
2014
- for (const pending of requests) {
2197
+ })) {
2015
2198
  const cur = await pending;
2016
2199
  if (cancel.isCancellationRequested)
2017
2200
  return;
2018
2201
  if (cur) {
2019
2202
  if (cur.changes) {
2020
2203
  if (changes) {
2204
+ changes = { ...changes };
2021
2205
  for (const uri in cur.changes) {
2022
- if (changes[uri]) {
2023
- changes[uri].push(...cur.changes[uri]);
2024
- } else {
2025
- changes[uri] = cur.changes[uri];
2026
- }
2206
+ changes[uri] = changes[uri] ? changes[uri].concat(cur.changes[uri]) : cur.changes[uri];
2027
2207
  }
2028
2208
  } else {
2029
2209
  changes = cur.changes;
2030
2210
  }
2031
2211
  }
2032
2212
  if (cur.changeAnnotations) {
2033
- if (changeAnnotations) {
2034
- Object.assign(changeAnnotations, cur.changeAnnotations);
2035
- } else {
2036
- changeAnnotations = cur.changeAnnotations;
2037
- }
2213
+ changeAnnotations = changeAnnotations ? {
2214
+ ...changeAnnotations,
2215
+ ...cur.changeAnnotations
2216
+ } : cur.changeAnnotations;
2038
2217
  }
2039
2218
  if (cur.documentChanges) {
2040
- if (documentChanges) {
2041
- documentChanges.push(...cur.documentChanges);
2042
- } else {
2043
- documentChanges = cur.documentChanges;
2044
- }
2219
+ documentChanges = documentChanges ? documentChanges.concat(cur.documentChanges) : cur.documentChanges;
2045
2220
  }
2046
2221
  }
2047
2222
  }
@@ -2057,19 +2232,17 @@ var service = {
2057
2232
  }
2058
2233
  },
2059
2234
  async doCodeActions(doc, params, cancel) {
2060
- const result = [];
2235
+ let result;
2061
2236
  try {
2062
- const requests = plugins.map((plugin) => {
2237
+ for (const pending of plugins.map((plugin) => {
2063
2238
  var _a;
2064
2239
  return (_a = plugin.doCodeActions) == null ? void 0 : _a.call(plugin, doc, params, cancel);
2065
- });
2066
- for (const pending of requests) {
2240
+ })) {
2067
2241
  const cur = await pending;
2068
2242
  if (cancel.isCancellationRequested)
2069
2243
  return;
2070
- if (cur) {
2071
- result.push(...cur);
2072
- }
2244
+ if (cur)
2245
+ result = result ? result.concat(cur) : cur;
2073
2246
  }
2074
2247
  } catch (err) {
2075
2248
  displayError(err);
@@ -2077,16 +2250,15 @@ var service = {
2077
2250
  return result;
2078
2251
  },
2079
2252
  async doValidate(doc) {
2080
- const result = [];
2253
+ let result;
2081
2254
  try {
2082
- const requests = plugins.map((plugin) => {
2255
+ for (const pending of plugins.map((plugin) => {
2083
2256
  var _a;
2084
2257
  return (_a = plugin.doValidate) == null ? void 0 : _a.call(plugin, doc);
2085
- });
2086
- for (const pending of requests) {
2258
+ })) {
2087
2259
  const cur = await pending;
2088
2260
  if (cur)
2089
- result.push(...cur);
2261
+ result = result ? result.concat(cur) : cur;
2090
2262
  }
2091
2263
  } catch (err) {
2092
2264
  displayError(err);
@@ -2128,6 +2300,7 @@ connection2.onInitialize(async (params) => {
2128
2300
  documentLinkProvider: { resolveProvider: false },
2129
2301
  colorProvider: true,
2130
2302
  documentHighlightProvider: true,
2303
+ documentSymbolProvider: true,
2131
2304
  completionProvider: {
2132
2305
  triggerCharacters: [
2133
2306
  ".",
@@ -2173,6 +2346,9 @@ connection2.onReferences(async (params, cancel) => {
2173
2346
  connection2.onDocumentLinks(async (params, cancel) => {
2174
2347
  return await service.findDocumentLinks(documents.get(params.textDocument.uri), params, cancel) || null;
2175
2348
  });
2349
+ connection2.onDocumentSymbol(async (params, cancel) => {
2350
+ return await service.findDocumentSymbols(documents.get(params.textDocument.uri), params, cancel) || null;
2351
+ });
2176
2352
  connection2.onDocumentHighlight(async (params, cancel) => {
2177
2353
  return await service.findDocumentHighlights(documents.get(params.textDocument.uri), params, cancel) || null;
2178
2354
  });