@marko/language-server 0.12.1 → 0.12.4

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 +1288 -555
  2. package/dist/index.js.map +3 -3
  3. package/dist/index.mjs +1311 -600
  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 +11 -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,796 @@ 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";
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
+ return path.dirname(getDocFile(doc));
31
+ }
32
+ function getDocFile(doc) {
33
+ return URI.parse(doc.uri).fsPath;
34
+ }
35
+
36
+ // src/utils/parser.ts
37
+ import { createParser, TagType, Range, Ranges } from "htmljs-parser";
38
+
39
+ // src/utils/get-node-at-offset.ts
40
+ function getNodeAtOffset(offset, program) {
41
+ const bodyNode = childAtOffset(offset, program.body);
42
+ if (bodyNode)
43
+ return visitChildNode(offset, bodyNode);
44
+ return childAtOffset(offset, program.static) || program;
45
+ }
46
+ function visitChildNode(offset, child) {
47
+ switch (child.type) {
48
+ case 1 /* Tag */:
49
+ case 14 /* AttrTag */:
50
+ return visitTag(offset, child);
51
+ default:
52
+ return child;
61
53
  }
62
- return compilerAndTranslator;
63
54
  }
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 {
55
+ function visitTag(offset, tag) {
56
+ const { body } = tag;
57
+ if (body && offset > tag.open.end) {
58
+ const childNode = childAtOffset(offset, body);
59
+ return childNode ? visitChildNode(offset, childNode) : tag;
60
+ }
61
+ const { attrs } = tag;
62
+ if (attrs && offset > attrs[0].start) {
63
+ const attrNode = childAtOffset(offset, attrs);
64
+ return attrNode ? visitAttrNode(offset, attrNode) : tag;
65
+ }
66
+ const { var: tagVar } = tag;
67
+ if (tagVar && offset > tagVar.start && offset <= tagVar.end) {
68
+ return tagVar;
69
+ }
70
+ const { args } = tag;
71
+ if (args && offset > args.start && offset <= args.end) {
72
+ return args;
73
+ }
74
+ const { params } = tag;
75
+ if (params && offset > params.start && offset <= params.end) {
76
+ return params;
77
+ }
78
+ const { name } = tag;
79
+ if (name && offset <= name.end) {
80
+ return name;
69
81
  }
82
+ return tag;
70
83
  }
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;
84
+ function visitAttrNode(offset, attr) {
85
+ switch (attr.type) {
86
+ case 14 /* AttrTag */:
87
+ return visitTag(offset, attr);
88
+ case 8 /* AttrNamed */: {
89
+ const { value } = attr;
90
+ if (value && offset > value.start) {
91
+ return value;
80
92
  }
81
- __require(resolveFrom(dir, translator));
82
- return {
83
- compiler: __require(resolveFrom(dir, "@marko/compiler")),
84
- translator
85
- };
86
- } catch {
93
+ const { name } = attr;
94
+ if (offset > name.start && offset <= name.end) {
95
+ return name;
96
+ }
97
+ break;
87
98
  }
88
99
  }
89
- return {
90
- compiler: builtinCompiler,
91
- translator: builtinTranslator
92
- };
100
+ return attr;
101
+ }
102
+ function childAtOffset(offset, children) {
103
+ let max = children.length - 1;
104
+ if (max === -1)
105
+ return void 0;
106
+ let min = 0;
107
+ while (min < max) {
108
+ const mid = 1 + min + max >>> 1;
109
+ if (children[mid].start < offset) {
110
+ min = mid;
111
+ } else {
112
+ max = mid - 1;
113
+ }
114
+ }
115
+ const child = children[min];
116
+ return offset > child.start && offset <= child.end ? child : void 0;
93
117
  }
94
118
 
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;
119
+ // src/utils/parser.ts
120
+ var UNFINISHED = Number.MAX_SAFE_INTEGER;
121
+ var NodeType = /* @__PURE__ */ ((NodeType2) => {
122
+ NodeType2[NodeType2["Program"] = 0] = "Program";
123
+ NodeType2[NodeType2["Tag"] = 1] = "Tag";
124
+ NodeType2[NodeType2["OpenTagName"] = 2] = "OpenTagName";
125
+ NodeType2[NodeType2["ShorthandId"] = 3] = "ShorthandId";
126
+ NodeType2[NodeType2["ShorthandClassName"] = 4] = "ShorthandClassName";
127
+ NodeType2[NodeType2["TagVar"] = 5] = "TagVar";
128
+ NodeType2[NodeType2["TagArgs"] = 6] = "TagArgs";
129
+ NodeType2[NodeType2["TagParams"] = 7] = "TagParams";
130
+ NodeType2[NodeType2["AttrNamed"] = 8] = "AttrNamed";
131
+ NodeType2[NodeType2["AttrName"] = 9] = "AttrName";
132
+ NodeType2[NodeType2["AttrArgs"] = 10] = "AttrArgs";
133
+ NodeType2[NodeType2["AttrValue"] = 11] = "AttrValue";
134
+ NodeType2[NodeType2["AttrMethod"] = 12] = "AttrMethod";
135
+ NodeType2[NodeType2["AttrSpread"] = 13] = "AttrSpread";
136
+ NodeType2[NodeType2["AttrTag"] = 14] = "AttrTag";
137
+ NodeType2[NodeType2["Text"] = 15] = "Text";
138
+ NodeType2[NodeType2["CDATA"] = 16] = "CDATA";
139
+ NodeType2[NodeType2["Doctype"] = 17] = "Doctype";
140
+ NodeType2[NodeType2["Declaration"] = 18] = "Declaration";
141
+ NodeType2[NodeType2["Comment"] = 19] = "Comment";
142
+ NodeType2[NodeType2["Statement"] = 20] = "Statement";
143
+ NodeType2[NodeType2["Placeholder"] = 21] = "Placeholder";
144
+ NodeType2[NodeType2["Scriptlet"] = 22] = "Scriptlet";
145
+ return NodeType2;
146
+ })(NodeType || {});
147
+ function parse(source) {
148
+ const program = {
149
+ type: 0 /* Program */,
150
+ parent: void 0,
151
+ static: [],
152
+ body: [],
153
+ start: 0,
154
+ end: source.length
155
+ };
156
+ let curBodyType;
157
+ let curOpenTagStart;
158
+ let curParent = program;
159
+ let curAttr = void 0;
160
+ let curBody = program.body;
106
161
  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);
162
+ onText(range) {
163
+ curBody.push({
164
+ type: 15 /* Text */,
165
+ parent: curParent,
166
+ start: range.start,
167
+ end: range.end
168
+ });
120
169
  },
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
- }
170
+ onCDATA(range) {
171
+ curBody.push({
172
+ type: 16 /* CDATA */,
173
+ parent: curParent,
174
+ value: range.value,
175
+ start: range.start,
176
+ end: range.end
177
+ });
178
+ },
179
+ onDoctype(range) {
180
+ curBody.push({
181
+ type: 17 /* Doctype */,
182
+ parent: curParent,
183
+ value: range.value,
184
+ start: range.start,
185
+ end: range.end
186
+ });
187
+ },
188
+ onDeclaration(range) {
189
+ curBody.push({
190
+ type: 18 /* Declaration */,
191
+ parent: curParent,
192
+ value: range.value,
193
+ start: range.start,
194
+ end: range.end
195
+ });
196
+ },
197
+ onComment(range) {
198
+ curBody.push({
199
+ type: 19 /* Comment */,
200
+ parent: curParent,
201
+ value: range.value,
202
+ start: range.start,
203
+ end: range.end
204
+ });
205
+ },
206
+ onPlaceholder(range) {
207
+ curBody.push({
208
+ type: 21 /* Placeholder */,
209
+ parent: curParent,
210
+ value: range.value,
211
+ escape: range.escape,
212
+ start: range.start,
213
+ end: range.end
214
+ });
215
+ },
216
+ onScriptlet(range) {
217
+ curBody.push({
218
+ type: 22 /* Scriptlet */,
219
+ parent: curParent,
220
+ value: range.value,
221
+ block: range.block,
222
+ start: range.start,
223
+ end: range.end
224
+ });
225
+ },
226
+ onOpenTagStart(range) {
227
+ curOpenTagStart = range;
228
+ },
229
+ onOpenTagName(range) {
230
+ let concise = true;
231
+ let start = range.start;
232
+ let type = 1 /* Tag */;
233
+ let nameText = void 0;
234
+ if (curOpenTagStart) {
235
+ concise = false;
236
+ start = curOpenTagStart.start;
237
+ curOpenTagStart = void 0;
143
238
  }
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
- })) {
239
+ if (range.expressions.length) {
240
+ curBodyType = TagType.html;
241
+ } else {
242
+ switch (nameText = parser.read(range)) {
243
+ case "area":
244
+ case "base":
245
+ case "br":
246
+ case "col":
247
+ case "embed":
248
+ case "hr":
249
+ case "img":
250
+ case "input":
251
+ case "link":
252
+ case "meta":
253
+ case "param":
254
+ case "source":
255
+ case "track":
256
+ case "wbr":
257
+ curBodyType = TagType.void;
196
258
  break;
259
+ case "html-comment":
260
+ case "script":
261
+ case "style":
262
+ case "textarea":
263
+ curBodyType = TagType.text;
264
+ break;
265
+ case "class":
266
+ case "export":
267
+ case "import":
268
+ case "static": {
269
+ let i = program.body.length;
270
+ for (; i--; ) {
271
+ const prev = program.body[i];
272
+ if (prev.type === 19 /* Comment */) {
273
+ program.static.push(prev);
274
+ } else {
275
+ break;
276
+ }
277
+ }
278
+ program.body.length = i + 1;
279
+ program.static.push(curParent = {
280
+ type: 20 /* Statement */,
281
+ parent: program,
282
+ start: range.start,
283
+ end: UNFINISHED
284
+ });
285
+ return curBodyType = TagType.statement;
197
286
  }
198
- } else {
199
- attrEndPos = attr.argument ? attr.argument.endPos + 1 : attr.endPos;
287
+ default:
288
+ if (nameText[0] === "@") {
289
+ type = 14 /* AttrTag */;
290
+ }
291
+ curBodyType = TagType.html;
292
+ break;
200
293
  }
201
294
  }
202
- finish(ev);
295
+ const parent = curParent;
296
+ const end = UNFINISHED;
297
+ const name = {
298
+ type: 2 /* OpenTagName */,
299
+ parent: void 0,
300
+ quasis: range.quasis,
301
+ expressions: range.expressions,
302
+ start: range.start,
303
+ end: range.end
304
+ };
305
+ const tag = curParent = name.parent = {
306
+ type,
307
+ parent,
308
+ owner: void 0,
309
+ concise,
310
+ open: { start, end },
311
+ nameText,
312
+ name,
313
+ var: void 0,
314
+ args: void 0,
315
+ params: void 0,
316
+ shorthandId: void 0,
317
+ shorthandClassNames: void 0,
318
+ attrs: void 0,
319
+ selfClosed: false,
320
+ bodyType: curBodyType,
321
+ body: void 0,
322
+ close: void 0,
323
+ start,
324
+ end
325
+ };
326
+ if (tag.type === 14 /* AttrTag */) {
327
+ let owner = parent;
328
+ outer:
329
+ do {
330
+ switch (owner.type) {
331
+ case 14 /* AttrTag */:
332
+ break;
333
+ case 1 /* Tag */:
334
+ if (isTransparentTag(owner)) {
335
+ owner = owner.parent;
336
+ continue outer;
337
+ }
338
+ break;
339
+ default:
340
+ break outer;
341
+ }
342
+ tag.owner = owner;
343
+ tag.nameText = resolveAttrTagName(tag);
344
+ pushAttr(owner, tag);
345
+ } while (false);
346
+ }
347
+ curBody.push(tag);
348
+ curOpenTagStart = void 0;
349
+ return curBodyType;
350
+ },
351
+ onTagShorthandId(range) {
352
+ curParent.shorthandId = {
353
+ type: 3 /* ShorthandId */,
354
+ parent: curParent,
355
+ quasis: range.quasis,
356
+ expressions: range.expressions,
357
+ start: range.start,
358
+ end: range.end
359
+ };
360
+ },
361
+ onTagShorthandClass(range) {
362
+ const shorthandClassName = {
363
+ type: 4 /* ShorthandClassName */,
364
+ parent: curParent,
365
+ quasis: range.quasis,
366
+ expressions: range.expressions,
367
+ start: range.start,
368
+ end: range.end
369
+ };
370
+ if (curParent.shorthandClassNames) {
371
+ curParent.shorthandClassNames.push(shorthandClassName);
372
+ } else {
373
+ curParent.shorthandClassNames = [shorthandClassName];
374
+ }
375
+ },
376
+ onTagVar(range) {
377
+ curParent.var = {
378
+ type: 5 /* TagVar */,
379
+ parent: curParent,
380
+ value: range.value,
381
+ start: range.start,
382
+ end: range.end
383
+ };
384
+ },
385
+ onTagParams(range) {
386
+ curParent.params = {
387
+ type: 7 /* TagParams */,
388
+ parent: curParent,
389
+ value: range.value,
390
+ start: range.start,
391
+ end: range.end
392
+ };
393
+ },
394
+ onTagArgs(range) {
395
+ curParent.args = {
396
+ type: 6 /* TagArgs */,
397
+ parent: curParent,
398
+ value: range.value,
399
+ start: range.start,
400
+ end: range.end
401
+ };
402
+ },
403
+ onAttrName(range) {
404
+ const parent = curParent;
405
+ const name = {
406
+ type: 9 /* AttrName */,
407
+ parent: void 0,
408
+ start: range.start,
409
+ end: range.end
410
+ };
411
+ pushAttr(parent, curAttr = name.parent = {
412
+ type: 8 /* AttrNamed */,
413
+ parent,
414
+ name,
415
+ value: void 0,
416
+ args: void 0,
417
+ start: range.start,
418
+ end: range.end
419
+ });
420
+ },
421
+ onAttrArgs(range) {
422
+ curAttr.args = {
423
+ type: 10 /* AttrArgs */,
424
+ parent: curAttr,
425
+ value: range.value,
426
+ start: range.start,
427
+ end: range.end
428
+ };
429
+ },
430
+ onAttrValue(range) {
431
+ curAttr.value = {
432
+ type: 11 /* AttrValue */,
433
+ parent: curAttr,
434
+ value: range.value,
435
+ bound: range.bound,
436
+ start: range.start,
437
+ end: range.end
438
+ };
439
+ curAttr.end = range.end;
440
+ },
441
+ onAttrMethod(range) {
442
+ curAttr.value = {
443
+ type: 12 /* AttrMethod */,
444
+ parent: curAttr,
445
+ params: range.params,
446
+ body: range.body,
447
+ start: range.start,
448
+ end: range.end
449
+ };
450
+ curAttr.end = range.end;
451
+ },
452
+ onAttrSpread(range) {
453
+ pushAttr(curParent, {
454
+ type: 13 /* AttrSpread */,
455
+ parent: curParent,
456
+ value: range.value,
457
+ start: range.start,
458
+ end: range.end
459
+ });
203
460
  },
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;
461
+ onOpenTagEnd(range) {
462
+ curAttr = void 0;
463
+ if (curBodyType === TagType.statement) {
464
+ curParent.end = range.end;
465
+ curParent = curParent.parent;
466
+ } else {
467
+ const tag = curParent;
468
+ tag.open.end = range.end;
469
+ if (range.selfClosed || curBodyType === TagType.void) {
470
+ curParent = tag.parent;
471
+ tag.selfClosed = range.selfClosed;
472
+ tag.end = range.end;
473
+ } else {
474
+ curBody = tag.body = [];
219
475
  }
220
476
  }
221
- finish(ev);
222
477
  },
