@marko/language-server 0.12.2 → 0.12.5

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.
Files changed (38) hide show
  1. package/dist/index.js +1322 -555
  2. package/dist/index.js.map +3 -3
  3. package/dist/index.mjs +1350 -605
  4. package/dist/index.mjs.map +3 -3
  5. package/dist/service/index.d.ts +6 -0
  6. package/dist/service/marko/complete/AttrName.d.ts +3 -0
  7. package/dist/service/marko/complete/OpenTagName.d.ts +3 -0
  8. package/dist/service/marko/complete/Tag.d.ts +6 -0
  9. package/dist/service/marko/complete/index.d.ts +14 -0
  10. package/dist/service/marko/definition/AttrName.d.ts +3 -0
  11. package/dist/service/marko/definition/OpenTagName.d.ts +3 -0
  12. package/dist/service/marko/definition/index.d.ts +14 -0
  13. package/dist/service/marko/format.d.ts +2 -0
  14. package/dist/service/marko/index.d.ts +3 -0
  15. package/dist/service/marko/validate.d.ts +2 -0
  16. package/dist/service/stylesheet/extract.d.ts +10 -0
  17. package/dist/service/stylesheet/index.d.ts +3 -0
  18. package/dist/service/types.d.ts +12 -0
  19. package/dist/utils/compiler.d.ts +16 -4
  20. package/dist/utils/doc-file.d.ts +3 -0
  21. package/dist/utils/extractor.d.ts +12 -0
  22. package/dist/utils/get-node-at-offset.d.ts +2 -0
  23. package/dist/utils/messages.d.ts +5 -0
  24. package/dist/utils/parser.d.ts +176 -0
  25. package/dist/utils/utils.d.ts +1 -8
  26. package/package.json +15 -14
  27. package/LICENSE +0 -20
  28. package/dist/utils/completions/index.d.ts +0 -6
  29. package/dist/utils/completions/types/attributeModifier.d.ts +0 -5
  30. package/dist/utils/completions/types/attributeName.d.ts +0 -5
  31. package/dist/utils/completions/types/closeTag.d.ts +0 -5
  32. package/dist/utils/completions/types/openTag.d.ts +0 -5
  33. package/dist/utils/completions/types/openTagName.d.ts +0 -5
  34. package/dist/utils/completions/types/styleContent.d.ts +0 -5
  35. package/dist/utils/definitions/index.d.ts +0 -2
  36. package/dist/utils/definitions/types/attributeName.d.ts +0 -5
  37. package/dist/utils/definitions/types/openTagName.d.ts +0 -5
  38. package/dist/utils/htmljs-parser.d.ts +0 -128
package/dist/index.mjs CHANGED
@@ -1,19 +1,4 @@
1
- var __defProp = Object.defineProperty;
2
- var __getOwnPropSymbols = Object.getOwnPropertySymbols;
3
- var __hasOwnProp = Object.prototype.hasOwnProperty;
4
- var __propIsEnum = Object.prototype.propertyIsEnumerable;
5
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
6
- var __spreadValues = (a, b) => {
7
- for (var prop in b || (b = {}))
8
- if (__hasOwnProp.call(b, prop))
9
- __defNormalProp(a, prop, b[prop]);
10
- if (__getOwnPropSymbols)
11
- for (var prop of __getOwnPropSymbols(b)) {
12
- if (__propIsEnum.call(b, prop))
13
- __defNormalProp(a, prop, b[prop]);
14
- }
15
- return a;
16
- };
1
+ "use strict";
17
2
  var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
18
3
  get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
19
4
  }) : x)(function(x) {
@@ -21,346 +6,806 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
21
6
  return require.apply(this, arguments);
22
7
  throw new Error('Dynamic require of "' + x + '" is not supported');
23
8
  });
24
- var __export = (target, all) => {
25
- for (var name in all)
26
- __defProp(target, name, { get: all[name], enumerable: true });
27
- };
28
9
 
29
10
  // src/index.ts
30
11
  import {
31
12
  createConnection,
32
13
  ProposedFeatures,
33
- Range as Range4,
34
- Position as Position3,
35
- CompletionList as CompletionList6,
36
- Diagnostic,
37
- DiagnosticSeverity,
38
14
  TextDocuments,
39
- TextEdit as TextEdit5,
40
15
  TextDocumentSyncKind
41
16
  } from "vscode-languageserver/node";
42
- import { URI as URI6 } from "vscode-uri";
43
17
  import { TextDocument as TextDocument3 } from "vscode-languageserver-textdocument";
44
- import * as prettier from "prettier";
45
- import * as markoPrettier from "prettier-plugin-marko";
46
- import { inspect, isDeepStrictEqual } from "util";
18
+ import { inspect as inspect2, isDeepStrictEqual } from "util";
47
19
 
48
20
  // src/utils/compiler.ts
49
- import path from "path";
50
- import { URI } from "vscode-uri";
21
+ import { URI as URI2 } from "vscode-uri";
51
22
  import resolveFrom from "resolve-from";
52
23
  import lassoPackageRoot from "lasso-package-root";
53
24
  import * as builtinCompiler from "@marko/compiler";
54
25
  import * as builtinTranslator from "@marko/translator-default";
