@marko/language-server 0.12.3 → 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 (37) hide show
  1. package/dist/index.js +1289 -560
  2. package/dist/index.js.map +3 -3
  3. package/dist/index.mjs +1312 -607
  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 +5 -5
  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,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 Range5,
34
- Position as Position4,
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;
258
+ break;
259
+ case "html-comment":
260
+ case "script":
261
+ case "style":
262
+ case "textarea":
263
+ curBodyType = TagType.text;
196
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
+ });
203
420
  },
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;
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
+ });
460
+ },
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;
489
+ }
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;
226
523
  }
227
- }, {
228
- isOpenTagOnly(ev) {
229
- const tagDef = taglib.getTag(ev);
230
- return tagDef && tagDef.openTagOnly;
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();
555
+ });
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
+ }
231
564
  }
232
565
  });
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;
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,164 +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);
429
- }
430
-
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);
863
+ return completions;
451
864
  }
452
865
 
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}`
475
- }
476
- ], true);
477
- }
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
+ };
478
887
 
479
- // src/utils/completions/types/openTagName.ts
480
- import path2 from "path";
888
+ // src/service/marko/validate.ts
481
889
  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
- }
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})`;
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
+ }
534
913
  }
535
914
  }
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
915
+ }
916
+ return diagnostics;
558
917
  };
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
918
 
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";
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";
581
923
 
582
924
  // src/utils/regexp-builder.ts
583
925
  function RegExpBuilder(strings, ...expressions) {
@@ -603,226 +945,589 @@ function escape(val) {
603
945
  return String(val).replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
604
946
  }
605
947
 
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);
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);
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), 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;
650
1337
  }
651
- const tagEntryFile = tagDef.template || tagDef.renderer || tagDef.filePath;
652
- if (!path3.isAbsolute(tagEntryFile)) {
653
- return [];
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;
654
1346
  }
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));
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
+ };
660
1369
  }
1370
+ cache.set(parsed, cached);
661
1371
  }
662
- return [
663
- LocationLink2.create(URI5.file(tagEntryFile).toString(), range, range, rangeFromEvent(document, event))
664
- ];
1372
+ return cached;
665
1373
  }
666
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
+
667
1450
  // src/index.ts
668
1451
  if (typeof __require !== "undefined" && __require.extensions && !(".ts" in __require.extensions)) {
669
1452
  __require.extensions[".ts"] = void 0;
670
1453
  }
671
- var cacheForCompiler = /* @__PURE__ */ new WeakMap();
672
- var connection = createConnection(ProposedFeatures.all);
1454
+ var documents = new TextDocuments(TextDocument3);
1455
+ var connection2 = createConnection(ProposedFeatures.all);
673
1456
  var prevDiagnostics = /* @__PURE__ */ new WeakMap();
674
1457
  var diagnosticTimeouts = /* @__PURE__ */ new WeakMap();
675
- var documents = new TextDocuments(TextDocument3);
676
- var markoErrorRegExp = /^(.+?)(?:\((\d+)(?:\s*,\s*(\d+))?\))?: (.*)$/gm;
677
1458
  console.log = (...args) => {
678
- connection.console.log(args.map((v) => inspect(v)).join(" "));
1459
+ connection2.console.log(args.map((v) => inspect2(v)).join(" "));
679
1460
  };
680
1461
  console.error = (...args) => {
681
- connection.console.error(args.map((v) => inspect(v)).join(" "));
1462
+ connection2.console.error(args.map((v) => inspect2(v)).join(" "));
682
1463
  };
683
1464
  process.on("uncaughtException", console.error);
684
1465
  process.on("unhandledRejection", console.error);
685
- connection.onInitialize(() => {
1466
+ connection2.onInitialize(() => {
1467
+ setup2(connection2);
1468
+ setup(connection2, documents);
686
1469
  return {
687
1470
  capabilities: {
688
1471
  textDocumentSync: TextDocumentSyncKind.Incremental,
689
1472
  documentFormattingProvider: true,
690
1473
  definitionProvider: true,
691
1474
  completionProvider: {
692
- triggerCharacters: [".", ":", "<", ">", "@", "/"]
1475
+ triggerCharacters: [
1476
+ ".",
1477
+ ":",
1478
+ "<",
1479
+ ">",
1480
+ "@",
1481
+ "/",
1482
+ '"',
1483
+ "'",
1484
+ "`",
1485
+ " ",
1486
+ "=",
1487
+ "*",
1488
+ "#",
1489
+ "$",
1490
+ "+",
1491
+ "^",
1492
+ "(",
1493
+ "[",
1494
+ "-"
1495
+ ]
693
1496
  }
694
1497
  }
695
1498
  };
696
1499
  });
697
- connection.onInitialized(() => {
1500
+ connection2.onInitialized(() => {
698
1501
  documents.all().forEach((doc) => queueValidation(doc));
699
1502
  });
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);
712
- });
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);
1503
+ documents.onDidChangeContent((change) => {
1504
+ queueValidation(change.document);
725
1505
  });
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
- ];
1506
+ connection2.onCompletion(async (params, cancel) => {
1507
+ return await service.doComplete(documents.get(params.textDocument.uri), params, cancel) || null;
752
1508
  });
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
- }
1509
+ connection2.onDefinition(async (params, cancel) => {
1510
+ return await service.findDefinition(documents.get(params.textDocument.uri), params, cancel) || null;
762
1511
  });
763
- documents.onDidChangeContent((change) => {
764
- queueValidation(change.document);
765
- if (change.document.version > 1) {
766
- clearCaches(getCompilerAndTranslatorForDoc(change.document).compiler);
767
- }
1512
+ connection2.onDocumentFormatting(async (params, cancel) => {
1513
+ return await service.format(documents.get(params.textDocument.uri), params, cancel) || null;
768
1514
  });
769
1515
  function queueValidation(doc) {
770
1516
  clearTimeout(diagnosticTimeouts.get(doc));
771
- diagnosticTimeouts.set(doc, setTimeout(() => {
1517
+ const id = setTimeout(async () => {
772
1518
  const prevDiag = prevDiagnostics.get(doc);
773
- const nextDiag = doValidate(doc);
774
- if (prevDiag && isDeepStrictEqual(prevDiag, nextDiag)) {
1519
+ const nextDiag = await service.doValidate(doc) || [];
1520
+ if (diagnosticTimeouts.get(doc) !== id || prevDiag && isDeepStrictEqual(prevDiag, nextDiag)) {
775
1521
  return;
776
1522
  }
777
1523
  prevDiagnostics.set(doc, nextDiag);
778
- connection.sendDiagnostics({
1524
+ connection2.sendDiagnostics({
779
1525
  uri: doc.uri,
780
1526
  diagnostics: nextDiag
781
1527
  });
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
- });
1528
+ }, 400);
1529
+ diagnosticTimeouts.set(doc, id);
825
1530
  }
826
- documents.listen(connection);
827
- connection.listen();
1531
+ documents.listen(connection2);
1532
+ connection2.listen();
828
1533
  //# sourceMappingURL=index.mjs.map