223
- onCloseTag(ev) {
224
- parentTag = parentTag && parentTag.parent;
225
- finish(ev);
478
+ onCloseTagStart(range) {
479
+ curParent.close = {
480
+ start: range.start,
481
+ end: Number.MAX_SAFE_INTEGER
482
+ };
483
+ },
484
+ onCloseTagEnd(range) {
485
+ if (hasCloseTag(curParent))
486
+ curParent.close.end = range.end;
487
+ curParent.end = range.end;
488
+ curBody = (curParent = curParent.parent).body;
226
489
  }
227
- }, {
228
- isOpenTagOnly(ev) {
229
- const tagDef = taglib.getTag(ev);
230
- return tagDef && tagDef.openTagOnly;
490
+ });
491
+ parser.parse(source);
492
+ return {
493
+ read: parser.read,
494
+ locationAt: parser.locationAt,
495
+ positionAt: parser.positionAt,
496
+ nodeAt: (offset) => getNodeAtOffset(offset, program),
497
+ program
498
+ };
499
+ }
500
+ function pushAttr(parent, node) {
501
+ if (parent.attrs) {
502
+ parent.attrs.push(node);
503
+ } else {
504
+ parent.attrs = [node];
505
+ }
506
+ }
507
+ function hasCloseTag(parent) {
508
+ return parent.close !== void 0;
509
+ }
510
+ function resolveAttrTagName(tag) {
511
+ let name = tag.nameText;
512
+ let parentTag = tag.owner;
513
+ do {
514
+ switch (parentTag.type) {
515
+ case 1 /* Tag */:
516
+ return parentTag.nameText ? `${parentTag.nameText}:${name}` : void 0;
517
+ case 14 /* AttrTag */:
518
+ name = `${parentTag.nameText}:${name}`;
519
+ parentTag = parentTag.owner;
520
+ break;
521
+ default:
522
+ return;
231
523
  }
524
+ } while (parentTag);
525
+ }
526
+ function isTransparentTag(node) {
527
+ return node.nameText !== void 0 && /^(?:if|else(?:-if)?|for|while)$/.test(node.nameText);
528
+ }
529
+
530
+ // src/utils/compiler.ts
531
+ var lookupKey = Symbol("lookup");
532
+ var compilerInfoByDir = /* @__PURE__ */ new Map();
533
+ builtinCompiler.configure({ translator: builtinTranslator });
534
+ function parse2(doc) {
535
+ const compilerInfo = getCompilerInfo(doc);
536
+ let parsed = compilerInfo.cache.get(doc);
537
+ if (!parsed) {
538
+ const source = doc.getText();
539
+ compilerInfo.cache.set(doc, parsed = parse(source));
540
+ }
541
+ return parsed;
542
+ }
543
+ function getCompilerInfo(doc) {
544
+ const dir = getDocDir(doc);
545
+ let info = compilerInfoByDir.get(dir);
546
+ if (!info) {
547
+ info = loadCompilerInfo(dir);
548
+ compilerInfoByDir.set(dir, info);
549
+ }
550
+ return info;
551
+ }
552
+ function setup(connection3, documents2) {
553
+ connection3.onDidChangeWatchedFiles(() => {
554
+ clearAllCaches();
232
555
  });
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;
556
+ documents2.onDidChangeContent(({ document }) => {
557
+ var _a;
558
+ if (document.version > 1) {
559
+ if (document.uri.endsWith(".marko")) {
560
+ (_a = getCompilerInfo(document)) == null ? void 0 : _a.cache.delete(document);
561
+ } else if (/[./\\]marko(?:-tag)?\.json$/.test(document.uri)) {
562
+ clearAllCaches();
563
+ }
564
+ }
565
+ });
566
+ }
567
+ function clearAllCaches() {
568
+ for (const [, info] of compilerInfoByDir) {
569
+ info.cache.clear();
570
+ info.compiler.taglib.clearCaches();
571
+ }
572
+ }
573
+ function loadCompilerInfo(dir) {
574
+ const rootDir = lassoPackageRoot.getRootDir(dir);
575
+ const pkgPath = rootDir && resolveFrom.silent(rootDir, "@marko/compiler/package.json");
576
+ const pkg = pkgPath && __require(pkgPath);
577
+ const cache2 = /* @__PURE__ */ new Map();
578
+ let translator = builtinTranslator;
579
+ let compiler = builtinCompiler;
580
+ if (pkg && /^5\./.test(pkg.version)) {
581
+ try {
582
+ let checkTranslator = [].concat(Object.keys(pkg.dependencies), Object.keys(pkg.peerDependencies), Object.keys(pkg.devDependencies)).find((name) => /^marko$|^(@\/marko\/|marko-)translator-/.test(name));
583
+ if (checkTranslator === "marko" || !checkTranslator) {
584
+ checkTranslator = __require(resolveFrom(dir, "@marko/compiler/config")).translator;
585
+ }
586
+ [compiler, translator] = [
587
+ __require(resolveFrom(dir, "@marko/compiler")),
588
+ __require(resolveFrom(dir, checkTranslator))
589
+ ];
590
+ } catch {
252
591
  }
253
- return false;
254
592
  }
593
+ return {
594
+ cache: cache2,
595
+ get lookup() {
596
+ let lookup = cache2.get(lookupKey);
597
+ if (lookup === void 0) {
598
+ try {
599
+ lookup = compiler.taglib.buildLookup(dir, translator);
600
+ } catch {
601
+ lookup = null;
602
+ }
603
+ cache2.set(lookupKey, lookup);
604
+ }
605
+ return lookup;
606
+ },
607
+ compiler,
608
+ translator
609
+ };
255
610
  }
