@marko/language-server 0.12.3 → 0.12.6

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