55
- builtinCompiler.configure({ translator: builtinTranslator });
56
- var compilerAndTranslatorForDoc = /* @__PURE__ */ new WeakMap();
57
- function getCompilerAndTranslatorForDoc(doc) {
58
- let compilerAndTranslator = compilerAndTranslatorForDoc.get(doc);
59
- if (!compilerAndTranslator) {
60
- compilerAndTranslatorForDoc.set(doc, compilerAndTranslator = loadCompiler(path.dirname(URI.parse(doc.uri).fsPath)));
26
+
27
+ // src/utils/doc-file.ts
28
+ import path from "path";
29
+ import { URI } from "vscode-uri";
30
+ function getDocDir(doc) {
31
+ const filename = getDocFile(doc);
32
+ return filename ? path.dirname(filename) : void 0;
33
+ }
34
+ function getDocFile(doc) {
35
+ return URI.parse(doc.uri).fsPath;
36
+ }
37
+
38
+ // src/utils/parser.ts
39
+ import { createParser, TagType, Range, Ranges } from "htmljs-parser";
40
+
41
+ // src/utils/get-node-at-offset.ts
42
+ function getNodeAtOffset(offset, program) {
43
+ const bodyNode = childAtOffset(offset, program.body);
44
+ if (bodyNode)
45
+ return visitChildNode(offset, bodyNode);
46
+ return childAtOffset(offset, program.static) || program;
47
+ }
48
+ function visitChildNode(offset, child) {
49
+ switch (child.type) {
50
+ case 1 /* Tag */:
51
+ case 14 /* AttrTag */:
52
+ return visitTag(offset, child);
53
+ default:
54
+ return child;
61
55
  }
62
- return compilerAndTranslator;
63
56
  }
64
- function getTagLibLookup(document) {
65
- try {
66
- const { compiler, translator } = getCompilerAndTranslatorForDoc(document);
67
- return compiler.taglib.buildLookup(URI.parse(document.uri).fsPath, translator);
68
- } catch {
57
+ function visitTag(offset, tag) {
58
+ const { body } = tag;
59
+ if (body && offset > tag.open.end) {
60
+ const childNode = childAtOffset(offset, body);
61
+ return childNode ? visitChildNode(offset, childNode) : tag;
62
+ }
63
+ const { attrs } = tag;
64
+ if (attrs && offset > attrs[0].start) {
65
+ const attrNode = childAtOffset(offset, attrs);
66
+ return attrNode ? visitAttrNode(offset, attrNode) : tag;
67
+ }
68
+ const { var: tagVar } = tag;
69
+ if (tagVar && offset > tagVar.start && offset <= tagVar.end) {
70
+ return tagVar;
69
71
  }
72
+ const { args } = tag;
73
+ if (args && offset > args.start && offset <= args.end) {
74
+ return args;
75
+ }
76
+ const { params } = tag;
77
+ if (params && offset > params.start && offset <= params.end) {
78
+ return params;
79
+ }
80
+ const { name } = tag;
81
+ if (name && offset <= name.end) {
82
+ return name;
83
+ }
84
+ return tag;
70
85
  }
71
- function loadCompiler(dir) {
72
- const rootDir = lassoPackageRoot.getRootDir(dir);
73
- const pkgPath = rootDir && resolveFrom.silent(rootDir, "@marko/compiler/package.json");
74
- const pkg = pkgPath && __require(pkgPath);
75
- if (pkg && /^5\./.test(pkg.version)) {
76
- try {
77
- let translator = [].concat(Object.keys(pkg.dependencies), Object.keys(pkg.peerDependencies), Object.keys(pkg.devDependencies)).find((name) => /^marko$|^(@\/marko\/|marko-)translator-/.test(name));
78
- if (translator === "marko" || !translator) {
79
- translator = __require(resolveFrom(dir, "@marko/compiler/config")).translator;
86
+ function visitAttrNode(offset, attr) {
87
+ switch (attr.type) {
88
+ case 14 /* AttrTag */:
89
+ return visitTag(offset, attr);
90
+ case 8 /* AttrNamed */: {
91
+ const { value } = attr;
92
+ if (value && offset > value.start) {
93
+ return value;
80
94
  }
81
- __require(resolveFrom(dir, translator));
82
- return {
83
- compiler: __require(resolveFrom(dir, "@marko/compiler")),
84
- translator
85
- };
86
- } catch {
95
+ const { name } = attr;
96
+ if (offset > name.start && offset <= name.end) {
97
+ return name;
98
+ }
99
+ break;
87
100
  }
88
101
  }
89
- return {
90
- compiler: builtinCompiler,
91
- translator: builtinTranslator
92
- };
102
+ return attr;
103
+ }
104
+ function childAtOffset(offset, children) {
105
+ let max = children.length - 1;
106
+ if (max === -1)
107
+ return void 0;
108
+ let min = 0;
109
+ while (min < max) {
110
+ const mid = 1 + min + max >>> 1;
111
+ if (children[mid].start < offset) {
112
+ min = mid;
113
+ } else {
114
+ max = mid - 1;
115
+ }
116
+ }
117
+ const child = children[min];
118
+ return offset > child.start && offset <= child.end ? child : void 0;
93
119
  }
94
120
 
95
- // src/utils/htmljs-parser.ts
96
- import { createParser } from "htmljs-parser";
97
- var SUPPORTED_STYLE_LANGS = {
98
- css: true,
99
- scss: true,
100
- less: true
101
- };
102
- function parseUntilOffset(options) {
103
- const { offset, text, taglib, includeErrors } = options;
104
- let result = null;
105
- let parentTag = null;
121
+ // src/utils/parser.ts
122
+ var UNFINISHED = Number.MAX_SAFE_INTEGER;
123
+ var NodeType = /* @__PURE__ */ ((NodeType2) => {
124
+ NodeType2[NodeType2["Program"] = 0] = "Program";
125
+ NodeType2[NodeType2["Tag"] = 1] = "Tag";
126
+ NodeType2[NodeType2["OpenTagName"] = 2] = "OpenTagName";
127
+ NodeType2[NodeType2["ShorthandId"] = 3] = "ShorthandId";
128
+ NodeType2[NodeType2["ShorthandClassName"] = 4] = "ShorthandClassName";
129
+ NodeType2[NodeType2["TagVar"] = 5] = "TagVar";
130
+ NodeType2[NodeType2["TagArgs"] = 6] = "TagArgs";
131
+ NodeType2[NodeType2["TagParams"] = 7] = "TagParams";
132
+ NodeType2[NodeType2["AttrNamed"] = 8] = "AttrNamed";
133
+ NodeType2[NodeType2["AttrName"] = 9] = "AttrName";
134
+ NodeType2[NodeType2["AttrArgs"] = 10] = "AttrArgs";
135
+ NodeType2[NodeType2["AttrValue"] = 11] = "AttrValue";
136
+ NodeType2[NodeType2["AttrMethod"] = 12] = "AttrMethod";
137
+ NodeType2[NodeType2["AttrSpread"] = 13] = "AttrSpread";
138
+ NodeType2[NodeType2["AttrTag"] = 14] = "AttrTag";
139
+ NodeType2[NodeType2["Text"] = 15] = "Text";
140
+ NodeType2[NodeType2["CDATA"] = 16] = "CDATA";
141
+ NodeType2[NodeType2["Doctype"] = 17] = "Doctype";
142
+ NodeType2[NodeType2["Declaration"] = 18] = "Declaration";
143
+ NodeType2[NodeType2["Comment"] = 19] = "Comment";
144
+ NodeType2[NodeType2["Statement"] = 20] = "Statement";
145
+ NodeType2[NodeType2["Placeholder"] = 21] = "Placeholder";
146
+ NodeType2[NodeType2["Scriptlet"] = 22] = "Scriptlet";
147
+ return NodeType2;
148
+ })(NodeType || {});
149
+ function parse(source) {
150
+ const program = {
151
+ type: 0 /* Program */,
152
+ parent: void 0,
153
+ static: [],
154
+ body: [],
155
+ start: 0,
156
+ end: source.length
157
+ };
158
+ let curBodyType;
159
+ let curOpenTagStart;
160
+ let curParent = program;
161
+ let curAttr = void 0;
162
+ let curBody = program.body;
106
163
  const parser = createParser({
107
- onError: includeErrors && finish,
108
- onScriptlet: finish,
109
- onPlaceholder: finish,
110
- onOpenTagName(ev) {
111
- if (parentTag) {
112
- ev.parent = parentTag;
113
- }
114
- if (!ev.concise) {
115
- ev.pos += 1;
116
- }
117
- ev.endPos = ev.pos + ev.tagName.length;
118
- parentTag = ev;
119
- finish(ev);
164
+ onText(range) {
165
+ curBody.push({
166
+ type: 15 /* Text */,
167
+ parent: curParent,
168
+ start: range.start,
169
+ end: range.end
170
+ });
120
171
  },
121
- onOpenTag(ev) {
122
- ev.parent = parentTag.parent;
123
- parentTag = ev;
124
- if (ev.tagName === "style") {
125
- const firstAttr = ev.attributes[0];
126
- const isBlock = firstAttr && firstAttr.name.startsWith("{");
127
- if (isBlock) {
128
- const content = firstAttr.name.slice(1, -1);
129
- const pos = text.indexOf(content, ev.tagNameEndPos);
130
- const endPos = pos + content.length;
131
- const requestedLanguage = ev.shorthandClassNames && ev.shorthandClassNames[0].rawParts[0] && ev.shorthandClassNames[0].rawParts[0].text;
132
- const language = requestedLanguage && SUPPORTED_STYLE_LANGS[requestedLanguage] ? requestedLanguage : "css";
133
- finish({
134
- type: "styleContent",
135
- language,
136
- block: true,
137
- content: text.slice(pos, endPos),
138
- pos,
139
- endPos
140
- });
141
- return;
142
- }
172
+ onCDATA(range) {
173
+ curBody.push({
174
+ type: 16 /* CDATA */,
175
+ parent: curParent,
176
+ value: range.value,
177
+ start: range.start,
178
+ end: range.end
179
+ });
180
+ },
181
+ onDoctype(range) {
182
+ curBody.push({
183
+ type: 17 /* Doctype */,
184
+ parent: curParent,
185
+ value: range.value,
186
+ start: range.start,
187
+ end: range.end
188
+ });
189
+ },
190
+ onDeclaration(range) {
191
+ curBody.push({
192
+ type: 18 /* Declaration */,
193
+ parent: curParent,
194
+ value: range.value,
195
+ start: range.start,
196
+ end: range.end
197
+ });
198
+ },
199
+ onComment(range) {
200
+ curBody.push({
201
+ type: 19 /* Comment */,
202
+ parent: curParent,
203
+ value: range.value,
204
+ start: range.start,
205
+ end: range.end
206
+ });
207
+ },
208
+ onPlaceholder(range) {
209
+ curBody.push({
210
+ type: 21 /* Placeholder */,
211
+ parent: curParent,
212
+ value: range.value,
213
+ escape: range.escape,
214
+ start: range.start,
215
+ end: range.end
216
+ });
217
+ },
218
+ onScriptlet(range) {
219
+ curBody.push({
220
+ type: 22 /* Scriptlet */,
221
+ parent: curParent,
222
+ value: range.value,
223
+ block: range.block,
224
+ start: range.start,
225
+ end: range.end
226
+ });
227
+ },
228
+ onOpenTagStart(range) {
229
+ curOpenTagStart = range;
230
+ },
231
+ onOpenTagName(range) {
232
+ let concise = true;
233
+ let start = range.start;
234
+ let type = 1 /* Tag */;
235
+ let nameText = void 0;
236
+ if (curOpenTagStart) {
237
+ concise = false;
238
+ start = curOpenTagStart.start;
239
+ curOpenTagStart = void 0;
143
240
  }
144
- let attrEndPos = ev.tagNameEndPos;
145
- for (const attr of ev.attributes) {
146
- if (!attr.name) {
147
- if (attr.value !== void 0) {
148
- attrEndPos += attr.value.length;
149
- }
150
- continue;
151
- }
152
- if (attr.name.slice(0, 3) === "...") {
153
- attrEndPos = attr.argument ? attr.argument.endPos + 1 : attr.endPos;
154
- continue;
155
- }
156
- const attrStartPos = text.indexOf(attr.name, attrEndPos);
157
- const match = /:(.*)$/.exec(attr.name);
158
- const modifier = match && match[1];
159
- let name = attr.name;
160
- if (modifier) {
161
- name = name.slice(0, name.length - modifier.length - 1);
162
- const modifierStartPos = attrStartPos + name.length;
163
- const modifierEndPos = modifierStartPos + modifier.length + 1;
164
- if (finish({
165
- type: "attributeModifier",
166
- tag: ev,
167
- name,
168
- modifier,
169
- pos: modifierStartPos,
170
- endPos: modifierEndPos
171
- })) {
172
- return;
173
- }
174
- }
175
- const attrNameEndPos = attrStartPos + name.length;
176
- if (finish({
177
- type: "attributeName",
178
- tag: ev,
179
- name,
180
- pos: attrStartPos,
181
- endPos: attrNameEndPos
182
- })) {
183
- return;
184
- }
185
- if (attr.value) {
186
- attrEndPos = attr.endPos;
187
- const valueStartPos = attr.pos + 1;
188
- if (finish({
189
- type: "attributeValue",
190
- tag: ev,
191
- name,
192
- value: text.slice(valueStartPos, attrEndPos),
193
- pos: valueStartPos,
194
- endPos: attr.endPos
195
- })) {
241
+ if (range.expressions.length) {
242
+ curBodyType = TagType.html;
243
+ } else {
244
+ switch (nameText = parser.read(range)) {
245
+ case "area":
246
+ case "base":
247
+ case "br":
248
+ case "col":
249
+ case "embed":
250
+ case "hr":
251
+ case "img":
252
+ case "input":
253
+ case "link":
254
+ case "meta":
255
+ case "param":
256
+ case "source":
257
+ case "track":
258
+ case "wbr":
259
+ curBodyType = TagType.void;
196
260
  break;
261
+ case "html-comment":
262
+ case "script":
263
+ case "style":
264
+ case "textarea":
265
+ curBodyType = TagType.text;
266
+ break;
267
+ case "class":
268
+ case "export":
269
+ case "import":
270
+ case "static": {
271
+ let i = program.body.length;
272
+ for (; i--; ) {
273
+ const prev = program.body[i];
274
+ if (prev.type === 19 /* Comment */) {
275
+ program.static.push(prev);
276
+ } else {
277
+ break;
278
+ }
279
+ }
280
+ program.body.length = i + 1;
281
+ program.static.push(curParent = {
282
+ type: 20 /* Statement */,
283
+ parent: program,
284
+ start: range.start,
285
+ end: UNFINISHED
286
+ });
287
+ return curBodyType = TagType.statement;
197
288
  }
198
- } else {
199
- attrEndPos = attr.argument ? attr.argument.endPos + 1 : attr.endPos;
289
+ default:
290
+ if (nameText[0] === "@") {
291
+ type = 14 /* AttrTag */;
292
+ }
293
+ curBodyType = TagType.html;
294
+ break;
200
295
  }
201
296
  }
202
- finish(ev);
297
+ const parent = curParent;
298
+ const end = UNFINISHED;
299
+ const name = {
300
+ type: 2 /* OpenTagName */,
301
+ parent: void 0,
302
+ quasis: range.quasis,
303
+ expressions: range.expressions,
304
+ start: range.start,
305
+ end: range.end
306
+ };
307
+ const tag = curParent = name.parent = {
308
+ type,
309
+ parent,
310
+ owner: void 0,
311
+ concise,
312
+ open: { start, end },
313
+ nameText,
314
+ name,
315
+ var: void 0,
316
+ args: void 0,
317
+ params: void 0,
318
+ shorthandId: void 0,
319
+ shorthandClassNames: void 0,
320
+ attrs: void 0,
321
+ selfClosed: false,
322
+ bodyType: curBodyType,
323
+ body: void 0,
324
+ close: void 0,
325
+ start,
326
+ end
327
+ };
328
+ if (tag.type === 14 /* AttrTag */) {
329
+ let owner = parent;
330
+ outer:
331
+ do {
332
+ switch (owner.type) {
333
+ case 14 /* AttrTag */:
334
+ break;
335
+ case 1 /* Tag */:
336
+ if (isTransparentTag(owner)) {
337
+ owner = owner.parent;
338
+ continue outer;
339
+ }
340
+ break;
341
+ default:
342
+ break outer;
343
+ }
344
+ tag.owner = owner;
345
+ tag.nameText = resolveAttrTagName(tag);
346
+ pushAttr(owner, tag);
347
+ } while (false);
348
+ }
349
+ curBody.push(tag);
350
+ curOpenTagStart = void 0;
351
+ return curBodyType;
203
352
  },
204
- onText(ev) {
205
- ev.endPos = parser.pos;
206
- ev.pos = ev.endPos - ev.value.length;
207
- if (parentTag) {
208
- ev.parent = parentTag;
209
- if (parentTag.tagName === "style") {
210
- finish({
211
- type: "styleContent",
212
- language: "css",
213
- block: false,
214
- content: ev.value,
215
- pos: ev.pos,
216
- endPos: ev.endPos
217
- });
218
- return;
353
+ onTagShorthandId(range) {
354
+ curParent.shorthandId = {
355
+ type: 3 /* ShorthandId */,
356
+ parent: curParent,
357
+ quasis: range.quasis,
358
+ expressions: range.expressions,
359
+ start: range.start,
360
+ end: range.end
361
+ };
362
+ },
363
+ onTagShorthandClass(range) {
364
+ const shorthandClassName = {
365
+ type: 4 /* ShorthandClassName */,
366
+ parent: curParent,
367
+ quasis: range.quasis,
368
+ expressions: range.expressions,
369
+ start: range.start,
370
+ end: range.end
371
+ };
372
+ if (curParent.shorthandClassNames) {
373
+ curParent.shorthandClassNames.push(shorthandClassName);
374
+ } else {
375
+ curParent.shorthandClassNames = [shorthandClassName];
376
+ }
377
+ },
378
+ onTagVar(range) {
379
+ curParent.var = {
380
+ type: 5 /* TagVar */,
381
+ parent: curParent,
382
+ value: range.value,
383
+ start: range.start,
384
+ end: range.end
385
+ };
386
+ },
387
+ onTagParams(range) {
388
+ curParent.params = {
389
+ type: 7 /* TagParams */,
390
+ parent: curParent,
391
+ value: range.value,
392
+ start: range.start,
393
+ end: range.end
394
+ };
395
+ },
396
+ onTagArgs(range) {
397
+ curParent.args = {
398
+ type: 6 /* TagArgs */,
399
+ parent: curParent,
400
+ value: range.value,
401
+ start: range.start,
402
+ end: range.end
403
+ };
404
+ },
405
+ onAttrName(range) {
406
+ const parent = curParent;
407
+ const name = {
408
+ type: 9 /* AttrName */,
409
+ parent: void 0,
410
+ start: range.start,
411
+ end: range.end
412
+ };
413
+ pushAttr(parent, curAttr = name.parent = {
414
+ type: 8 /* AttrNamed */,
415
+ parent,
416
+ name,
417
+ value: void 0,
418
+ args: void 0,
419
+ start: range.start,
420
+ end: range.end
421
+ });
422
+ },
423
+ onAttrArgs(range) {
424
+ curAttr.args = {
425
+ type: 10 /* AttrArgs */,
426
+ parent: curAttr,
427
+ value: range.value,
428
+ start: range.start,
429
+ end: range.end
430
+ };
431
+ },
432
+ onAttrValue(range) {
433
+ curAttr.value = {
434
+ type: 11 /* AttrValue */,
435
+ parent: curAttr,
436
+ value: range.value,
437
+ bound: range.bound,
438
+ start: range.start,
439
+ end: range.end
440
+ };
441
+ curAttr.end = range.end;
442
+ },
443
+ onAttrMethod(range) {
444
+ curAttr.value = {
445
+ type: 12 /* AttrMethod */,
446
+ parent: curAttr,
447
+ params: range.params,
448
+ body: range.body,
449
+ start: range.start,
450
+ end: range.end
451
+ };
452
+ curAttr.end = range.end;
453
+ },
454
+ onAttrSpread(range) {
455
+ pushAttr(curParent, {
456
+ type: 13 /* AttrSpread */,
457
+ parent: curParent,
458
+ value: range.value,
459
+ start: range.start,
460
+ end: range.end
461
+ });
462
+ },
463
+ onOpenTagEnd(range) {
464
+ curAttr = void 0;
465
+ if (curBodyType === TagType.statement) {
466
+ curParent.end = range.end;
467
+ curParent = curParent.parent;
468
+ } else {
469
+ const tag = curParent;
470
+ tag.open.end = range.end;
471
+ if (range.selfClosed || curBodyType === TagType.void) {
472
+ curParent = tag.parent;
473
+ tag.selfClosed = range.selfClosed;
474
+ tag.end = range.end;
475
+ } else {
476
+ curBody = tag.body = [];
219
477
  }
220
478
  }
221
- finish(ev);
222
479
  },
223
- onCloseTag(ev) {
224
- parentTag = parentTag && parentTag.parent;
225
- finish(ev);
226
- }
227
- }, {
228
- isOpenTagOnly(ev) {
229
- const tagDef = taglib.getTag(ev);
230
- return tagDef && tagDef.openTagOnly;
480
+ onCloseTagStart(range) {
481
+ curParent.close = {
482
+ start: range.start,
483
+ end: Number.MAX_SAFE_INTEGER
484
+ };
485
+ },
486
+ onCloseTagEnd(range) {
487
+ if (hasCloseTag(curParent))
488
+ curParent.close.end = range.end;
489
+ curParent.end = range.end;
490
+ curBody = (curParent = curParent.parent).body;
231
491
  }
232
492
  });
233
- try {
234
- parser.parse(`${text}
235
- `);
236
- } catch (err) {
237
- return includeErrors ? {
238
- type: "error",
239
- code: "UNEXPECTED_TOKEN",
240
- message: err.message,
241
- pos: parser.pos,
242
- endPos: parser.pos
243
- } : null;
244
- }
245
- return result;
246
- function finish(event) {
247
- const { type, pos, endPos } = event;
248
- if (!result && (type === "error" || pos != null && pos <= offset && endPos != null && endPos >= offset)) {
249
- result = event;
250
- parser.end();
251
- return true;
252
- }
253
- return false;
254
- }
255
- }
256
-
257
- // src/utils/completions/index.ts
258
- var completions_exports = {};
259
- __export(completions_exports, {
260
- attributeModifier: () => attributeModifier,
261
- attributeName: () => attributeName,
262
- closeTag: () => closeTag,
263
- openTag: () => openTag,
264
- openTagName: () => openTagName,
265
- styleContent: () => styleContent
266
- });
267
-
268
- // src/utils/completions/types/attributeModifier.ts
269
- import {
270
- CompletionList,
271
- CompletionItemKind
272
- } from "vscode-languageserver";
273
- function attributeModifier(_taglib, _document, _params, _event) {
274
- return CompletionList.create([
275
- {
276
- label: "scoped",
277
- kind: CompletionItemKind.Keyword,
278
- detail: "Use to prefix with a unique ID"
279
- },
280
- {
281
- label: "no-update",
282
- kind: CompletionItemKind.Keyword,
283
- detail: "Use to skip future updates to this attribute"
493
+ parser.parse(source);
494
+ return {
495
+ read: parser.read,
496
+ locationAt: parser.locationAt,
497
+ positionAt: parser.positionAt,
498
+ nodeAt: (offset) => getNodeAtOffset(offset, program),
499
+ program
500
+ };
501
+ }
502
+ function pushAttr(parent, node) {
503
+ if (parent.attrs) {
504
+ parent.attrs.push(node);
505
+ } else {
506
+ parent.attrs = [node];
507
+ }
508
+ }
509
+ function hasCloseTag(parent) {
510
+ return parent.close !== void 0;
511
+ }
512
+ function resolveAttrTagName(tag) {
513
+ let name = tag.nameText;
514
+ let parentTag = tag.owner;
515
+ do {
516
+ switch (parentTag.type) {
517
+ case 1 /* Tag */:
518
+ return parentTag.nameText ? `${parentTag.nameText}:${name}` : void 0;
519
+ case 14 /* AttrTag */:
520
+ name = `${parentTag.nameText}:${name}`;
521
+ parentTag = parentTag.owner;
522
+ break;
523
+ default:
524
+ return;
284
525
  }
285
- ], true);
526
+ } while (parentTag);
527
+ }
528
+ function isTransparentTag(node) {
529
+ return node.nameText !== void 0 && /^(?:if|else(?:-if)?|for|while)$/.test(node.nameText);
286
530
  }
287
531
 
288
- // src/utils/completions/types/attributeName.ts
289
- import {
290
- CompletionList as CompletionList2,
291
- CompletionItemKind as CompletionItemKind2,
292
- MarkupKind,
293
- InsertTextFormat,
294
- TextEdit as TextEdit2
295
- } from "vscode-languageserver";
296
-
297
- // src/utils/utils.ts
298
- import fs from "fs";
299
- import { URI as URI2 } from "vscode-uri";
300
- import {
301
- TextEdit,
302
- Position,
303
- Range
304
- } from "vscode-languageserver";
305
- import { TextDocument } from "vscode-languageserver-textdocument";
306
- var START_OF_FILE = Range.create(Position.create(0, 0), Position.create(0, 0));
307
- function findNonControlFlowParent(tag) {
308
- let parent = tag.parent;
309
- while (parent) {
310
- if (!/^(?:else-)?if|else|for|while$/.test(parent.tagName)) {
311
- return parent;
312
- }
313
- parent = parent.parent;
532
+ // src/utils/compiler.ts
533
+ var lookupKey = Symbol("lookup");
534
+ var compilerInfoByDir = /* @__PURE__ */ new Map();
535
+ var builtinInfo = {
536
+ cache: /* @__PURE__ */ new Map(),
537
+ lookup: builtinCompiler.taglib.buildLookup(__dirname, builtinTranslator),
538
+ compiler: builtinCompiler,
539
+ translator: builtinTranslator
540
+ };
541
+ builtinCompiler.configure({ translator: builtinTranslator });
542
+ function parse2(doc) {
543
+ const compilerInfo = getCompilerInfo(doc);
544
+ let parsed = compilerInfo.cache.get(doc);
545
+ if (!parsed) {
546
+ const source = doc.getText();
547
+ compilerInfo.cache.set(doc, parsed = parse(source));
314
548
  }
315
- return null;
316
- }
317
- function rangeFromEvent(document, event) {
318
- return Range.create(document.positionAt(event.pos), document.positionAt(event.endPos));
549
+ return parsed;
319
550
  }
320
- function createTextDocument(filename) {
321
- const uri = URI2.file(filename).toString();
322
- const content = fs.readFileSync(filename, "utf-8");
323
- return TextDocument.create(uri, "plaintext", 0, content);
551
+ function getCompilerInfo(doc) {
552
+ const dir = getDocDir(doc);
553
+ if (!dir)
554
+ return builtinInfo;
555
+ let info = compilerInfoByDir.get(dir);
556
+ if (!info) {
557
+ info = loadCompilerInfo(dir);
558
+ compilerInfoByDir.set(dir, info);
559
+ }
560
+ return info;
324
561
  }
325
- function shiftCompletionRanges(list, offset) {
326
- list.items.forEach((item) => {
327
- if (item.additionalTextEdits) {
328
- item.additionalTextEdits.forEach((edit) => shiftRange(edit.range, offset));
562
+ function setup(connection3, documents2) {
563
+ connection3.onDidChangeWatchedFiles(() => {
564
+ clearAllCaches();
565
+ });
566
+ documents2.onDidChangeContent(({ document }) => {
567
+ if (document.version > 1) {
568
+ if (document.languageId === "marko") {
569
+ getCompilerInfo(document).cache.delete(document);
570
+ } else if (/[./\\]marko(?:-tag)?\.json$/.test(document.uri)) {
571
+ clearAllCaches();
572
+ }
329
573
  }
330
- if (item.textEdit) {
331
- shiftEdit(item.textEdit, offset);
574
+ });
575
+ documents2.onDidClose(({ document }) => {
576
+ if (document.languageId === "marko" && URI2.parse(document.uri).scheme !== "file") {
577
+ getCompilerInfo(document).cache.delete(document);
332
578
  }
333
579
  });
334
- return list;
335
580
  }
336
- function shiftEdit(edit, offset) {
337
- if (TextEdit.is(edit)) {
338
- shiftRange(edit.range, offset);
339
- } else {
340
- shiftRange(edit.insert, offset);
341
- shiftRange(edit.replace, offset);
581
+ function clearAllCaches() {
582
+ for (const [, info] of compilerInfoByDir) {
583
+ info.cache.clear();
584
+ info.compiler.taglib.clearCaches();
342
585
  }
343
586
  }
344
- function shiftRange(range, offset) {
345
- if (range) {
346
- shiftPosition(range.start, offset);
347
- shiftPosition(range.end, offset);
587
+ function loadCompilerInfo(dir) {
588
+ const rootDir = lassoPackageRoot.getRootDir(dir);
589
+ const pkgPath = rootDir && resolveFrom.silent(rootDir, "@marko/compiler/package.json");
590
+ const pkg = pkgPath && __require(pkgPath);
591
+ const cache2 = /* @__PURE__ */ new Map();
592
+ let translator = builtinTranslator;
593
+ let compiler = builtinCompiler;
594
+ if (pkg && /^5\./.test(pkg.version)) {
595
+ try {
596
+ let checkTranslator = [].concat(Object.keys(pkg.dependencies), Object.keys(pkg.peerDependencies), Object.keys(pkg.devDependencies)).find((name) => /^marko$|^(@\/marko\/|marko-)translator-/.test(name));
597
+ if (checkTranslator === "marko" || !checkTranslator) {
598
+ checkTranslator = __require(resolveFrom(dir, "@marko/compiler/config")).translator;
599
+ }
600
+ [compiler, translator] = [
601
+ __require(resolveFrom(dir, "@marko/compiler")),
602
+ __require(resolveFrom(dir, checkTranslator))
603
+ ];
604
+ } catch {
605
+ }
348
606
  }
607
+ return {
608
+ cache: cache2,
609
+ get lookup() {
610
+ let lookup = cache2.get(lookupKey);
611
+ if (lookup === void 0) {
612
+ try {
613
+ lookup = compiler.taglib.buildLookup(dir, translator);
614
+ } catch {
615
+ lookup = builtinInfo.lookup;
616
+ }
617
+ cache2.set(lookupKey, lookup);
618
+ }
619
+ return lookup;
620
+ },
621
+ compiler,
622
+ translator
623
+ };
349
624
  }
350
- function shiftPosition(pos, offset) {
351
- if (pos.line === 0) {
352
- pos.character += offset.character;
625
+
626
+ // src/utils/messages.ts
627
+ import { inspect } from "util";
628
+ var connection;
629
+ function setup2(_) {
630
+ connection = _;
631
+ }
632
+ function displayError(data) {
633
+ display("showError", data);
634
+ }
635
+ function display(type, data) {
636
+ const msg = typeof data === "string" ? data : inspect(data, { colors: false });
637
+ setImmediate(() => connection.sendNotification(type, msg));
638
+ }
639
+
640
+ // src/service/index.ts
641
+ import {
642
+ CompletionList as CompletionList3
643
+ } from "vscode-languageserver";
644
+
645
+ // src/service/marko/complete/index.ts
646
+ import {
647
+ CompletionList
648
+ } from "vscode-languageserver";
649
+
650
+ // src/service/marko/complete/Tag.ts
651
+ import {
652
+ CompletionItemKind,
653
+ InsertTextFormat,
654
+ TextEdit
655
+ } from "vscode-languageserver";
656
+ var partialCloseTagReg = /<\/(?:[^><]*>)?/iy;
657
+ function Tag(event) {
658
+ const { node } = event;
659
+ const isClosed = node.end !== UNFINISHED;
660
+ if (isClosed || node.concise)
661
+ return;
662
+ const { offset, parsed, code } = event;
663
+ const closingTagStr = `</${node.nameText}>`;
664
+ if (offset === node.open.end) {
665
+ return [
666
+ {
667
+ label: closingTagStr,
668
+ kind: CompletionItemKind.Class,
669
+ insertTextFormat: InsertTextFormat.Snippet,
670
+ insertText: `
671
+ $0
672
+ ${closingTagStr}`
673
+ }
674
+ ];
675
+ } else if (node.close && offset >= node.close.start) {
676
+ const start = node.close.start;
677
+ partialCloseTagReg.lastIndex = start;
678
+ const [{ length }] = partialCloseTagReg.exec(code);
679
+ const end = start + length;
680
+ return [
681
+ {
682
+ label: closingTagStr,
683
+ kind: CompletionItemKind.Class,
684
+ insertTextFormat: InsertTextFormat.Snippet,
685
+ textEdit: TextEdit.replace(parsed.locationAt({
686
+ start,
687
+ end
688
+ }), closingTagStr)
689
+ }
690
+ ];
353
691
  }
354
- pos.line += offset.line;
355
- return pos;
356
692
  }
357
693
 
358
- // src/utils/completions/types/attributeName.ts
359
- function attributeName(taglib, document, _params, event) {
694
+ // src/service/marko/complete/OpenTagName.ts
695
+ import path2 from "path";
696
+ import { URI as URI3 } from "vscode-uri";
697
+ import {
698
+ CompletionItemKind as CompletionItemKind2,
699
+ InsertTextFormat as InsertTextFormat2,
700
+ MarkupKind,
701
+ TextEdit as TextEdit2
702
+ } from "vscode-languageserver";
703
+ function OpenTagName({
704
+ document,
705
+ lookup,
706
+ parsed,
707
+ node
708
+ }) {
709
+ const currentTemplateFilePath = getDocFile(document);
710
+ const tag = node.parent;
711
+ const tagNameLocation = parsed.locationAt(node);
712
+ let tags;
713
+ if (tag.type === 14 /* AttrTag */) {
714
+ let parentTag = tag.owner;
715
+ while ((parentTag == null ? void 0 : parentTag.type) === 14 /* AttrTag */)
716
+ parentTag = parentTag.owner;
717
+ const parentTagDef = parentTag && parentTag.nameText && lookup.getTag(parentTag.nameText);
718
+ tags = parentTagDef && parentTagDef.nestedTags && Object.values(parentTagDef.nestedTags) || [];
719
+ } else {
720
+ tags = lookup.getTagsSorted().filter((it) => !it.isNestedTag);
721
+ }
722
+ return tags.filter((it) => !it.deprecated).filter((it) => it.name !== "*").filter((it) => /^[^_]/.test(it.name) || !/\/node_modules\//.test(it.filePath)).map((it) => {
723
+ let label = it.isNestedTag ? `@${it.name}` : it.name;
724
+ const fileForTag = it.template || it.renderer || it.filePath;
725
+ const fileURIForTag = URI3.file(fileForTag).toString();
726
+ const nodeModuleMatch = /\/node_modules\/((?:@[^/]+\/)?[^/]+)/.exec(fileForTag);
727
+ const nodeModuleName = nodeModuleMatch && nodeModuleMatch[1];
728
+ const isCoreTag = nodeModuleName === "marko";
729
+ const documentation = {
730
+ kind: MarkupKind.Markdown,
731
+ 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:
732
+
733
+ [${currentTemplateFilePath ? path2.relative(currentTemplateFilePath, fileForTag) : currentTemplateFilePath}](${fileURIForTag})`
734
+ };
735
+ if (it.description) {
736
+ documentation.value += `
737
+
738
+ ${it.description}`;
739
+ }
740
+ const autocomplete = it.autocomplete && it.autocomplete[0];
741
+ if (autocomplete) {
742
+ if (autocomplete.displayText) {
743
+ label = autocomplete.displayText;
744
+ }
745
+ if (autocomplete.description) {
746
+ documentation.value += `
747
+
748
+ ${autocomplete.description}`;
749
+ }
750
+ if (autocomplete.descriptionMoreURL) {
751
+ documentation.value += `
752
+
753
+ [More Info](${autocomplete.descriptionMoreURL})`;
754
+ }
755
+ }
756
+ return {
757
+ label,
758
+ documentation,
759
+ kind: CompletionItemKind2.Class,
760
+ insertTextFormat: InsertTextFormat2.Snippet,
761
+ textEdit: TextEdit2.replace(tagNameLocation, autocomplete && autocomplete.snippet || label)
762
+ };
763
+ });
764
+ }
765
+
766
+ // src/service/marko/complete/AttrName.ts
767
+ import {
768
+ CompletionItemKind as CompletionItemKind3,
769
+ MarkupKind as MarkupKind2,
770
+ InsertTextFormat as InsertTextFormat3,
771
+ TextEdit as TextEdit3
772
+ } from "vscode-languageserver";
773
+ function AttrName({
774
+ offset,
775
+ node,
776
+ parsed,
777
+ lookup
778
+ }) {
779
+ let name = parsed.read(node);
780
+ if (name[0] === "{")
781
+ return;
782
+ const modifierIndex = name.indexOf(":");
783
+ const hasModifier = modifierIndex !== -1;
784
+ if (hasModifier) {
785
+ if (offset >= node.start + modifierIndex) {
786
+ return [
787
+ {
788
+ label: "scoped",
789
+ kind: CompletionItemKind3.Keyword,
790
+ detail: "Use to prefix with a unique ID"
791
+ },
792
+ {
793
+ label: "no-update",
794
+ kind: CompletionItemKind3.Keyword,
795
+ detail: "Use to skip future updates to this attribute"
796
+ }
797
+ ];
798
+ } else {
799
+ name = name.slice(0, modifierIndex);
800
+ }
801
+ }
360
802
  const completions = [];
361
- const attrNameRange = rangeFromEvent(document, event);
362
- const tagDef = !event.tag.tagNameExpression && taglib.getTag(event.tag.tagName);
363
- const tagName = tagDef && tagDef.name || "*";
803
+ const attrNameLoc = parsed.locationAt(hasModifier ? {
804
+ start: node.start,
805
+ end: node.start + name.length
806
+ } : node);
807
+ const tagName = node.parent.parent.nameText || "";
808
+ const tagDef = tagName && lookup.getTag(tagName);
364
809
  const nestedTagAttrs = {};
365
810
  const neverAttrs = /* @__PURE__ */ new Set();
366
811
  if (tagDef && tagDef.nestedTags) {
@@ -369,18 +814,18 @@ function attributeName(taglib, document, _params, event) {
369
814
  nestedTagAttrs[nestedTagDef.targetProperty] = true;
370
815
  }
371
816
  }
372
- taglib.forEachAttribute(tagName, (attr) => {
817
+ lookup.forEachAttribute(tagName, (attr) => {
373
818
  if (attr.type === "never") {
374
819
  neverAttrs.add(attr.name);
375
820
  }
376
821
  });
377
- taglib.forEachAttribute(tagName, (attr, parent) => {
822
+ lookup.forEachAttribute(tagName, (attr, parent) => {
378
823
  if (attr.deprecated || nestedTagAttrs[attr.name] || attr.name === "*" || neverAttrs.has(attr.name) || attr.name[0] === "_" && /\/node_modules\//.test(attr.filePath || parent.filePath)) {
379
824
  return;
380
825
  }
381
826
  const type = attr.type || (attr.html ? "string" : null);
382
827
  const documentation = {
383
- kind: MarkupKind.Markdown,
828
+ kind: MarkupKind2.Markdown,
384
829
  value: attr.description || ""
385
830
  };
386
831
  let label = attr.name;
@@ -420,162 +865,66 @@ function attributeName(taglib, document, _params, event) {
420
865
  completions.push({
421
866
  label,
422
867
  documentation: documentation.value ? documentation : void 0,
423
- kind: CompletionItemKind2.Property,
424
- insertTextFormat: InsertTextFormat.Snippet,
425
- textEdit: TextEdit2.replace(attrNameRange, snippet)
868
+ kind: CompletionItemKind3.Property,
869
+ insertTextFormat: InsertTextFormat3.Snippet,
870
+ textEdit: TextEdit3.replace(attrNameLoc, snippet)
426
871
  });
427
872
  });
428
- return CompletionList2.create(completions, true);
873
+ return completions;
429
874
  }
430
875
 
431
- // src/utils/completions/types/closeTag.ts
432
- import {
433
- CompletionList as CompletionList3,
434
- CompletionItemKind as CompletionItemKind3,
435
- InsertTextFormat as InsertTextFormat2,
436
- TextEdit as TextEdit3
437
- } from "vscode-languageserver";
438
- function closeTag(_taglib, document, _params, event) {
439
- if (event.tagName[0] === "$") {
440
- return;
441
- }
442
- const closingTagStr = `</${event.tagName}>`;
443
- return CompletionList3.create([
444
- {
445
- label: closingTagStr,
446
- kind: CompletionItemKind3.Class,
447
- insertTextFormat: InsertTextFormat2.Snippet,
448
- textEdit: TextEdit3.replace(rangeFromEvent(document, event), closingTagStr)
449
- }
450
- ], true);
451
- }
876
+ // src/service/marko/complete/index.ts
877
+ var handlers = {
878
+ Tag,
879
+ OpenTagName,
880
+ AttrName
881
+ };
882
+ var doComplete = async (doc, params) => {
883
+ var _a;
884
+ const parsed = parse2(doc);
885
+ const offset = doc.offsetAt(params.position);
886
+ const node = parsed.nodeAt(offset);
887
+ return CompletionList.create(await ((_a = handlers[NodeType[node.type]]) == null ? void 0 : _a.call(handlers, {
888
+ document: doc,
889
+ params,
890
+ parsed,
891
+ offset,
892
+ node,
893
+ code: doc.getText(),
894
+ ...getCompilerInfo(doc)
895
+ })) || [], true);
896
+ };
452
897
 
453
- // src/utils/completions/types/openTag.ts
454
- import {
455
- CompletionList as CompletionList4,
456
- CompletionItemKind as CompletionItemKind4,
457
- InsertTextFormat as InsertTextFormat3
458
- } from "vscode-languageserver";
459
- function openTag(_taglib, _document, params, event) {
460
- const triggerCharacter = params.context && params.context.triggerCharacter;
461
- if (triggerCharacter !== ">" || event.openTagOnly || event.selfClosed) {
462
- return;
463
- }
464
- const closingTagStr = `</${event.tagName[0] === "$" ? "" : event.tagName}>`;
465
- return CompletionList4.create([
466
- {
467
- label: closingTagStr,
468
- kind: CompletionItemKind4.Class,
469
- insertTextFormat: InsertTextFormat3.Snippet,
470
- insertText: `
471
- $0
472
- ${closingTagStr}`
898
+ // src/service/marko/validate.ts
899
+ import { Diagnostic, DiagnosticSeverity, Range as Range2 } from "vscode-languageserver";
900
+ var markoErrorRegExp = /^(.+?)(?:\((\d+)(?:\s*,\s*(\d+))?\))?: (.*)$/gm;
901
+ var doValidate = (doc) => {
902
+ const fsPath = getDocFile(doc);
903
+ const diagnostics = [];
904
+ const { compiler, translator, cache: cache2 } = getCompilerInfo(doc);
905
+ try {
906
+ compiler.compileSync(doc.getText(), fsPath || "untitled.marko", {
907
+ cache: cache2,
908
+ output: "source",
909
+ code: false,
910
+ translator
911
+ });
912
+ } catch (e) {
913
+ let match;
914
+ while (match = markoErrorRegExp.exec(e.message)) {
915
+ const [, fileName, rawLine, rawCol, msg] = match;
916
+ const line = (parseInt(rawLine, 10) || 1) - 1;
917
+ const col = (parseInt(rawCol, 10) || 1) - 1;
918
+ diagnostics.push(Diagnostic.create(Range2.create(line, col, line, col), msg, DiagnosticSeverity.Error, void 0, fileName));
473
919
  }
474
- ], true);
475
- }
476
-
477
- // src/utils/completions/types/openTagName.ts
478
- import path2 from "path";
479
- import { URI as URI3 } from "vscode-uri";
480
- import {
481
- CompletionItemKind as CompletionItemKind5,
482
- CompletionList as CompletionList5,
483
- InsertTextFormat as InsertTextFormat4,
484
- MarkupKind as MarkupKind2,
485
- TextEdit as TextEdit4
486
- } from "vscode-languageserver";
487
- function openTagName(taglib, document, params, event) {
488
- const { fsPath: currentTemplateFilePath } = URI3.parse(document.uri);
489
- let tags;
490
- const triggerCharacter = params.context && params.context.triggerCharacter || event.tagName[0];
491
- const isAttributeTag = triggerCharacter === "@";
492
- const tagNameRange = rangeFromEvent(document, event);
493
- if (isAttributeTag) {
494
- const parentTag = findNonControlFlowParent(event);
495
- const parentTagDef = parentTag && !parentTag.tagNameExpression && taglib.getTag(parentTag.tagName);
496
- tags = parentTagDef && parentTagDef.nestedTags && Object.values(parentTagDef.nestedTags) || [];
497
- } else {
498
- tags = taglib.getTagsSorted().filter((it) => !it.isNestedTag);
499
920
  }
500
- return CompletionList5.create(tags.filter((it) => !it.deprecated).filter((it) => it.name !== "*").filter((it) => /^[^_]/.test(it.name) || !/\/node_modules\//.test(it.filePath)).map((it) => {
501
- let label = it.isNestedTag ? `@${it.name}` : it.name;
502
- const fileForTag = it.template || it.renderer || it.filePath;
503
- const fileURIForTag = URI3.file(fileForTag).toString();
504
- const nodeModuleMatch = /\/node_modules\/((?:@[^/]+\/)?[^/]+)/.exec(fileForTag);
505
- const nodeModuleName = nodeModuleMatch && nodeModuleMatch[1];
506
- const isCoreTag = nodeModuleName === "marko";
507
- const documentation = {
508
- kind: MarkupKind2.Markdown,
509
- 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:
510
-
511
- [${path2.relative(currentTemplateFilePath, fileForTag)}](${fileURIForTag})`
512
- };
513
- if (it.description) {
514
- documentation.value += `
515
-
516
- ${it.description}`;
517
- }
518
- const autocomplete = it.autocomplete && it.autocomplete[0];
519
- if (autocomplete) {
520
- if (autocomplete.displayText) {
521
- label = autocomplete.displayText;
522
- }
523
- if (autocomplete.description) {
524
- documentation.value += `
525
-
526
- ${autocomplete.description}`;
527
- }
528
- if (autocomplete.descriptionMoreURL) {
529
- documentation.value += `
530
-
531
- [More Info](${autocomplete.descriptionMoreURL})`;
532
- }
533
- }
534
- return {
535
- label,
536
- documentation,
537
- kind: CompletionItemKind5.Class,
538
- insertTextFormat: InsertTextFormat4.Snippet,
539
- textEdit: TextEdit4.replace(tagNameRange, autocomplete && autocomplete.snippet || label)
540
- };
541
- }), true);
542
- }
543
-
544
- // src/utils/completions/types/styleContent.ts
545
- import { Position as Position2 } from "vscode-languageserver";
546
- import { TextDocument as TextDocument2 } from "vscode-languageserver-textdocument";
547
- import {
548
- getCSSLanguageService,
549
- getSCSSLanguageService,
550
- getLESSLanguageService
551
- } from "vscode-css-languageservice";
552
- var services = {
553
- css: getCSSLanguageService,
554
- scss: getSCSSLanguageService,
555
- less: getLESSLanguageService
921
+ return diagnostics;
556
922
  };
557
- function styleContent(_taglib, document, params, event) {
558
- const service = services[event.language]();
559
- const startPos = document.positionAt(event.pos);
560
- const relativePos = shiftPosition(params.position, Position2.create(startPos.line * -1, startPos.character * -1));
561
- const contentDocument = TextDocument2.create(document.uri, event.language, document.version, event.content);
562
- const completions = service.doComplete(contentDocument, relativePos, service.parseStylesheet(contentDocument));
563
- return shiftCompletionRanges(completions, startPos);
564
- }
565
-
566
- // src/utils/definitions/index.ts
567
- var definitions_exports = {};
568
- __export(definitions_exports, {
569
- attributeName: () => attributeName2,
570
- openTagName: () => openTagName2
571
- });
572
923
 
573
- // src/utils/definitions/types/attributeName.ts
574
- import { URI as URI4 } from "vscode-uri";
575
- import {
576
- Range as Range2,
577
- LocationLink
578
- } from "vscode-languageserver";
924
+ // src/service/marko/definition/OpenTagName.ts
925
+ import path3 from "path";
926
+ import { URI as URI5 } from "vscode-uri";
927
+ import { Range as Range4, LocationLink } from "vscode-languageserver";
579
928
 
580
929
  // src/utils/regexp-builder.ts
581
930
  function RegExpBuilder(strings, ...expressions) {
@@ -601,11 +950,68 @@ function escape(val) {
601
950
  return String(val).replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
602
951
  }
603
952
 
604
- // src/utils/definitions/types/attributeName.ts
605
- function attributeName2(taglib, document, _params, event) {
606
- const tagName = event.tag.tagNameExpression ? void 0 : event.tag.tagName;
607
- const tagDef = tagName && taglib.getTag(tagName);
608
- const attrDef = taglib.getAttribute(tagName || "*", event.name);
953
+ // src/utils/utils.ts
954
+ import fs from "fs";
955
+ import { URI as URI4 } from "vscode-uri";
956
+ import { Position, Range as Range3 } from "vscode-languageserver";
957
+ import { TextDocument } from "vscode-languageserver-textdocument";
958
+ var START_OF_FILE = Range3.create(Position.create(0, 0), Position.create(0, 0));
959
+ function createTextDocument(filename) {
960
+ const uri = URI4.file(filename).toString();
961
+ const content = fs.readFileSync(filename, "utf-8");
962
+ return TextDocument.create(uri, "plaintext", 0, content);
963
+ }
964
+
965
+ // src/service/marko/definition/OpenTagName.ts
966
+ function OpenTagName2({
967
+ lookup,
968
+ parsed,
969
+ node
970
+ }) {
971
+ const tag = node.parent;
972
+ let tagDef;
973
+ let range = START_OF_FILE;
974
+ if (tag.type === 14 /* AttrTag */) {
975
+ let parentTag = tag.owner;
976
+ while ((parentTag == null ? void 0 : parentTag.type) === 14 /* AttrTag */)
977
+ parentTag = parentTag.owner;
978
+ tagDef = parentTag && parentTag.nameText ? lookup.getTag(parentTag.nameText) : void 0;
979
+ } else {
980
+ tagDef = tag.nameText ? lookup.getTag(tag.nameText) : void 0;
981
+ }
982
+ if (!tagDef) {
983
+ return;
984
+ }
985
+ const tagEntryFile = tagDef.template || tagDef.renderer || tagDef.filePath;
986
+ if (!path3.isAbsolute(tagEntryFile)) {
987
+ return;
988
+ }
989
+ if (/\/marko(?:-tag)?\.json$/.test(tagEntryFile)) {
990
+ const tagDefDoc = createTextDocument(tagEntryFile);
991
+ const match = RegExpBuilder`/"(?:<${tag.nameText}>|${tag.nameText})"\s*:\s*[^\r\n,]+/g`.exec(tagDefDoc.getText());
992
+ if (match && match.index) {
993
+ range = Range4.create(tagDefDoc.positionAt(match.index), tagDefDoc.positionAt(match.index + match[0].length));
994
+ }
995
+ }
996
+ return [
997
+ LocationLink.create(URI5.file(tagEntryFile).toString(), range, range, parsed.locationAt(node))
998
+ ];
999
+ }
1000
+
1001
+ // src/service/marko/definition/AttrName.ts
1002
+ import { URI as URI6 } from "vscode-uri";
1003
+ import { Range as Range5, LocationLink as LocationLink2 } from "vscode-languageserver";
1004
+ function AttrName2({
1005
+ lookup,
1006
+ parsed,
1007
+ node
1008
+ }) {
1009
+ const tagName = node.parent.parent.nameText;
1010
+ const attrName = parsed.read(node);
1011
+ if (attrName[0] === "{")
1012
+ return;
1013
+ const tagDef = tagName && lookup.getTag(tagName);
1014
+ const attrDef = lookup.getAttribute(tagName || "", attrName);
609
1015
  let range = START_OF_FILE;
610
1016
  if (!attrDef) {
611
1017
  return;
@@ -616,207 +1022,546 @@ function attributeName2(taglib, document, _params, event) {
616
1022
  }
617
1023
  if (/\/marko(?:-tag)?\.json$/.test(attrEntryFile)) {
618
1024
  const tagDefDoc = createTextDocument(attrEntryFile);
619
- const match = RegExpBuilder`/"@${event.name}"\s*:\s*[^\r\n,]+/g`.exec(tagDefDoc.getText());
1025
+ const match = RegExpBuilder`/"@${attrName}"\s*:\s*[^\r\n,]+/g`.exec(tagDefDoc.getText());
620
1026
  if (match && match.index) {
621
- range = Range2.create(tagDefDoc.positionAt(match.index), tagDefDoc.positionAt(match.index + match[0].length));
1027
+ range = Range5.create(tagDefDoc.positionAt(match.index), tagDefDoc.positionAt(match.index + match[0].length));
622
1028
  }
623
1029
  }
624
1030
  return [
625
- LocationLink.create(URI4.file(attrEntryFile).toString(), range, range, rangeFromEvent(document, event))
1031
+ LocationLink2.create(URI6.file(attrEntryFile).toString(), range, range, parsed.locationAt(node))
626
1032
  ];
627
1033
  }
628
1034
 
629
- // src/utils/definitions/types/openTagName.ts
630
- import { URI as URI5 } from "vscode-uri";
1035
+ // src/service/marko/definition/index.ts
1036
+ var handlers2 = {
1037
+ OpenTagName: OpenTagName2,
1038
+ AttrName: AttrName2
1039
+ };
1040
+ var findDefinition = async (doc, params) => {
1041
+ var _a;
1042
+ const parsed = parse2(doc);
1043
+ const offset = doc.offsetAt(params.position);
1044
+ const node = parsed.nodeAt(offset);
1045
+ return await ((_a = handlers2[NodeType[node.type]]) == null ? void 0 : _a.call(handlers2, {
1046
+ document: doc,
1047
+ params,
1048
+ parsed,
1049
+ offset,
1050
+ node,
1051
+ code: doc.getText(),
1052
+ ...getCompilerInfo(doc)
1053
+ })) || [];
1054
+ };
1055
+
1056
+ // src/service/marko/format.ts
1057
+ import { Position as Position2, Range as Range6, TextEdit as TextEdit4 } from "vscode-languageserver";
1058
+ import { URI as URI7 } from "vscode-uri";
1059
+ import * as prettier from "prettier";
1060
+ import * as markoPrettier from "prettier-plugin-marko";
1061
+ var NO_EDIT = [
1062
+ TextEdit4.replace(Range6.create(Position2.create(0, 0), Position2.create(0, 0)), "")
1063
+ ];
1064
+ var format2 = async (doc, params, token) => {
1065
+ try {
1066
+ const { fsPath, scheme } = URI7.parse(doc.uri);
1067
+ const text = doc.getText();
1068
+ const options = {
1069
+ parser: "marko",
1070
+ filepath: fsPath,
1071
+ plugins: [markoPrettier],
1072
+ tabWidth: params.options.tabSize,
1073
+ useTabs: params.options.insertSpaces === false,
1074
+ ...scheme === "file" ? await prettier.resolveConfig(fsPath, {
1075
+ editorconfig: true
1076
+ }).catch(() => null) : null
1077
+ };
1078
+ if (!token.isCancellationRequested) {
1079
+ return [
1080
+ TextEdit4.replace(Range6.create(doc.positionAt(0), doc.positionAt(text.length)), prettier.format(text, options))
1081
+ ];
1082
+ }
1083
+ } catch (e) {
1084
+ displayError(e);
1085
+ }
1086
+ return NO_EDIT;
1087
+ };
1088
+
1089
+ // src/service/marko/index.ts
1090
+ var marko_default = {
1091
+ doComplete,
1092
+ doValidate,
1093
+ findDefinition,
1094
+ format: format2
1095
+ };
1096
+
1097
+ // src/service/stylesheet/index.ts
631
1098
  import {
632
- Range as Range3,
633
- LocationLink as LocationLink2
1099
+ CompletionList as CompletionList2
634
1100
  } from "vscode-languageserver";
635
- function openTagName2(taglib, document, _params, event) {
636
- let tagDef;
637
- let range = START_OF_FILE;
638
- const isAttributeTag = event.tagName[0] === "@";
639
- if (isAttributeTag) {
640
- const parentTag = findNonControlFlowParent(event);
641
- tagDef = parentTag && (parentTag.tagNameExpression ? void 0 : taglib.getTag(parentTag.tagName));
642
- } else {
643
- tagDef = taglib.getTag(event.tagName);
1101
+ import {
1102
+ getCSSLanguageService,
1103
+ getLESSLanguageService,
1104
+ getSCSSLanguageService
1105
+ } from "vscode-css-languageservice";
1106
+ import { TextDocument as TextDocument2 } from "vscode-languageserver-textdocument";
1107
+
1108
+ // src/utils/extractor.ts
1109
+ function createExtractor(code) {
1110
+ let generated = "";
1111
+ const generatedMap = [];
1112
+ return {
1113
+ write(strs, ...exprs) {
1114
+ const len = exprs.length;
1115
+ for (let i = 0; i < len; i++) {
1116
+ const expr = exprs[i];
1117
+ generated += strs[i];
1118
+ if (typeof expr === "string") {
1119
+ generated += expr;
1120
+ } else {
1121
+ generatedMap.push(generated.length, expr.start, expr.end);
1122
+ generated += code.slice(expr.start, expr.end);
1123
+ }
1124
+ }
1125
+ generated += strs[len];
1126
+ },
1127
+ end() {
1128
+ const sourceMap = generatedMap.slice();
1129
+ (function sort(left, right) {
1130
+ if (left < right) {
1131
+ let next = left;
1132
+ for (let i = left; i <= right; i += 3) {
1133
+ if (sourceMap[i] <= sourceMap[right]) {
1134
+ [sourceMap[next - 1], sourceMap[i - 1]] = [
1135
+ sourceMap[i - 1],
1136
+ sourceMap[next - 1]
1137
+ ];
1138
+ [sourceMap[next], sourceMap[i]] = [sourceMap[i], sourceMap[next]];
1139
+ [sourceMap[next + 1], sourceMap[i + 1]] = [
1140
+ sourceMap[i + 1],
1141
+ sourceMap[next + 1]
1142
+ ];
1143
+ next += 3;
1144
+ }
1145
+ }
1146
+ next -= 3;
1147
+ sort(left, next - 3);
1148
+ sort(next + 3, right);
1149
+ }
1150
+ })(1, sourceMap.length - 2);
1151
+ return {
1152
+ generated,
1153
+ sourceOffsetAt(generatedOffset) {
1154
+ let max = generatedMap.length / 3;
1155
+ let min = 0;
1156
+ while (min < max) {
1157
+ const mid = 1 + min + max >>> 1;
1158
+ if (generatedMap[mid * 3] <= generatedOffset) {
1159
+ min = mid;
1160
+ } else {
1161
+ max = mid - 1;
1162
+ }
1163
+ }
1164
+ const key = min * 3;
1165
+ const generatedStart = generatedMap[key];
1166
+ const sourceStart = generatedMap[key + 1];
1167
+ const sourceEnd = generatedMap[key + 2];
1168
+ return sourceEnd - sourceStart <= generatedOffset - generatedStart ? void 0 : sourceStart + (generatedOffset - generatedStart);
1169
+ },
1170
+ generatedOffsetAt(sourceOffset) {
1171
+ let max = sourceMap.length / 3;
1172
+ let min = 0;
1173
+ while (min < max) {
1174
+ const mid = 1 + min + max >>> 1;
1175
+ if (sourceMap[mid * 3 + 1] <= sourceOffset) {
1176
+ min = mid;
1177
+ } else {
1178
+ max = mid - 1;
1179
+ }
1180
+ }
1181
+ const key = min * 3;
1182
+ const sourceStart = sourceMap[key + 1];
1183
+ const sourceEnd = sourceMap[key + 2];
1184
+ if (sourceOffset < sourceStart || sourceOffset > sourceEnd)
1185
+ return void 0;
1186
+ const generatedStart = sourceMap[key];
1187
+ return generatedStart + (sourceOffset - sourceStart);
1188
+ }
1189
+ };
1190
+ }
1191
+ };
1192
+ }
1193
+
1194
+ // src/service/stylesheet/extract.ts
1195
+ function extractStyleSheets(code, program, lookup) {
1196
+ let placeholderId = 0;
1197
+ const extractorsByExt = {};
1198
+ const read = (range) => code.slice(range.start, range.end);
1199
+ const getExtractor = (ext) => extractorsByExt[ext] || (extractorsByExt[ext] = createExtractor(code));
1200
+ const getFileExtFromTag = (tag) => {
1201
+ const prefixEnd = tag.shorthandClassNames ? tag.shorthandClassNames.at(-1).end : tag.name.end;
1202
+ return tag.shorthandClassNames ? read({
1203
+ start: tag.shorthandClassNames[0].start,
1204
+ end: prefixEnd
1205
+ }).replace(/^.*\./, "") : "css";
1206
+ };
1207
+ const visit = (node) => {
1208
+ var _a, _b, _c;
1209
+ switch (node.type) {
1210
+ case 1 /* Tag */:
1211
+ if ((_a = node.body) == null ? void 0 : _a.length) {
1212
+ if (node.nameText === "style") {
1213
+ const ext = getFileExtFromTag(node);
1214
+ for (const child of node.body) {
1215
+ switch (child.type) {
1216
+ case 15 /* Text */:
1217
+ getExtractor(ext).write`${child}`;
1218
+ break;
1219
+ case 21 /* Placeholder */:
1220
+ getExtractor(ext).write`${`var(--_${placeholderId++})`}`;
1221
+ break;
1222
+ }
1223
+ }
1224
+ } else {
1225
+ if (node.attrs) {
1226
+ for (const attr of node.attrs) {
1227
+ if (attr.type === 8 /* AttrNamed */ && ((_b = attr.value) == null ? void 0 : _b.type) === 11 /* AttrValue */ && /^['"]$/.test(code[attr.value.value.start])) {
1228
+ const name = read(attr.name);
1229
+ if (name === "#style" || name === "style" && lookup && node.nameText && name === "style" && ((_c = lookup.getTag(node.nameText)) == null ? void 0 : _c.html)) {
1230
+ getExtractor("css").write`:root{${{
1231
+ start: attr.value.value.start + 1,
1232
+ end: attr.value.value.end - 1
1233
+ }}}`;
1234
+ }
1235
+ }
1236
+ }
1237
+ }
1238
+ for (const child of node.body) {
1239
+ visit(child);
1240
+ }
1241
+ }
1242
+ } else if (node.nameText === "style" && node.concise && node.attrs) {
1243
+ const block = node.attrs.at(-1);
1244
+ if (block.type === 8 /* AttrNamed */ && code[block.start] === "{") {
1245
+ getExtractor(getFileExtFromTag(node)).write`${{
1246
+ start: block.start + 1,
1247
+ end: block.end - 1
1248
+ }}`;
1249
+ }
1250
+ }
1251
+ break;
1252
+ }
1253
+ };
1254
+ for (const node of program.body)
1255
+ visit(node);
1256
+ const resultsByExt = {};
1257
+ for (const ext in extractorsByExt) {
1258
+ resultsByExt[ext] = extractorsByExt[ext].end();
644
1259
  }
645
- if (!tagDef) {
646
- return;
1260
+ return resultsByExt;
1261
+ }
1262
+
1263
+ // src/service/stylesheet/index.ts
1264
+ var cache = /* @__PURE__ */ new WeakMap();
1265
+ var services = {
1266
+ css: getCSSLanguageService,
1267
+ less: getLESSLanguageService,
1268
+ scss: getSCSSLanguageService
1269
+ };
1270
+ var stylesheet_default = {
1271
+ async doComplete(doc, params) {
1272
+ const infoByExt = getStyleSheetInfo(doc);
1273
+ const sourceOffset = doc.offsetAt(params.position);
1274
+ for (const ext in infoByExt) {
1275
+ const info = infoByExt[ext];
1276
+ const generatedOffset = info.generatedOffsetAt(sourceOffset);
1277
+ if (generatedOffset === void 0)
1278
+ continue;
1279
+ const { service: service2, virtualDoc } = info;
1280
+ const result = service2.doComplete(virtualDoc, virtualDoc.positionAt(generatedOffset), info.parsed);
1281
+ for (const item of result.items) {
1282
+ if (item.additionalTextEdits) {
1283
+ for (const edit of item.additionalTextEdits) {
1284
+ if (!updateRange(doc, info, edit.range)) {
1285
+ edit.newText = "";
1286
+ edit.range = START_OF_FILE;
1287
+ }
1288
+ }
1289
+ }
1290
+ const { textEdit } = item;
1291
+ if (textEdit) {
1292
+ if (textEdit.range) {
1293
+ if (!updateRange(doc, info, textEdit.range)) {
1294
+ textEdit.newText = "";
1295
+ textEdit.range = START_OF_FILE;
1296
+ }
1297
+ }
1298
+ if (textEdit.insert) {
1299
+ if (!updateRange(doc, info, textEdit.insert)) {
1300
+ textEdit.newText = "";
1301
+ textEdit.insert = START_OF_FILE;
1302
+ }
1303
+ }
1304
+ }
1305
+ }
1306
+ return result;
1307
+ }
1308
+ return CompletionList2.create([], true);
1309
+ },
1310
+ async findDefinition(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.findDefinition(virtualDoc, virtualDoc.positionAt(generatedOffset), info.parsed);
1320
+ if (result && updateRange(doc, info, result.range)) {
1321
+ return result;
1322
+ }
1323
+ break;
1324
+ }
1325
+ },
1326
+ async doHover(doc, params) {
1327
+ const infoByExt = getStyleSheetInfo(doc);
1328
+ const sourceOffset = doc.offsetAt(params.position);
1329
+ for (const ext in infoByExt) {
1330
+ const info = infoByExt[ext];
1331
+ const generatedOffset = info.generatedOffsetAt(sourceOffset);
1332
+ if (generatedOffset === void 0)
1333
+ continue;
1334
+ const { service: service2, virtualDoc } = info;
1335
+ const result = service2.doHover(virtualDoc, virtualDoc.positionAt(generatedOffset), service2.parseStylesheet(virtualDoc));
1336
+ if (result && (!result.range || updateRange(doc, info, result.range))) {
1337
+ return result;
1338
+ }
1339
+ }
1340
+ },
1341
+ async doValidate(doc) {
1342
+ const infoByExt = getStyleSheetInfo(doc);
1343
+ const result = [];
1344
+ for (const ext in infoByExt) {
1345
+ const info = infoByExt[ext];
1346
+ for (const diag of info.service.doValidation(info.virtualDoc, info.parsed)) {
1347
+ if (updateRange(doc, info, diag.range)) {
1348
+ result.push(diag);
1349
+ }
1350
+ }
1351
+ }
1352
+ return result;
647
1353
  }
648
- const tagEntryFile = tagDef.template || tagDef.renderer || tagDef.filePath;
649
- if (/\/marko(?:-tag)?\.json$/.test(tagEntryFile)) {
650
- const tagDefDoc = createTextDocument(tagEntryFile);
651
- const match = RegExpBuilder`/"<${event.tagName}>"\s*:\s*[^\r\n,]+/g`.exec(tagDefDoc.getText());
652
- if (match && match.index) {
653
- range = Range3.create(tagDefDoc.positionAt(match.index), tagDefDoc.positionAt(match.index + match[0].length));
1354
+ };
1355
+ function updateRange(doc, info, range) {
1356
+ const start = info.sourceOffsetAt(info.virtualDoc.offsetAt(range.start));
1357
+ const end = info.sourceOffsetAt(info.virtualDoc.offsetAt(range.end));
1358
+ if (start !== void 0 || end !== void 0) {
1359
+ range.start = doc.positionAt(start ?? end);
1360
+ range.end = doc.positionAt(end ?? start);
1361
+ return true;
1362
+ }
1363
+ return false;
1364
+ }
1365
+ function getStyleSheetInfo(doc) {
1366
+ var _a;
1367
+ const parsed = parse2(doc);
1368
+ let cached = cache.get(parsed);
1369
+ if (!cached) {
1370
+ const results = extractStyleSheets(doc.getText(), parsed.program, getCompilerInfo(doc).lookup);
1371
+ cached = {};
1372
+ for (const ext in results) {
1373
+ const service2 = (_a = services[ext]) == null ? void 0 : _a.call(services);
1374
+ if (!service2)
1375
+ continue;
1376
+ const { generated, sourceOffsetAt, generatedOffsetAt } = results[ext];
1377
+ const virtualDoc = TextDocument2.create(doc.uri, "css", doc.version, generated);
1378
+ cached[ext] = {
1379
+ service: service2,
1380
+ virtualDoc,
1381
+ sourceOffsetAt,
1382
+ generatedOffsetAt,
1383
+ parsed: service2.parseStylesheet(virtualDoc)
1384
+ };
654
1385
  }
1386
+ cache.set(parsed, cached);
655
1387
  }
656
- return [
657
- LocationLink2.create(URI5.file(tagEntryFile).toString(), range, range, rangeFromEvent(document, event))
658
- ];
1388
+ return cached;
659
1389
  }
660
1390
 
1391
+ // src/service/index.ts
1392
+ var plugins = [marko_default, stylesheet_default];
1393
+ var service = {
1394
+ async doComplete(doc, params, cancel) {
1395
+ const result = CompletionList3.create([], false);
1396
+ try {
1397
+ const requests = plugins.map((plugin) => {
1398
+ var _a;
1399
+ return (_a = plugin.doComplete) == null ? void 0 : _a.call(plugin, doc, params, cancel);
1400
+ });
1401
+ for (const pending of requests) {
1402
+ const cur = await pending;
1403
+ if (cancel.isCancellationRequested)
1404
+ break;
1405
+ if (cur) {
1406
+ let items;
1407
+ if (Array.isArray(cur)) {
1408
+ items = cur;
1409
+ } else {
1410
+ items = cur.items;
1411
+ result.isIncomplete || (result.isIncomplete = cur.isIncomplete);
1412
+ }
1413
+ result.items.push(...items);
1414
+ }
1415
+ }
1416
+ } catch (err) {
1417
+ result.isIncomplete = true;
1418
+ displayError(err);
1419
+ }
1420
+ return result;
1421
+ },
1422
+ async findDefinition(doc, params, cancel) {
1423
+ const result = [];
1424
+ try {
1425
+ const requests = plugins.map((plugin) => {
1426
+ var _a;
1427
+ return (_a = plugin.findDefinition) == null ? void 0 : _a.call(plugin, doc, params, cancel);
1428
+ });
1429
+ for (const pending of requests) {
1430
+ const cur = await pending;
1431
+ if (cancel.isCancellationRequested)
1432
+ break;
1433
+ if (cur) {
1434
+ if (Array.isArray(cur)) {
1435
+ result.push(...cur);
1436
+ } else {
1437
+ result.push(cur);
1438
+ }
1439
+ }
1440
+ }
1441
+ } catch (err) {
1442
+ displayError(err);
1443
+ }
1444
+ return result;
1445
+ },
1446
+ async doHover(doc, params, cancel) {
1447
+ var _a;
1448
+ try {
1449
+ for (const plugin of plugins) {
1450
+ const result = await ((_a = plugin.doHover) == null ? void 0 : _a.call(plugin, doc, params, cancel));
1451
+ if (cancel.isCancellationRequested)
1452
+ return;
1453
+ if (result)
1454
+ return result;
1455
+ }
1456
+ } catch (err) {
1457
+ displayError(err);
1458
+ }
1459
+ },
1460
+ async doValidate(doc) {
1461
+ const result = [];
1462
+ try {
1463
+ const requests = plugins.map((plugin) => {
1464
+ var _a;
1465
+ return (_a = plugin.doValidate) == null ? void 0 : _a.call(plugin, doc);
1466
+ });
1467
+ for (const pending of requests) {
1468
+ const cur = await pending;
1469
+ if (cur)
1470
+ result.push(...cur);
1471
+ }
1472
+ } catch (err) {
1473
+ displayError(err);
1474
+ }
1475
+ return result;
1476
+ },
1477
+ format: marko_default.format
1478
+ };
1479
+
661
1480
  // src/index.ts
662
1481
  if (typeof __require !== "undefined" && __require.extensions && !(".ts" in __require.extensions)) {
663
1482
  __require.extensions[".ts"] = void 0;
664
1483
  }
665
- var cacheForCompiler = /* @__PURE__ */ new WeakMap();
666
- var connection = createConnection(ProposedFeatures.all);
1484
+ var documents = new TextDocuments(TextDocument3);
1485
+ var connection2 = createConnection(ProposedFeatures.all);
667
1486
  var prevDiagnostics = /* @__PURE__ */ new WeakMap();
668
1487
  var diagnosticTimeouts = /* @__PURE__ */ new WeakMap();
669
- var documents = new TextDocuments(TextDocument3);
670
- var markoErrorRegExp = /^(.+?)(?:\((\d+)(?:\s*,\s*(\d+))?\))?: (.*)$/gm;
671
1488
  console.log = (...args) => {
672
- connection.console.log(args.map((v) => inspect(v)).join(" "));
1489
+ connection2.console.log(args.map((v) => inspect2(v)).join(" "));
673
1490
  };
674
1491
  console.error = (...args) => {
675
- connection.console.error(args.map((v) => inspect(v)).join(" "));
1492
+ connection2.console.error(args.map((v) => inspect2(v)).join(" "));
676
1493
  };
677
1494
  process.on("uncaughtException", console.error);
678
1495
  process.on("unhandledRejection", console.error);
679
- connection.onInitialize(() => {
1496
+ connection2.onInitialize(() => {
1497
+ setup2(connection2);
1498
+ setup(connection2, documents);
680
1499
  return {
681
1500
  capabilities: {
682
1501
  textDocumentSync: TextDocumentSyncKind.Incremental,
683
1502
  documentFormattingProvider: true,
684
1503
  definitionProvider: true,
1504
+ hoverProvider: true,
685
1505
  completionProvider: {
686
- triggerCharacters: [".", ":", "<", ">", "@", "/"]
1506
+ triggerCharacters: [
1507
+ ".",
1508
+ ":",
1509
+ "<",
1510
+ ">",
1511
+ "@",
1512
+ "/",
1513
+ '"',
1514
+ "'",
1515
+ "`",
1516
+ " ",
1517
+ "=",
1518
+ "*",
1519
+ "#",
1520
+ "$",
1521
+ "+",
1522
+ "^",
1523
+ "(",
1524
+ "[",
1525
+ "-"
1526
+ ]
687
1527
  }
688
1528
  }
689
1529
  };
690
1530
  });
691
- connection.onInitialized(() => {
1531
+ connection2.onInitialized(() => {
692
1532
  documents.all().forEach((doc) => queueValidation(doc));
693
1533
  });
694
- connection.onCompletion((params) => {
695
- const doc = documents.get(params.textDocument.uri);
696
- const taglib = getTagLibLookup(doc);
697
- if (!taglib)
698
- return CompletionList6.create([], true);
699
- const event = parseUntilOffset({
700
- taglib,
701
- offset: doc.offsetAt(params.position),
702
- text: doc.getText()
703
- });
704
- const handler = event && completions_exports[event.type];
705
- return handler && handler(taglib, doc, params, event) || CompletionList6.create([], true);
1534
+ documents.onDidChangeContent((change) => {
1535
+ queueValidation(change.document);
706
1536
  });
707
- connection.onDefinition((params) => {
708
- const doc = documents.get(params.textDocument.uri);
709
- const taglib = getTagLibLookup(doc);
710
- if (!taglib)
711
- return;
712
- const event = parseUntilOffset({
713
- taglib,
714
- offset: doc.offsetAt(params.position),
715
- text: doc.getText()
716
- });
717
- const handler = event && definitions_exports[event.type];
718
- return handler && handler(taglib, doc, params, event);
1537
+ connection2.onCompletion(async (params, cancel) => {
1538
+ return await service.doComplete(documents.get(params.textDocument.uri), params, cancel) || null;
719
1539
  });
720
- connection.onDocumentFormatting(async ({
721
- textDocument,
722
- options
723
- }) => {
724
- try {
725
- const doc = documents.get(textDocument.uri);
726
- const { fsPath, scheme } = URI6.parse(textDocument.uri);
727
- const text = doc.getText();
728
- const formatted = prettier.format(text, __spreadValues({
729
- parser: "marko",
730
- filepath: fsPath,
731
- plugins: [markoPrettier],
732
- tabWidth: options.tabSize,
733
- useTabs: options.insertSpaces === false
734
- }, scheme === "file" ? await prettier.resolveConfig(fsPath, {
735
- editorconfig: true
736
- }).catch(() => null) : null));
737
- return [
738
- TextEdit5.replace(Range4.create(doc.positionAt(0), doc.positionAt(text.length)), formatted)
739
- ];
740
- } catch (e) {
741
- displayMessage("Error", inspect(e, { colors: false }));
742
- }
743
- return [
744
- TextEdit5.replace(Range4.create(Position3.create(0, 0), Position3.create(0, 0)), "")
745
- ];
1540
+ connection2.onDefinition(async (params, cancel) => {
1541
+ return await service.findDefinition(documents.get(params.textDocument.uri), params, cancel) || null;
746
1542
  });
747
- connection.onDidChangeWatchedFiles(() => {
748
- const clearedCompilers = /* @__PURE__ */ new Set();
749
- for (const doc of documents.all()) {
750
- const { compiler } = getCompilerAndTranslatorForDoc(doc);
751
- if (!clearedCompilers.has(compiler)) {
752
- clearCaches(compiler);
753
- clearedCompilers.add(compiler);
754
- }
755
- }
1543
+ connection2.onHover(async (params, cancel) => {
1544
+ return await service.doHover(documents.get(params.textDocument.uri), params, cancel) || null;
756
1545
  });
757
- documents.onDidChangeContent((change) => {
758
- queueValidation(change.document);
759
- if (change.document.version > 1) {
760
- clearCaches(getCompilerAndTranslatorForDoc(change.document).compiler);
761
- }
1546
+ connection2.onDocumentFormatting(async (params, cancel) => {
1547
+ return await service.format(documents.get(params.textDocument.uri), params, cancel) || null;
762
1548
  });
763
1549
  function queueValidation(doc) {
764
1550
  clearTimeout(diagnosticTimeouts.get(doc));
765
- diagnosticTimeouts.set(doc, setTimeout(() => {
1551
+ const id = setTimeout(async () => {
766
1552
  const prevDiag = prevDiagnostics.get(doc);
767
- const nextDiag = doValidate(doc);
768
- if (prevDiag && isDeepStrictEqual(prevDiag, nextDiag)) {
1553
+ const nextDiag = await service.doValidate(doc) || [];
1554
+ if (diagnosticTimeouts.get(doc) !== id || prevDiag && isDeepStrictEqual(prevDiag, nextDiag)) {
769
1555
  return;
770
1556
  }
771
1557
  prevDiagnostics.set(doc, nextDiag);
772
- connection.sendDiagnostics({
1558
+ connection2.sendDiagnostics({
773
1559
  uri: doc.uri,
774
1560
  diagnostics: nextDiag
775
1561
  });
776
- }, 800));
777
- }
778
- function doValidate(doc) {
779
- const { fsPath, scheme } = URI6.parse(doc.uri);
780
- if (scheme !== "file") {
781
- return [];
782
- }
783
- const { compiler, translator } = getCompilerAndTranslatorForDoc(doc);
784
- const diagnostics = [];
785
- try {
786
- compiler.compileSync(doc.getText(), fsPath, {
787
- cache: getCacheForCompiler(compiler),
788
- output: "source",
789
- code: false,
790
- translator
791
- });
792
- } catch (e) {
793
- let match;
794
- while (match = markoErrorRegExp.exec(e.message)) {
795
- const [, fileName, rawLine, rawCol, msg] = match;
796
- const line = (parseInt(rawLine, 10) || 1) - 1;
797
- const col = (parseInt(rawCol, 10) || 1) - 1;
798
- diagnostics.push(Diagnostic.create(Range4.create(line, col, line, col), msg, DiagnosticSeverity.Error, void 0, fileName));
799
- }
800
- }
801
- return diagnostics;
802
- }
803
- function clearCaches(compiler) {
804
- var _a;
805
- (_a = cacheForCompiler.get(compiler)) == null ? void 0 : _a.clear();
806
- compiler.taglib.clearCaches();
807
- }
808
- function getCacheForCompiler(compiler) {
809
- let cache = cacheForCompiler.get(compiler);
810
- if (!cache) {
811
- cacheForCompiler.set(compiler, cache = /* @__PURE__ */ new Map());
812
- }
813
- return cache;
814
- }
815
- function displayMessage(type, msg) {
816
- setImmediate(() => {
817
- connection.sendNotification(`show${type}`, msg);
818
- });
1562
+ }, 400);
1563
+ diagnosticTimeouts.set(doc, id);
819
1564
  }
820
- documents.listen(connection);
821
- connection.listen();
1565
+ documents.listen(connection2);
1566
+ connection2.listen();
822
1567
  //# sourceMappingURL=index.mjs.map