256
611
 
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
- });
612
+ // src/utils/messages.ts
613
+ import { inspect } from "util";
614
+ var connection;
615
+ function setup2(_) {
616
+ connection = _;
617
+ }
618
+ function displayError(data) {
619
+ display("showError", data);
620
+ }
621
+ function display(type, data) {
622
+ const msg = typeof data === "string" ? data : inspect(data, { colors: false });
623
+ setImmediate(() => connection.sendNotification(type, msg));
624
+ }
267
625
 
268
- // src/utils/completions/types/attributeModifier.ts
626
+ // src/service/index.ts
269
627
  import {
270
- CompletionList,
271
- CompletionItemKind
628
+ CompletionList as CompletionList3
272
629
  } 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"
284
- }
285
- ], true);
286
- }
287
630
 
288
- // src/utils/completions/types/attributeName.ts
631
+ // src/service/marko/complete/index.ts
289
632
  import {
290
- CompletionList as CompletionList2,
291
- CompletionItemKind as CompletionItemKind2,
292
- MarkupKind,
633
+ CompletionList
634
+ } from "vscode-languageserver";
635
+
636
+ // src/service/marko/complete/Tag.ts
637
+ import {
638
+ CompletionItemKind,
293
639
  InsertTextFormat,
294
- TextEdit as TextEdit2
640
+ TextEdit
295
641
  } from "vscode-languageserver";
642
+ var partialCloseTagReg = /<\/(?:[^><]*>)?/iy;
643
+ function Tag(event) {
644
+ const { node } = event;
645
+ const isClosed = node.end !== UNFINISHED;
646
+ if (isClosed || node.concise)
647
+ return;
648
+ const { offset, parsed, code } = event;
649
+ const closingTagStr = `</${node.nameText}>`;
650
+ if (offset === node.open.end) {
651
+ return [
652
+ {
653
+ label: closingTagStr,
654
+ kind: CompletionItemKind.Class,
655
+ insertTextFormat: InsertTextFormat.Snippet,
656
+ insertText: `
657
+ $0
658
+ ${closingTagStr}`
659
+ }
660
+ ];
661
+ } else if (node.close && offset >= node.close.start) {
662
+ const start = node.close.start;
663
+ partialCloseTagReg.lastIndex = start;
664
+ const [{ length }] = partialCloseTagReg.exec(code);
665
+ const end = start + length;
666
+ return [
667
+ {
668
+ label: closingTagStr,
669
+ kind: CompletionItemKind.Class,
670
+ insertTextFormat: InsertTextFormat.Snippet,
671
+ textEdit: TextEdit.replace(parsed.locationAt({
672
+ start,
673
+ end
674
+ }), closingTagStr)
675
+ }
676
+ ];
677
+ }
678
+ }
296
679
 
297
- // src/utils/utils.ts
298
- import fs from "fs";
680
+ // src/service/marko/complete/OpenTagName.ts
681
+ import path2 from "path";
299
682
  import { URI as URI2 } from "vscode-uri";
300
683
  import {
301
- TextEdit,
302
- Position,
303
- Range
684
+ CompletionItemKind as CompletionItemKind2,
685
+ InsertTextFormat as InsertTextFormat2,
686
+ MarkupKind,
687
+ TextEdit as TextEdit2
304
688
  } 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;
689
+ function OpenTagName({
690
+ document,
691
+ lookup,
692
+ parsed,
693
+ node
694
+ }) {
695
+ if (!lookup)
696
+ return;
697
+ const currentTemplateFilePath = getDocFile(document);
698
+ const tag = node.parent;
699
+ const tagNameLocation = parsed.locationAt(node);
700
+ let tags;
701
+ if (tag.type === 14 /* AttrTag */) {
702
+ let parentTag = tag.owner;
703
+ while ((parentTag == null ? void 0 : parentTag.type) === 14 /* AttrTag */)
704
+ parentTag = parentTag.owner;
705
+ const parentTagDef = parentTag && parentTag.nameText && lookup.getTag(parentTag.nameText);
706
+ tags = parentTagDef && parentTagDef.nestedTags && Object.values(parentTagDef.nestedTags) || [];
707
+ } else {
708
+ tags = lookup.getTagsSorted().filter((it) => !it.isNestedTag);
314
709
  }
315
- return null;
316
- }
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);
324
- }
325
- function shiftCompletionRanges(list, offset) {
326
- list.items.forEach((item) => {
327
- if (item.additionalTextEdits) {
328
- item.additionalTextEdits.forEach((edit) => shiftRange(edit.range, offset));
710
+ return tags.filter((it) => !it.deprecated).filter((it) => it.name !== "*").filter((it) => /^[^_]/.test(it.name) || !/\/node_modules\//.test(it.filePath)).map((it) => {
711
+ let label = it.isNestedTag ? `@${it.name}` : it.name;
712
+ const fileForTag = it.template || it.renderer || it.filePath;
713
+ const fileURIForTag = URI2.file(fileForTag).toString();
714
+ const nodeModuleMatch = /\/node_modules\/((?:@[^/]+\/)?[^/]+)/.exec(fileForTag);
715
+ const nodeModuleName = nodeModuleMatch && nodeModuleMatch[1];
716
+ const isCoreTag = nodeModuleName === "marko";
717
+ const documentation = {
718
+ kind: MarkupKind.Markdown,
719
+ value: it.html ? `Built in [<${it.name}>](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/${it.name}) HTML tag.` : nodeModuleName ? isCoreTag ? `Core Marko [<${it.name}>](${fileURIForTag}) tag.` : `Custom Marko tag discovered from the ["${nodeModuleName}"](${fileURIForTag}) npm package.` : `Custom Marko tag discovered from:
720
+
721
+ [${path2.relative(currentTemplateFilePath, fileForTag)}](${fileURIForTag})`
722
+ };
723
+ if (it.description) {
724
+ documentation.value += `
725
+
726
+ ${it.description}`;
329
727
  }
330
- if (item.textEdit) {
331
- shiftEdit(item.textEdit, offset);
728
+ const autocomplete = it.autocomplete && it.autocomplete[0];
729
+ if (autocomplete) {
730
+ if (autocomplete.displayText) {
731
+ label = autocomplete.displayText;
732
+ }
733
+ if (autocomplete.description) {
734
+ documentation.value += `
735
+
736
+ ${autocomplete.description}`;
737
+ }
738
+ if (autocomplete.descriptionMoreURL) {
739
+ documentation.value += `
740
+
741
+ [More Info](${autocomplete.descriptionMoreURL})`;
742
+ }
332
743
  }
744
+ return {
745
+ label,
746
+ documentation,
747
+ kind: CompletionItemKind2.Class,
748
+ insertTextFormat: InsertTextFormat2.Snippet,
749
+ textEdit: TextEdit2.replace(tagNameLocation, autocomplete && autocomplete.snippet || label)
750
+ };
333
751
  });
334
- return list;
335
- }
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);
342
- }
343
- }
344
- function shiftRange(range, offset) {
345
- if (range) {
346
- shiftPosition(range.start, offset);
347
- shiftPosition(range.end, offset);
348
- }
349
- }
350
- function shiftPosition(pos, offset) {
351
- if (pos.line === 0) {
352
- pos.character += offset.character;
353
- }
354
- pos.line += offset.line;
355
- return pos;
356
752
  }
357
753
 
358
- // src/utils/completions/types/attributeName.ts
359
- function attributeName(taglib, document, _params, event) {
754
+ // src/service/marko/complete/AttrName.ts
755
+ import {
756
+ CompletionItemKind as CompletionItemKind3,
757
+ MarkupKind as MarkupKind2,
758
+ InsertTextFormat as InsertTextFormat3,
759
+ TextEdit as TextEdit3
760
+ } from "vscode-languageserver";
761
+ function AttrName({
762
+ offset,
763
+ node,
764
+ parsed,
765
+ lookup
766
+ }) {
767
+ let name = parsed.read(node);
768
+ if (name[0] === "{")
769
+ return;
770
+ const modifierIndex = name.indexOf(":");
771
+ const hasModifier = modifierIndex !== -1;
772
+ if (hasModifier) {
773
+ if (offset >= node.start + modifierIndex) {
774
+ return [
775
+ {
776
+ label: "scoped",
777
+ kind: CompletionItemKind3.Keyword,
778
+ detail: "Use to prefix with a unique ID"
779
+ },
780
+ {
781
+ label: "no-update",
782
+ kind: CompletionItemKind3.Keyword,
783
+ detail: "Use to skip future updates to this attribute"
784
+ }
785
+ ];
786
+ } else {
787
+ name = name.slice(0, modifierIndex);
788
+ }
789
+ }
790
+ if (!lookup)
791
+ return;
360
792
  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 || "*";
793
+ const attrNameLoc = parsed.locationAt(hasModifier ? {
794
+ start: node.start,
795
+ end: node.start + name.length
796
+ } : node);
797
+ const tagName = node.parent.parent.nameText || "";
798
+ const tagDef = tagName && lookup.getTag(tagName);
364
799
  const nestedTagAttrs = {};
365
800
  const neverAttrs = /* @__PURE__ */ new Set();
366
801
  if (tagDef && tagDef.nestedTags) {
@@ -369,18 +804,18 @@ function attributeName(taglib, document, _params, event) {
369
804
  nestedTagAttrs[nestedTagDef.targetProperty] = true;
370
805
  }
371
806
  }
372
- taglib.forEachAttribute(tagName, (attr) => {
807
+ lookup.forEachAttribute(tagName, (attr) => {
373
808
  if (attr.type === "never") {
374
809
  neverAttrs.add(attr.name);
375
810
  }
376
811
  });
377
- taglib.forEachAttribute(tagName, (attr, parent) => {
812
+ lookup.forEachAttribute(tagName, (attr, parent) => {
378
813
  if (attr.deprecated || nestedTagAttrs[attr.name] || attr.name === "*" || neverAttrs.has(attr.name) || attr.name[0] === "_" && /\/node_modules\//.test(attr.filePath || parent.filePath)) {
379
814
  return;
380
815
  }
381
816
  const type = attr.type || (attr.html ? "string" : null);
382
817
  const documentation = {
383
- kind: MarkupKind.Markdown,
818
+ kind: MarkupKind2.Markdown,
384
819
  value: attr.description || ""
385
820
  };
386
821
  let label = attr.name;
@@ -420,162 +855,71 @@ function attributeName(taglib, document, _params, event) {
420
855
  completions.push({
421
856
  label,
422
857
  documentation: documentation.value ? documentation : void 0,
423
- kind: CompletionItemKind2.Property,
424
- insertTextFormat: InsertTextFormat.Snippet,
425
- textEdit: TextEdit2.replace(attrNameRange, snippet)
858
+ kind: CompletionItemKind3.Property,
859
+ insertTextFormat: InsertTextFormat3.Snippet,
860
+ textEdit: TextEdit3.replace(attrNameLoc, snippet)
426
861
  });
427
862
  });
428
- return CompletionList2.create(completions, true);
863
+ return completions;
429
864
  }
430
865
 
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
- }
452
-
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}`
473
- }
474
- ], true);
475
- }
866
+ // src/service/marko/complete/index.ts
867
+ var handlers = {
868
+ Tag,
869
+ OpenTagName,
870
+ AttrName
871
+ };
872
+ var doComplete = async (doc, params) => {
873
+ var _a;
874
+ const parsed = parse2(doc);
875
+ const offset = doc.offsetAt(params.position);
876
+ const node = parsed.nodeAt(offset);
877
+ return CompletionList.create(await ((_a = handlers[NodeType[node.type]]) == null ? void 0 : _a.call(handlers, {
878
+ document: doc,
879
+ params,
880
+ parsed,
881
+ offset,
882
+ node,
883
+ code: doc.getText(),
884
+ ...getCompilerInfo(doc)
885
+ })) || [], true);
886
+ };
476
887
 
477
- // src/utils/completions/types/openTagName.ts
478
- import path2 from "path";
888
+ // src/service/marko/validate.ts
479
889
  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
- }
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})`;
890
+ import { Diagnostic, DiagnosticSeverity, Range as Range2 } from "vscode-languageserver";
891
+ var markoErrorRegExp = /^(.+?)(?:\((\d+)(?:\s*,\s*(\d+))?\))?: (.*)$/gm;
892
+ var doValidate = (doc) => {
893
+ const { fsPath, scheme } = URI3.parse(doc.uri);
894
+ const diagnostics = [];
895
+ if (scheme === "file") {
896
+ const { compiler, translator, cache: cache2, lookup } = getCompilerInfo(doc);
897
+ if (lookup) {
898
+ try {
899
+ compiler.compileSync(doc.getText(), fsPath, {
900
+ cache: cache2,
901
+ output: "source",
902
+ code: false,
903
+ translator
904
+ });
905
+ } catch (e) {
906
+ let match;
907
+ while (match = markoErrorRegExp.exec(e.message)) {
908
+ const [, fileName, rawLine, rawCol, msg] = match;
909
+ const line = (parseInt(rawLine, 10) || 1) - 1;
910
+ const col = (parseInt(rawCol, 10) || 1) - 1;
911
+ diagnostics.push(Diagnostic.create(Range2.create(line, col, line, col), msg, DiagnosticSeverity.Error, void 0, fileName));
912
+ }
532
913
  }
533
914
  }
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
915
+ }
916
+ return diagnostics;
556
917
  };
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
918
 
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";
919
+ // src/service/marko/definition/OpenTagName.ts
920
+ import path3 from "path";
921
+ import { URI as URI5 } from "vscode-uri";
922
+ import { Range as Range4, LocationLink } from "vscode-languageserver";
579
923
 
580
924
  // src/utils/regexp-builder.ts
581
925
  function RegExpBuilder(strings, ...expressions) {
@@ -601,11 +945,72 @@ function escape(val) {
601
945
  return String(val).replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
602
946
  }
603
947
 
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);
948
+ // src/utils/utils.ts
949
+ import fs from "fs";
950
+ import { URI as URI4 } from "vscode-uri";
951
+ import { Position, Range as Range3 } from "vscode-languageserver";
952
+ import { TextDocument } from "vscode-languageserver-textdocument";
953
+ var START_OF_FILE = Range3.create(Position.create(0, 0), Position.create(0, 0));
954
+ function createTextDocument(filename) {
955
+ const uri = URI4.file(filename).toString();
956
+ const content = fs.readFileSync(filename, "utf-8");
957
+ return TextDocument.create(uri, "plaintext", 0, content);
958
+ }
959
+
960
+ // src/service/marko/definition/OpenTagName.ts
961
+ function OpenTagName2({
962
+ lookup,
963
+ parsed,
964
+ node
965
+ }) {
966
+ if (!lookup)
967
+ return;
968
+ const tag = node.parent;
969
+ let tagDef;
970
+ let range = START_OF_FILE;
971
+ if (tag.type === 14 /* AttrTag */) {
972
+ let parentTag = tag.owner;
973
+ while ((parentTag == null ? void 0 : parentTag.type) === 14 /* AttrTag */)
974
+ parentTag = parentTag.owner;
975
+ tagDef = parentTag && parentTag.nameText ? lookup.getTag(parentTag.nameText) : void 0;
976
+ } else {
977
+ tagDef = tag.nameText ? lookup.getTag(tag.nameText) : void 0;
978
+ }
979
+ if (!tagDef) {
980
+ return;
981
+ }
982
+ const tagEntryFile = tagDef.template || tagDef.renderer || tagDef.filePath;
983
+ if (!path3.isAbsolute(tagEntryFile)) {
984
+ return;
985
+ }
986
+ if (/\/marko(?:-tag)?\.json$/.test(tagEntryFile)) {
987
+ const tagDefDoc = createTextDocument(tagEntryFile);
988
+ const match = RegExpBuilder`/"(?:<${tag.nameText}>|${tag.nameText})"\s*:\s*[^\r\n,]+/g`.exec(tagDefDoc.getText());
989
+ if (match && match.index) {
990
+ range = Range4.create(tagDefDoc.positionAt(match.index), tagDefDoc.positionAt(match.index + match[0].length));
991
+ }
992
+ }
993
+ return [
994
+ LocationLink.create(URI5.file(tagEntryFile).toString(), range, range, parsed.locationAt(node))
995
+ ];
996
+ }
997
+
998
+ // src/service/marko/definition/AttrName.ts
999
+ import { URI as URI6 } from "vscode-uri";
1000
+ import { Range as Range5, LocationLink as LocationLink2 } from "vscode-languageserver";
1001
+ function AttrName2({
1002
+ lookup,
1003
+ parsed,
1004
+ node
1005
+ }) {
1006
+ if (!lookup)
1007
+ return;
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);
609
1014
  let range = START_OF_FILE;
610
1015
  if (!attrDef) {
611
1016
  return;
@@ -616,207 +1021,513 @@ function attributeName2(taglib, document, _params, event) {
616
1021
  }
617
1022
  if (/\/marko(?:-tag)?\.json$/.test(attrEntryFile)) {
618
1023
  const tagDefDoc = createTextDocument(attrEntryFile);
619
- 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());
620
1025
  if (match && match.index) {
621
- range = Range2.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));
622
1027
  }
623
1028
  }
624
1029
  return [
625
- LocationLink.create(URI4.file(attrEntryFile).toString(), range, range, rangeFromEvent(document, event))
1030
+ LocationLink2.create(URI6.file(attrEntryFile).toString(), range, range, parsed.locationAt(node))
626
1031
  ];
627
1032
  }
628
1033
 
629
- // src/utils/definitions/types/openTagName.ts
630
- 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
631
1097
  import {
632
- Range as Range3,
633
- LocationLink as LocationLink2
1098
+ CompletionList as CompletionList2
634
1099
  } 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);
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();
644
1258
  }
645
- if (!tagDef) {
646
- 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), service2.parseStylesheet(virtualDoc));
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), service2.parseStylesheet(virtualDoc));
1319
+ if (result && updateRange(doc, info, result.range)) {
1320
+ return result;
1321
+ }
1322
+ break;
1323
+ }
1324
+ },
1325
+ async doValidate(doc) {
1326
+ const infoByExt = getStyleSheetInfo(doc);
1327
+ const result = [];
1328
+ for (const ext in infoByExt) {
1329
+ const info = infoByExt[ext];
1330
+ for (const diag of info.service.doValidation(info.virtualDoc, info.parsed)) {
1331
+ if (updateRange(doc, info, diag.range)) {
1332
+ result.push(diag);
1333
+ }
1334
+ }
1335
+ }
1336
+ return result;
647
1337
  }
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));
1338
+ };
1339
+ function updateRange(doc, info, range) {
1340
+ const start = info.sourceOffsetAt(info.virtualDoc.offsetAt(range.start));
1341
+ const end = info.sourceOffsetAt(info.virtualDoc.offsetAt(range.end));
1342
+ if (start !== void 0 || end !== void 0) {
1343
+ range.start = doc.positionAt(start ?? end);
1344
+ range.end = doc.positionAt(end ?? start);
1345
+ return true;
1346
+ }
1347
+ return false;
1348
+ }
1349
+ function getStyleSheetInfo(doc) {
1350
+ var _a;
1351
+ const parsed = parse2(doc);
1352
+ let cached = cache.get(parsed);
1353
+ if (!cached) {
1354
+ const results = extractStyleSheets(doc.getText(), parsed.program, getCompilerInfo(doc).lookup);
1355
+ cached = {};
1356
+ for (const ext in results) {
1357
+ const service2 = (_a = services[ext]) == null ? void 0 : _a.call(services);
1358
+ if (!service2)
1359
+ continue;
1360
+ const { generated, sourceOffsetAt, generatedOffsetAt } = results[ext];
1361
+ const virtualDoc = TextDocument2.create(doc.uri, "css", doc.version, generated);
1362
+ cached[ext] = {
1363
+ service: service2,
1364
+ virtualDoc,
1365
+ sourceOffsetAt,
1366
+ generatedOffsetAt,
1367
+ parsed: service2.parseStylesheet(virtualDoc)
1368
+ };
654
1369
  }
1370
+ cache.set(parsed, cached);
655
1371
  }
656
- return [
657
- LocationLink2.create(URI5.file(tagEntryFile).toString(), range, range, rangeFromEvent(document, event))
658
- ];
1372
+ return cached;
659
1373
  }
660
1374
 
1375
+ // src/service/index.ts
1376
+ var plugins = [marko_default, stylesheet_default];
1377
+ var service = {
1378
+ async doComplete(doc, params, cancel) {
1379
+ const result = CompletionList3.create([], false);
1380
+ try {
1381
+ const requests = plugins.map((plugin) => {
1382
+ var _a;
1383
+ return (_a = plugin.doComplete) == null ? void 0 : _a.call(plugin, doc, params, cancel);
1384
+ });
1385
+ for (const pending of requests) {
1386
+ const cur = await pending;
1387
+ if (cancel.isCancellationRequested)
1388
+ break;
1389
+ if (cur) {
1390
+ let items;
1391
+ if (Array.isArray(cur)) {
1392
+ items = cur;
1393
+ } else {
1394
+ items = cur.items;
1395
+ result.isIncomplete || (result.isIncomplete = cur.isIncomplete);
1396
+ }
1397
+ result.items.push(...items);
1398
+ }
1399
+ }
1400
+ } catch (err) {
1401
+ result.isIncomplete = true;
1402
+ displayError(err);
1403
+ }
1404
+ return result;
1405
+ },
1406
+ async findDefinition(doc, params, cancel) {
1407
+ const result = [];
1408
+ try {
1409
+ const requests = plugins.map((plugin) => {
1410
+ var _a;
1411
+ return (_a = plugin.findDefinition) == null ? void 0 : _a.call(plugin, doc, params, cancel);
1412
+ });
1413
+ for (const pending of requests) {
1414
+ const cur = await pending;
1415
+ if (cancel.isCancellationRequested)
1416
+ break;
1417
+ if (cur) {
1418
+ if (Array.isArray(cur)) {
1419
+ result.push(...cur);
1420
+ } else {
1421
+ result.push(cur);
1422
+ }
1423
+ }
1424
+ }
1425
+ } catch (err) {
1426
+ displayError(err);
1427
+ }
1428
+ return result;
1429
+ },
1430
+ async doValidate(doc) {
1431
+ const result = [];
1432
+ try {
1433
+ const requests = plugins.map((plugin) => {
1434
+ var _a;
1435
+ return (_a = plugin.doValidate) == null ? void 0 : _a.call(plugin, doc);
1436
+ });
1437
+ for (const pending of requests) {
1438
+ const cur = await pending;
1439
+ if (cur)
1440
+ result.push(...cur);
1441
+ }
1442
+ } catch (err) {
1443
+ displayError(err);
1444
+ }
1445
+ return result;
1446
+ },
1447
+ format: marko_default.format
1448
+ };
1449
+
661
1450
  // src/index.ts
662
1451
  if (typeof __require !== "undefined" && __require.extensions && !(".ts" in __require.extensions)) {
663
1452
  __require.extensions[".ts"] = void 0;
664
1453
  }
665
- var cacheForCompiler = /* @__PURE__ */ new WeakMap();
666
- var connection = createConnection(ProposedFeatures.all);
1454
+ var documents = new TextDocuments(TextDocument3);
1455
+ var connection2 = createConnection(ProposedFeatures.all);
667
1456
  var prevDiagnostics = /* @__PURE__ */ new WeakMap();
668
1457
  var diagnosticTimeouts = /* @__PURE__ */ new WeakMap();
669
- var documents = new TextDocuments(TextDocument3);
670
- var markoErrorRegExp = /^(.+?)(?:\((\d+)(?:\s*,\s*(\d+))?\))?: (.*)$/gm;
671
1458
  console.log = (...args) => {
672
- connection.console.log(args.map((v) => inspect(v)).join(" "));
1459
+ connection2.console.log(args.map((v) => inspect2(v)).join(" "));
673
1460
  };
674
1461
  console.error = (...args) => {
675
- connection.console.error(args.map((v) => inspect(v)).join(" "));
1462
+ connection2.console.error(args.map((v) => inspect2(v)).join(" "));
676
1463
  };
677
1464
  process.on("uncaughtException", console.error);
678
1465
  process.on("unhandledRejection", console.error);
679
- connection.onInitialize(() => {
1466
+ connection2.onInitialize(() => {
1467
+ setup2(connection2);
1468
+ setup(connection2, documents);
680
1469
  return {
681
1470
  capabilities: {
682
1471
  textDocumentSync: TextDocumentSyncKind.Incremental,
683
1472
  documentFormattingProvider: true,
684
1473
  definitionProvider: true,
685
1474
  completionProvider: {
686
- triggerCharacters: [".", ":", "<", ">", "@", "/"]
1475
+ triggerCharacters: [
1476
+ ".",
1477
+ ":",
1478
+ "<",
1479
+ ">",
1480
+ "@",
1481
+ "/",
1482
+ '"',
1483
+ "'",
1484
+ "`",
1485
+ " ",
1486
+ "=",
1487
+ "*",
1488
+ "#",
1489
+ "$",
1490
+ "+",
1491
+ "^",
1492
+ "(",
1493
+ "[",
1494
+ "-"
1495
+ ]
687
1496
  }
688
1497
  }
689
1498
  };
690
1499
  });
691
- connection.onInitialized(() => {
1500
+ connection2.onInitialized(() => {
692
1501
  documents.all().forEach((doc) => queueValidation(doc));
693
1502
  });
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);
1503
+ documents.onDidChangeContent((change) => {
1504
+ queueValidation(change.document);
706
1505
  });
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);
1506
+ connection2.onCompletion(async (params, cancel) => {
1507
+ return await service.doComplete(documents.get(params.textDocument.uri), params, cancel) || null;
719
1508
  });
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
- ];
1509
+ connection2.onDefinition(async (params, cancel) => {
1510
+ return await service.findDefinition(documents.get(params.textDocument.uri), params, cancel) || null;
746
1511
  });
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
- }
756
- });
757
- documents.onDidChangeContent((change) => {
758
- queueValidation(change.document);
759
- if (change.document.version > 1) {
760
- clearCaches(getCompilerAndTranslatorForDoc(change.document).compiler);
761
- }
1512
+ connection2.onDocumentFormatting(async (params, cancel) => {
1513
+ return await service.format(documents.get(params.textDocument.uri), params, cancel) || null;
762
1514
  });
763
1515
  function queueValidation(doc) {
764
1516
  clearTimeout(diagnosticTimeouts.get(doc));
765
- diagnosticTimeouts.set(doc, setTimeout(() => {
1517
+ const id = setTimeout(async () => {
766
1518
  const prevDiag = prevDiagnostics.get(doc);
767
- const nextDiag = doValidate(doc);
768
- if (prevDiag && isDeepStrictEqual(prevDiag, nextDiag)) {
1519
+ const nextDiag = await service.doValidate(doc) || [];
1520
+ if (diagnosticTimeouts.get(doc) !== id || prevDiag && isDeepStrictEqual(prevDiag, nextDiag)) {
769
1521
  return;
770
1522
  }
771
1523
  prevDiagnostics.set(doc, nextDiag);
772
- connection.sendDiagnostics({
1524
+ connection2.sendDiagnostics({
773
1525
  uri: doc.uri,
774
1526
  diagnostics: nextDiag
775
1527
  });
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
- });
1528
+ }, 400);
1529
+ diagnosticTimeouts.set(doc, id);
819
1530
  }
820
- documents.listen(connection);
821
- connection.listen();
1531
+ documents.listen(connection2);
1532
+ connection2.listen();
822
1533
  //# sourceMappingURL=index.mjs.map