@elurjs/language-server 1.1.0

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 (115) hide show
  1. package/README.md +71 -0
  2. package/bin/elur-language-server.js +3 -0
  3. package/dist/capabilities.d.ts +6 -0
  4. package/dist/capabilities.d.ts.map +1 -0
  5. package/dist/capabilities.js +22 -0
  6. package/dist/capabilities.js.map +1 -0
  7. package/dist/codeActions/fixes.d.ts +16 -0
  8. package/dist/codeActions/fixes.d.ts.map +1 -0
  9. package/dist/codeActions/fixes.js +94 -0
  10. package/dist/codeActions/fixes.js.map +1 -0
  11. package/dist/codeActions/provider.d.ts +7 -0
  12. package/dist/codeActions/provider.d.ts.map +1 -0
  13. package/dist/codeActions/provider.js +46 -0
  14. package/dist/codeActions/provider.js.map +1 -0
  15. package/dist/completion/directives.d.ts +6 -0
  16. package/dist/completion/directives.d.ts.map +1 -0
  17. package/dist/completion/directives.js +16 -0
  18. package/dist/completion/directives.js.map +1 -0
  19. package/dist/completion/events.d.ts +6 -0
  20. package/dist/completion/events.d.ts.map +1 -0
  21. package/dist/completion/events.js +20 -0
  22. package/dist/completion/events.js.map +1 -0
  23. package/dist/completion/modifiers.d.ts +6 -0
  24. package/dist/completion/modifiers.d.ts.map +1 -0
  25. package/dist/completion/modifiers.js +19 -0
  26. package/dist/completion/modifiers.js.map +1 -0
  27. package/dist/completion/provider.d.ts +7 -0
  28. package/dist/completion/provider.d.ts.map +1 -0
  29. package/dist/completion/provider.js +46 -0
  30. package/dist/completion/provider.js.map +1 -0
  31. package/dist/diagnostics/provider.d.ts +7 -0
  32. package/dist/diagnostics/provider.d.ts.map +1 -0
  33. package/dist/diagnostics/provider.js +49 -0
  34. package/dist/diagnostics/provider.js.map +1 -0
  35. package/dist/diagnostics/rules.d.ts +29 -0
  36. package/dist/diagnostics/rules.d.ts.map +1 -0
  37. package/dist/diagnostics/rules.js +46 -0
  38. package/dist/diagnostics/rules.js.map +1 -0
  39. package/dist/formatting/ast.d.ts +37 -0
  40. package/dist/formatting/ast.d.ts.map +1 -0
  41. package/dist/formatting/ast.js +112 -0
  42. package/dist/formatting/ast.js.map +1 -0
  43. package/dist/formatting/attributes.d.ts +7 -0
  44. package/dist/formatting/attributes.d.ts.map +1 -0
  45. package/dist/formatting/attributes.js +7 -0
  46. package/dist/formatting/attributes.js.map +1 -0
  47. package/dist/formatting/printer.d.ts +34 -0
  48. package/dist/formatting/printer.d.ts.map +1 -0
  49. package/dist/formatting/printer.js +380 -0
  50. package/dist/formatting/printer.js.map +1 -0
  51. package/dist/formatting/provider.d.ts +10 -0
  52. package/dist/formatting/provider.d.ts.map +1 -0
  53. package/dist/formatting/provider.js +82 -0
  54. package/dist/formatting/provider.js.map +1 -0
  55. package/dist/formatting/renderer.d.ts +11 -0
  56. package/dist/formatting/renderer.d.ts.map +1 -0
  57. package/dist/formatting/renderer.js +175 -0
  58. package/dist/formatting/renderer.js.map +1 -0
  59. package/dist/formatting/tokenizer.d.ts +7 -0
  60. package/dist/formatting/tokenizer.d.ts.map +1 -0
  61. package/dist/formatting/tokenizer.js +7 -0
  62. package/dist/formatting/tokenizer.js.map +1 -0
  63. package/dist/hover/provider.d.ts +7 -0
  64. package/dist/hover/provider.d.ts.map +1 -0
  65. package/dist/hover/provider.js +48 -0
  66. package/dist/hover/provider.js.map +1 -0
  67. package/dist/modifiers/analyzer.d.ts +18 -0
  68. package/dist/modifiers/analyzer.d.ts.map +1 -0
  69. package/dist/modifiers/analyzer.js +75 -0
  70. package/dist/modifiers/analyzer.js.map +1 -0
  71. package/dist/modifiers/constants.d.ts +17 -0
  72. package/dist/modifiers/constants.d.ts.map +1 -0
  73. package/dist/modifiers/constants.js +58 -0
  74. package/dist/modifiers/constants.js.map +1 -0
  75. package/dist/modifiers/normalizer.d.ts +20 -0
  76. package/dist/modifiers/normalizer.d.ts.map +1 -0
  77. package/dist/modifiers/normalizer.js +62 -0
  78. package/dist/modifiers/normalizer.js.map +1 -0
  79. package/dist/modifiers/parser.d.ts +33 -0
  80. package/dist/modifiers/parser.d.ts.map +1 -0
  81. package/dist/modifiers/parser.js +73 -0
  82. package/dist/modifiers/parser.js.map +1 -0
  83. package/dist/modifiers/suggestions.d.ts +20 -0
  84. package/dist/modifiers/suggestions.d.ts.map +1 -0
  85. package/dist/modifiers/suggestions.js +60 -0
  86. package/dist/modifiers/suggestions.js.map +1 -0
  87. package/dist/server-browser.d.ts +16 -0
  88. package/dist/server-browser.d.ts.map +1 -0
  89. package/dist/server-browser.js +16 -0
  90. package/dist/server-browser.js.map +1 -0
  91. package/dist/server.d.ts +8 -0
  92. package/dist/server.d.ts.map +1 -0
  93. package/dist/server.js +29 -0
  94. package/dist/server.js.map +1 -0
  95. package/dist/template/detector.d.ts +43 -0
  96. package/dist/template/detector.d.ts.map +1 -0
  97. package/dist/template/detector.js +184 -0
  98. package/dist/template/detector.js.map +1 -0
  99. package/dist/template/parser.d.ts +42 -0
  100. package/dist/template/parser.d.ts.map +1 -0
  101. package/dist/template/parser.js +225 -0
  102. package/dist/template/parser.js.map +1 -0
  103. package/dist/template/scope.d.ts +18 -0
  104. package/dist/template/scope.d.ts.map +1 -0
  105. package/dist/template/scope.js +44 -0
  106. package/dist/template/scope.js.map +1 -0
  107. package/dist/utils/config.d.ts +14 -0
  108. package/dist/utils/config.d.ts.map +1 -0
  109. package/dist/utils/config.js +13 -0
  110. package/dist/utils/config.js.map +1 -0
  111. package/dist/utils/levenshtein.d.ts +7 -0
  112. package/dist/utils/levenshtein.d.ts.map +1 -0
  113. package/dist/utils/levenshtein.js +7 -0
  114. package/dist/utils/levenshtein.js.map +1 -0
  115. package/package.json +61 -0
package/README.md ADDED
@@ -0,0 +1,71 @@
1
+ # @elurjs/language-server
2
+
3
+ LSP (Language Server Protocol) server for [Elur](https://elur.dev/) `html\`\`` tagged templates.
4
+
5
+ Provides diagnostics, autocompletion, hover help, quick fixes, and formatting —
6
+ works in **any** editor that supports LSP.
7
+
8
+ ## Features
9
+
10
+ - **Diagnostics**: unknown modifiers, duplicate modifiers, passive+prevent conflict,
11
+ key modifiers on non-key events, non-canonical modifier order
12
+ - **Completion**: `@event` names, `.modifier` suggestions, `ref`/`show`/`hide` directives
13
+ - **Hover**: help text for each modifier (`.prevent`, `.stop`, `.enter`, etc.)
14
+ - **Quick fixes**: dedupe modifiers, normalize order, resolve conflicts, replace unknowns
15
+ - **Formatting**: indents and wraps `html\`\`` template content
16
+
17
+ ## Install
18
+
19
+ ```bash
20
+ npm install @elurjs/language-server
21
+ ```
22
+
23
+ ## Editor setup
24
+
25
+ ### VS Code
26
+
27
+ The `vscode-elur` extension launches this server automatically.
28
+
29
+ ### Neovim
30
+
31
+ ```lua
32
+ require("lspconfig").elur = {
33
+ cmd = { "elur-language-server", "--stdio" },
34
+ filetypes = { "typescript", "javascript", "typescriptreact", "javascriptreact" },
35
+ }
36
+ ```
37
+
38
+ ### Helix
39
+
40
+ ```toml
41
+ # ~/.config/helix/languages.toml
42
+ [[language]]
43
+ name = "typescript"
44
+ language-servers = ["elur-language-server"]
45
+ ```
46
+
47
+ ### Zed
48
+
49
+ ```json
50
+ "language_servers": ["elur-language-server"]
51
+ ```
52
+
53
+ ### Emacs (eglot)
54
+
55
+ ```elisp
56
+ (add-to-list 'eglot-server-programs
57
+ '((typescript-mode) . ("elur-language-server" "--stdio")))
58
+ ```
59
+
60
+ ## Development
61
+
62
+ ```bash
63
+ npm install
64
+ npm run typecheck
65
+ npm test
66
+ npm run build
67
+ ```
68
+
69
+ ## License
70
+
71
+ MIT
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ import { startServer } from "../dist/server.js";
3
+ startServer();
@@ -0,0 +1,6 @@
1
+ /**
2
+ * capabilities.ts — LSP capability declarations.
3
+ */
4
+ import type { InitializeResult } from "vscode-languageserver/node.js";
5
+ export declare function getCapabilities(): InitializeResult;
6
+ //# sourceMappingURL=capabilities.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capabilities.d.ts","sourceRoot":"","sources":["../src/capabilities.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAGtE,wBAAgB,eAAe,IAAI,gBAAgB,CAgBlD"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * capabilities.ts — LSP capability declarations.
3
+ */
4
+ import { TextDocumentSyncKind } from "vscode-languageserver/node.js";
5
+ export function getCapabilities() {
6
+ return {
7
+ capabilities: {
8
+ textDocumentSync: TextDocumentSyncKind.Incremental,
9
+ completionProvider: {
10
+ triggerCharacters: ["@", ".", "="],
11
+ resolveProvider: true,
12
+ },
13
+ hoverProvider: true,
14
+ codeActionProvider: {
15
+ codeActionKinds: ["quickfix"],
16
+ },
17
+ documentFormattingProvider: true,
18
+ documentRangeFormattingProvider: true,
19
+ },
20
+ };
21
+ }
22
+ //# sourceMappingURL=capabilities.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capabilities.js","sourceRoot":"","sources":["../src/capabilities.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAErE,MAAM,UAAU,eAAe;IAC7B,OAAO;QACL,YAAY,EAAE;YACZ,gBAAgB,EAAE,oBAAoB,CAAC,WAAW;YAClD,kBAAkB,EAAE;gBAClB,iBAAiB,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;gBAClC,eAAe,EAAE,IAAI;aACtB;YACD,aAAa,EAAE,IAAI;YACnB,kBAAkB,EAAE;gBAClB,eAAe,EAAE,CAAC,UAAU,CAAC;aAC9B;YACD,0BAA0B,EAAE,IAAI;YAChC,+BAA+B,EAAE,IAAI;SACtC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * fixes.ts — Generate quick fixes for modifier issues.
3
+ *
4
+ * Ported from elur-vscode/event-modifiers.js createModifierQuickFixes().
5
+ */
6
+ interface RawFix {
7
+ id: string;
8
+ title: string;
9
+ modifiers: string[];
10
+ }
11
+ export interface QuickFix extends RawFix {
12
+ chain: string;
13
+ }
14
+ export declare function createModifierQuickFixes(eventName: string, modifiers: string[]): QuickFix[];
15
+ export {};
16
+ //# sourceMappingURL=fixes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fixes.d.ts","sourceRoot":"","sources":["../../src/codeActions/fixes.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAQH,UAAU,MAAM;IACd,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,QAAS,SAAQ,MAAM;IACtC,KAAK,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EAAE,GAClB,QAAQ,EAAE,CAyFZ"}
@@ -0,0 +1,94 @@
1
+ /**
2
+ * fixes.ts — Generate quick fixes for modifier issues.
3
+ *
4
+ * Ported from elur-vscode/event-modifiers.js createModifierQuickFixes().
5
+ */
6
+ import { analyzeEventModifiers, isKeyEventName } from "../modifiers/analyzer.js";
7
+ import { uniqueModifiers, removeModifier, normalizeModifierOrder } from "../modifiers/normalizer.js";
8
+ import { suggestClosestModifier } from "../modifiers/suggestions.js";
9
+ import { buildEventBindingChain } from "../modifiers/parser.js";
10
+ import { KEY_MODIFIERS } from "../modifiers/constants.js";
11
+ export function createModifierQuickFixes(eventName, modifiers) {
12
+ const fixes = [];
13
+ const issues = analyzeEventModifiers(eventName, modifiers);
14
+ // Dedupe
15
+ const deduped = uniqueModifiers(modifiers);
16
+ if (deduped.length !== modifiers.length) {
17
+ fixes.push({
18
+ id: "remove-duplicate-modifiers",
19
+ title: "Remove duplicate modifiers",
20
+ modifiers: deduped,
21
+ });
22
+ }
23
+ // Normalize order
24
+ const normalizedOrder = normalizeModifierOrder(eventName, modifiers);
25
+ if (normalizedOrder.join(".") !== (modifiers || []).join(".")) {
26
+ fixes.push({
27
+ id: "normalize-modifier-order",
28
+ title: "Normalize modifier order",
29
+ modifiers: normalizedOrder,
30
+ });
31
+ }
32
+ // passive + prevent conflict
33
+ const hasPassive = modifiers.includes("passive");
34
+ const hasPrevent = modifiers.includes("prevent");
35
+ if (hasPassive && hasPrevent) {
36
+ fixes.push({
37
+ id: "drop-prevent",
38
+ title: "Remove .prevent (keep .passive)",
39
+ modifiers: removeModifier(modifiers, "prevent"),
40
+ });
41
+ fixes.push({
42
+ id: "drop-passive",
43
+ title: "Remove .passive (keep .prevent)",
44
+ modifiers: removeModifier(modifiers, "passive"),
45
+ });
46
+ }
47
+ // Unknown modifiers
48
+ const seenUnknown = new Set();
49
+ for (const issue of issues) {
50
+ if (issue.code !== "unknown-modifier")
51
+ continue;
52
+ const unknown = issue.message.replace("Unknown modifier .", "").trim().toLowerCase();
53
+ if (!unknown || seenUnknown.has(unknown))
54
+ continue;
55
+ seenUnknown.add(unknown);
56
+ const suggestion = suggestClosestModifier(unknown, eventName);
57
+ if (!suggestion) {
58
+ fixes.push({
59
+ id: `remove-unknown-${unknown}`,
60
+ title: `Remove unknown modifier .${unknown}`,
61
+ modifiers: removeModifier(modifiers, unknown),
62
+ });
63
+ continue;
64
+ }
65
+ fixes.push({
66
+ id: `replace-${unknown}-with-${suggestion}`,
67
+ title: `Replace .${unknown} with .${suggestion}`,
68
+ modifiers: modifiers.map((mod) => (mod === unknown ? suggestion : mod)),
69
+ });
70
+ }
71
+ // Key modifiers on non-key event
72
+ if (!isKeyEventName(eventName)) {
73
+ const keyMods = modifiers.filter((mod) => KEY_MODIFIERS.includes(mod));
74
+ if (keyMods.length > 0) {
75
+ fixes.push({
76
+ id: "remove-key-modifiers",
77
+ title: "Remove key-only modifiers",
78
+ modifiers: modifiers.filter((mod) => !KEY_MODIFIERS.includes(mod)),
79
+ });
80
+ }
81
+ }
82
+ // Deduplicate by chain
83
+ const uniqueFixes = [];
84
+ const seenChains = new Set();
85
+ for (const fix of fixes) {
86
+ const chain = buildEventBindingChain(eventName, fix.modifiers);
87
+ if (seenChains.has(chain))
88
+ continue;
89
+ seenChains.add(chain);
90
+ uniqueFixes.push({ ...fix, chain });
91
+ }
92
+ return uniqueFixes;
93
+ }
94
+ //# sourceMappingURL=fixes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fixes.js","sourceRoot":"","sources":["../../src/codeActions/fixes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * provider.ts — Code actions provider for the LSP server.
3
+ */
4
+ import type { Connection, TextDocuments } from "vscode-languageserver/node.js";
5
+ import type { TextDocument } from "vscode-languageserver-textdocument";
6
+ export declare function registerCodeActions(connection: Connection, documents: TextDocuments<TextDocument>): void;
7
+ //# sourceMappingURL=provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/codeActions/provider.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC/E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAKvE,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,aAAa,CAAC,YAAY,CAAC,GACrC,IAAI,CA0CN"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * provider.ts — Code actions provider for the LSP server.
3
+ */
4
+ import { CodeActionKind } from "vscode-languageserver/node.js";
5
+ import { parseEventBindingChain } from "../modifiers/parser.js";
6
+ import { createModifierQuickFixes } from "./fixes.js";
7
+ export function registerCodeActions(connection, documents) {
8
+ connection.onCodeAction((params) => {
9
+ const document = documents.get(params.textDocument.uri);
10
+ if (!document)
11
+ return null;
12
+ const actions = [];
13
+ for (const diagnostic of params.context.diagnostics) {
14
+ if (diagnostic.source !== "elur")
15
+ continue;
16
+ const chainText = document.getText(diagnostic.range);
17
+ const parsed = parseEventBindingChain(chainText);
18
+ if (!parsed)
19
+ continue;
20
+ const fixes = createModifierQuickFixes(parsed.eventName, parsed.modifiers);
21
+ for (const fix of fixes) {
22
+ const action = {
23
+ title: fix.title,
24
+ kind: CodeActionKind.QuickFix,
25
+ diagnostics: [diagnostic],
26
+ edit: {
27
+ changes: {
28
+ [document.uri]: [
29
+ {
30
+ range: diagnostic.range,
31
+ newText: fix.chain,
32
+ },
33
+ ],
34
+ },
35
+ },
36
+ isPreferred: fix.id === "remove-duplicate-modifiers" ||
37
+ fix.id === "drop-prevent" ||
38
+ fix.id === "normalize-modifier-order",
39
+ };
40
+ actions.push(action);
41
+ }
42
+ }
43
+ return actions;
44
+ });
45
+ }
46
+ //# sourceMappingURL=provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.js","sourceRoot":"","sources":["../../src/codeActions/provider.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,EAAc,cAAc,EAAiB,MAAM,+BAA+B,CAAC;AAC1F,OAAO,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAEtD,MAAM,UAAU,mBAAmB,CACjC,UAAsB,EACtB,SAAsC;IAEtC,UAAU,CAAC,YAAY,CAAC,CAAC,MAAM,EAAE,EAAE;QACjC,MAAM,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;QACxD,IAAI,CAAC,QAAQ;YAAE,OAAO,IAAI,CAAC;QAE3B,MAAM,OAAO,GAAiB,EAAE,CAAC;QAEjC,KAAK,MAAM,UAAU,IAAI,MAAM,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;YACpD,IAAI,UAAU,CAAC,MAAM,KAAK,MAAM;gBAAE,SAAS;YAE3C,MAAM,SAAS,GAAG,QAAQ,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;YACrD,MAAM,MAAM,GAAG,sBAAsB,CAAC,SAAS,CAAC,CAAC;YACjD,IAAI,CAAC,MAAM;gBAAE,SAAS;YAEtB,MAAM,KAAK,GAAG,wBAAwB,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;YAE3E,KAAK,MAAM,GAAG,IAAI,KAAK,EAAE,CAAC;gBACxB,MAAM,MAAM,GAAe;oBACzB,KAAK,EAAE,GAAG,CAAC,KAAK;oBAChB,IAAI,EAAE,cAAc,CAAC,QAAQ;oBAC7B,WAAW,EAAE,CAAC,UAAU,CAAC;oBACzB,IAAI,EAAE;wBACJ,OAAO,EAAE;4BACP,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE;gCACd;oCACE,KAAK,EAAE,UAAU,CAAC,KAAK;oCACvB,OAAO,EAAE,GAAG,CAAC,KAAK;iCACnB;6BACF;yBACF;qBACe;oBAClB,WAAW,EACT,GAAG,CAAC,EAAE,KAAK,4BAA4B;wBACvC,GAAG,CAAC,EAAE,KAAK,cAAc;wBACzB,GAAG,CAAC,EAAE,KAAK,0BAA0B;iBACxC,CAAC;gBACF,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACvB,CAAC;QACH,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * directives.ts — Directive attribute completion items (ref, show, hide).
3
+ */
4
+ import type { CompletionItem } from "vscode-languageserver/node.js";
5
+ export declare function buildDirectiveCompletions(): CompletionItem[];
6
+ //# sourceMappingURL=directives.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"directives.d.ts","sourceRoot":"","sources":["../../src/completion/directives.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAGpE,wBAAgB,yBAAyB,IAAI,cAAc,EAAE,CAS5D"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * directives.ts — Directive attribute completion items (ref, show, hide).
3
+ */
4
+ import { DIRECTIVE_ATTRIBUTES } from "../modifiers/constants.js";
5
+ import { CompletionItemKind } from "vscode-languageserver/node.js";
6
+ export function buildDirectiveCompletions() {
7
+ return DIRECTIVE_ATTRIBUTES.map((directive) => ({
8
+ label: directive,
9
+ kind: CompletionItemKind.Property,
10
+ insertText: `${directive}=\${1}`,
11
+ insertTextFormat: 2,
12
+ detail: "Elur directive",
13
+ documentation: `Elur directive attribute: ${directive}.`,
14
+ }));
15
+ }
16
+ //# sourceMappingURL=directives.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"directives.js","sourceRoot":"","sources":["../../src/completion/directives.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAEjE,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAEnE,MAAM,UAAU,yBAAyB;IACvC,OAAO,oBAAoB,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;QAC9C,KAAK,EAAE,SAAS;QAChB,IAAI,EAAE,kBAAkB,CAAC,QAAQ;QACjC,UAAU,EAAE,GAAG,SAAS,QAAQ;QAChC,gBAAgB,EAAE,CAAC;QACnB,MAAM,EAAE,gBAAgB;QACxB,aAAa,EAAE,6BAA6B,SAAS,GAAG;KACzD,CAAC,CAAC,CAAC;AACN,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * events.ts — Event name completion items.
3
+ */
4
+ import type { CompletionItem } from "vscode-languageserver/node.js";
5
+ export declare function buildEventCompletions(prefix: string): CompletionItem[];
6
+ //# sourceMappingURL=events.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/completion/events.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAGpE,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,EAAE,CAatE"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * events.ts — Event name completion items.
3
+ */
4
+ import { EVENT_BINDINGS } from "../modifiers/constants.js";
5
+ import { CompletionItemKind } from "vscode-languageserver/node.js";
6
+ export function buildEventCompletions(prefix) {
7
+ const p = (prefix || "").toLowerCase();
8
+ return EVENT_BINDINGS
9
+ .filter((eventName) => eventName.startsWith(p))
10
+ .map((eventName) => ({
11
+ label: `@${eventName}`,
12
+ kind: CompletionItemKind.Event,
13
+ filterText: `@${eventName}`,
14
+ insertText: `@${eventName}=\${1}`,
15
+ insertTextFormat: 2,
16
+ detail: "Elur event binding",
17
+ documentation: `Bind ${eventName} inside html tagged templates.`,
18
+ }));
19
+ }
20
+ //# sourceMappingURL=events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/completion/events.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAE3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAEnE,MAAM,UAAU,qBAAqB,CAAC,MAAc;IAClD,MAAM,CAAC,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;IACvC,OAAO,cAAc;SAClB,MAAM,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;SAC9C,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;QACnB,KAAK,EAAE,IAAI,SAAS,EAAE;QACtB,IAAI,EAAE,kBAAkB,CAAC,KAAK;QAC9B,UAAU,EAAE,IAAI,SAAS,EAAE;QAC3B,UAAU,EAAE,IAAI,SAAS,QAAQ;QACjC,gBAAgB,EAAE,CAAC;QACnB,MAAM,EAAE,oBAAoB;QAC5B,aAAa,EAAE,QAAQ,SAAS,gCAAgC;KACjE,CAAC,CAAC,CAAC;AACR,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * modifiers.ts — Modifier completion items.
3
+ */
4
+ import type { CompletionItem } from "vscode-languageserver/node.js";
5
+ export declare function buildModifierCompletions(eventName: string, usedModifiers: string[], modifierPrefix: string): CompletionItem[];
6
+ //# sourceMappingURL=modifiers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"modifiers.d.ts","sourceRoot":"","sources":["../../src/completion/modifiers.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAGpE,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,MAAM,EAAE,EACvB,cAAc,EAAE,MAAM,GACrB,cAAc,EAAE,CAWlB"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * modifiers.ts — Modifier completion items.
3
+ */
4
+ import { getModifierSuggestions } from "../modifiers/suggestions.js";
5
+ import { MODIFIER_HELP } from "../modifiers/constants.js";
6
+ import { isKeyEventName } from "../modifiers/analyzer.js";
7
+ import { CompletionItemKind } from "vscode-languageserver/node.js";
8
+ export function buildModifierCompletions(eventName, usedModifiers, modifierPrefix) {
9
+ const suggestions = getModifierSuggestions(eventName, usedModifiers, modifierPrefix);
10
+ const isKey = isKeyEventName(eventName);
11
+ return suggestions.map((modifier) => ({
12
+ label: `.${modifier}`,
13
+ kind: CompletionItemKind.EnumMember,
14
+ insertText: modifier,
15
+ detail: isKey ? "Elur key/event modifier" : "Elur event modifier",
16
+ documentation: MODIFIER_HELP[modifier] || "Elur event modifier",
17
+ }));
18
+ }
19
+ //# sourceMappingURL=modifiers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"modifiers.js","sourceRoot":"","sources":["../../src/completion/modifiers.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAE1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAEnE,MAAM,UAAU,wBAAwB,CACtC,SAAiB,EACjB,aAAuB,EACvB,cAAsB;IAEtB,MAAM,WAAW,GAAG,sBAAsB,CAAC,SAAS,EAAE,aAAa,EAAE,cAAc,CAAC,CAAC;IACrF,MAAM,KAAK,GAAG,cAAc,CAAC,SAAS,CAAC,CAAC;IAExC,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QACpC,KAAK,EAAE,IAAI,QAAQ,EAAE;QACrB,IAAI,EAAE,kBAAkB,CAAC,UAAU;QACnC,UAAU,EAAE,QAAQ;QACpB,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,yBAAyB,CAAC,CAAC,CAAC,qBAAqB;QACjE,aAAa,EAAE,aAAa,CAAC,QAAQ,CAAC,IAAI,qBAAqB;KAChE,CAAC,CAAC,CAAC;AACN,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * provider.ts — Completion provider for the LSP server.
3
+ */
4
+ import type { Connection, TextDocuments } from "vscode-languageserver/node.js";
5
+ import type { TextDocument } from "vscode-languageserver-textdocument";
6
+ export declare function registerCompletion(connection: Connection, documents: TextDocuments<TextDocument>): void;
7
+ //# sourceMappingURL=provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/completion/provider.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC/E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAYvE,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,aAAa,CAAC,YAAY,CAAC,GACrC,IAAI,CA4CN"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * provider.ts — Completion provider for the LSP server.
3
+ */
4
+ import { Position } from "vscode-languageserver/node.js";
5
+ import { parseEventContextFromPrefix } from "../modifiers/parser.js";
6
+ import { isInsideTaggedTemplate } from "../template/detector.js";
7
+ import { buildEventCompletions } from "./events.js";
8
+ import { buildModifierCompletions } from "./modifiers.js";
9
+ import { buildDirectiveCompletions } from "./directives.js";
10
+ const SUPPORTED_LANGUAGES = new Set([
11
+ "javascript", "typescript", "javascriptreact", "typescriptreact",
12
+ ]);
13
+ export function registerCompletion(connection, documents) {
14
+ connection.onCompletion((params) => {
15
+ const document = documents.get(params.textDocument.uri);
16
+ if (!document || !SUPPORTED_LANGUAGES.has(document.languageId)) {
17
+ return null;
18
+ }
19
+ const text = document.getText();
20
+ const offset = document.offsetAt(params.position);
21
+ if (!isInsideTaggedTemplate(text, offset)) {
22
+ return null;
23
+ }
24
+ const linePrefix = document.getText({
25
+ start: Position.create(params.position.line, 0),
26
+ end: params.position,
27
+ });
28
+ const eventContext = parseEventContextFromPrefix(linePrefix);
29
+ if (eventContext?.mode === "modifier") {
30
+ const items = buildModifierCompletions(eventContext.eventName || "", eventContext.usedModifiers || [], eventContext.modifierPrefix || "");
31
+ return { items, isIncomplete: false };
32
+ }
33
+ if (eventContext?.mode === "event") {
34
+ const items = buildEventCompletions(eventContext.eventPrefix || "");
35
+ return { items, isIncomplete: false };
36
+ }
37
+ // Default: offer events + directives
38
+ const items = [
39
+ ...buildEventCompletions(""),
40
+ ...buildDirectiveCompletions(),
41
+ ];
42
+ return { items, isIncomplete: false };
43
+ });
44
+ connection.onCompletionResolve((item) => item);
45
+ }
46
+ //# sourceMappingURL=provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.js","sourceRoot":"","sources":["../../src/completion/provider.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,EAAkC,QAAQ,EAAE,MAAM,+BAA+B,CAAC;AACzF,OAAO,EAAE,2BAA2B,EAAE,MAAM,wBAAwB,CAAC;AACrE,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAC;AAE5D,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAC;IAClC,YAAY,EAAE,YAAY,EAAE,iBAAiB,EAAE,iBAAiB;CACjE,CAAC,CAAC;AAEH,MAAM,UAAU,kBAAkB,CAChC,UAAsB,EACtB,SAAsC;IAEtC,UAAU,CAAC,YAAY,CAAC,CAAC,MAAM,EAAE,EAAE;QACjC,MAAM,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;QACxD,IAAI,CAAC,QAAQ,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;YAC/D,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,EAAE,CAAC;QAChC,MAAM,MAAM,GAAG,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAElD,IAAI,CAAC,sBAAsB,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC;YAC1C,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,UAAU,GAAG,QAAQ,CAAC,OAAO,CAAC;YAClC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;YAC/C,GAAG,EAAE,MAAM,CAAC,QAAQ;SACrB,CAAC,CAAC;QAEH,MAAM,YAAY,GAAG,2BAA2B,CAAC,UAAU,CAAC,CAAC;QAE7D,IAAI,YAAY,EAAE,IAAI,KAAK,UAAU,EAAE,CAAC;YACtC,MAAM,KAAK,GAAG,wBAAwB,CACpC,YAAY,CAAC,SAAS,IAAI,EAAE,EAC5B,YAAY,CAAC,aAAa,IAAI,EAAE,EAChC,YAAY,CAAC,cAAc,IAAI,EAAE,CAClC,CAAC;YACF,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAoB,CAAC;QAC1D,CAAC;QAED,IAAI,YAAY,EAAE,IAAI,KAAK,OAAO,EAAE,CAAC;YACnC,MAAM,KAAK,GAAG,qBAAqB,CAAC,YAAY,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC;YACpE,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAoB,CAAC;QAC1D,CAAC;QAED,qCAAqC;QACrC,MAAM,KAAK,GAAqB;YAC9B,GAAG,qBAAqB,CAAC,EAAE,CAAC;YAC5B,GAAG,yBAAyB,EAAE;SAC/B,CAAC;QACF,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAoB,CAAC;IAC1D,CAAC,CAAC,CAAC;IAEH,UAAU,CAAC,mBAAmB,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;AACjD,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * provider.ts — Diagnostics provider for the LSP server.
3
+ */
4
+ import type { Connection, TextDocuments } from "vscode-languageserver/node.js";
5
+ import type { TextDocument } from "vscode-languageserver-textdocument";
6
+ export declare function registerDiagnostics(connection: Connection, documents: TextDocuments<TextDocument>): void;
7
+ //# sourceMappingURL=provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/diagnostics/provider.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC/E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAQvE,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,aAAa,CAAC,YAAY,CAAC,GACrC,IAAI,CA2CN"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * provider.ts — Diagnostics provider for the LSP server.
3
+ */
4
+ import { DiagnosticSeverity } from "vscode-languageserver/node.js";
5
+ import { scanDiagnostics } from "./rules.js";
6
+ const SUPPORTED_LANGUAGES = new Set([
7
+ "javascript", "typescript", "javascriptreact", "typescriptreact",
8
+ ]);
9
+ export function registerDiagnostics(connection, documents) {
10
+ function validate(document) {
11
+ if (!SUPPORTED_LANGUAGES.has(document.languageId))
12
+ return;
13
+ const scheme = document.uri.startsWith("file:") ? "file"
14
+ : document.uri.startsWith("untitled:") ? "untitled"
15
+ : "other";
16
+ if (scheme !== "file" && scheme !== "untitled")
17
+ return;
18
+ const text = document.getText();
19
+ if (!text.includes("@")) {
20
+ connection.sendDiagnostics({ uri: document.uri, diagnostics: [] });
21
+ return;
22
+ }
23
+ const enableStyleHints = true; // TODO: read from client config
24
+ const rawDiags = scanDiagnostics(text, enableStyleHints);
25
+ const diagnostics = rawDiags.map((d) => {
26
+ const severity = d.severity === "information"
27
+ ? DiagnosticSeverity.Information
28
+ : DiagnosticSeverity.Warning;
29
+ return {
30
+ severity,
31
+ code: d.code,
32
+ message: d.message,
33
+ source: "elur",
34
+ range: {
35
+ start: document.positionAt(d.range.start),
36
+ end: document.positionAt(d.range.end),
37
+ },
38
+ data: d.data,
39
+ };
40
+ });
41
+ connection.sendDiagnostics({ uri: document.uri, diagnostics });
42
+ }
43
+ documents.onDidOpen((e) => validate(e.document));
44
+ documents.onDidChangeContent((e) => validate(e.document));
45
+ documents.onDidClose((e) => {
46
+ connection.sendDiagnostics({ uri: e.document.uri, diagnostics: [] });
47
+ });
48
+ }
49
+ //# sourceMappingURL=provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.js","sourceRoot":"","sources":["../../src/diagnostics/provider.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,EAAc,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAC/E,OAAO,EAAE,eAAe,EAAuB,MAAM,YAAY,CAAC;AAElE,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAC;IAClC,YAAY,EAAE,YAAY,EAAE,iBAAiB,EAAE,iBAAiB;CACjE,CAAC,CAAC;AAEH,MAAM,UAAU,mBAAmB,CACjC,UAAsB,EACtB,SAAsC;IAEtC,SAAS,QAAQ,CAAC,QAAsB;QACtC,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC;YAAE,OAAO;QAC1D,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM;YACtD,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,UAAU;gBACjD,CAAC,CAAC,OAAO,CAAC;QACd,IAAI,MAAM,KAAK,MAAM,IAAI,MAAM,KAAK,UAAU;YAAE,OAAO;QAEvD,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,EAAE,CAAC;QAChC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YACxB,UAAU,CAAC,eAAe,CAAC,EAAE,GAAG,EAAE,QAAQ,CAAC,GAAG,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,CAAC;YACnE,OAAO;QACT,CAAC;QAED,MAAM,gBAAgB,GAAG,IAAI,CAAC,CAAC,gCAAgC;QAC/D,MAAM,QAAQ,GAAG,eAAe,CAAC,IAAI,EAAE,gBAAgB,CAAC,CAAC;QAEzD,MAAM,WAAW,GAAiB,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAiB,EAAE,EAAE;YACnE,MAAM,QAAQ,GAAG,CAAC,CAAC,QAAQ,KAAK,aAAa;gBAC3C,CAAC,CAAC,kBAAkB,CAAC,WAAW;gBAChC,CAAC,CAAC,kBAAkB,CAAC,OAAO,CAAC;YAE/B,OAAO;gBACL,QAAQ;gBACR,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,OAAO,EAAE,CAAC,CAAC,OAAO;gBAClB,MAAM,EAAE,MAAM;gBACd,KAAK,EAAE;oBACL,KAAK,EAAE,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC;oBACzC,GAAG,EAAE,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC;iBACtC;gBACD,IAAI,EAAE,CAAC,CAAC,IAAI;aACb,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,UAAU,CAAC,eAAe,CAAC,EAAE,GAAG,EAAE,QAAQ,CAAC,GAAG,EAAE,WAAW,EAAE,CAAC,CAAC;IACjE,CAAC;IAED,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;IACjD,SAAS,CAAC,kBAAkB,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC1D,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,EAAE;QACzB,UAAU,CAAC,eAAe,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,QAAQ,CAAC,GAAG,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,CAAC;IACvE,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * rules.ts — Diagnostic rules for event modifiers.
3
+ *
4
+ * Ported from elur-vscode/extension.js validateDocument().
5
+ */
6
+ export interface DiagnosticData {
7
+ code: string;
8
+ eventName: string;
9
+ modifiers: string[];
10
+ range: {
11
+ start: number;
12
+ end: number;
13
+ };
14
+ }
15
+ export interface TextDiagnostic {
16
+ code: string;
17
+ severity: "warning" | "information";
18
+ message: string;
19
+ range: {
20
+ start: number;
21
+ end: number;
22
+ };
23
+ data: DiagnosticData;
24
+ }
25
+ /**
26
+ * Scans text for @event.modifier chains and returns diagnostics for all issues.
27
+ */
28
+ export declare function scanDiagnostics(text: string, enableStyleHints: boolean): TextDiagnostic[];
29
+ //# sourceMappingURL=rules.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../../src/diagnostics/rules.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,KAAK,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;CACvC;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,SAAS,GAAG,aAAa,CAAC;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IACtC,IAAI,EAAE,cAAc,CAAC;CACtB;AAMD;;GAEG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,gBAAgB,EAAE,OAAO,GACxB,cAAc,EAAE,CAqClB"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * rules.ts — Diagnostic rules for event modifiers.
3
+ *
4
+ * Ported from elur-vscode/extension.js validateDocument().
5
+ */
6
+ import { analyzeEventModifiers } from "../modifiers/analyzer.js";
7
+ // Match @event.modifier chains with or without trailing = (so diagnostics
8
+ // appear while the user is still typing, before completing the binding).
9
+ const EVENT_CHAIN_RE = /@([a-zA-Z][a-zA-Z0-9:-]*)((?:\.[a-zA-Z0-9-]+)*)(?:\s*=(?![=]))?/g;
10
+ /**
11
+ * Scans text for @event.modifier chains and returns diagnostics for all issues.
12
+ */
13
+ export function scanDiagnostics(text, enableStyleHints) {
14
+ if (!text.includes("@"))
15
+ return [];
16
+ const diagnostics = [];
17
+ let match;
18
+ while ((match = EVENT_CHAIN_RE.exec(text)) !== null) {
19
+ const eventName = (match[1] || "").toLowerCase();
20
+ const modifiers = (match[2] || "")
21
+ .split(".")
22
+ .map((mod) => mod.toLowerCase())
23
+ .filter(Boolean);
24
+ let issues = analyzeEventModifiers(eventName, modifiers, enableStyleHints);
25
+ if (!enableStyleHints) {
26
+ issues = issues.filter((issue) => issue.code !== "modifier-order-noncanonical");
27
+ }
28
+ if (issues.length === 0)
29
+ continue;
30
+ const eqIndex = match[0].indexOf("=");
31
+ const highlightLength = eqIndex >= 0 ? eqIndex : match[0].length;
32
+ const start = match.index;
33
+ const end = match.index + highlightLength;
34
+ for (const issue of issues) {
35
+ diagnostics.push({
36
+ code: issue.code,
37
+ severity: issue.severity,
38
+ message: issue.message,
39
+ range: { start, end },
40
+ data: { code: issue.code, eventName, modifiers, range: { start, end } },
41
+ });
42
+ }
43
+ }
44
+ return diagnostics;
45
+ }
46
+ //# sourceMappingURL=rules.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rules.js","sourceRoot":"","sources":["../../src/diagnostics/rules.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAiBjE,0EAA0E;AAC1E,yEAAyE;AACzE,MAAM,cAAc,GAAG,kEAAkE,CAAC;AAE1F;;GAEG;AACH,MAAM,UAAU,eAAe,CAC7B,IAAY,EACZ,gBAAyB;IAEzB,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IAEnC,MAAM,WAAW,GAAqB,EAAE,CAAC;IACzC,IAAI,KAA6B,CAAC;IAElC,OAAO,CAAC,KAAK,GAAG,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QACpD,MAAM,SAAS,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;QACjD,MAAM,SAAS,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;aAC/B,KAAK,CAAC,GAAG,CAAC;aACV,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;aAC/B,MAAM,CAAC,OAAO,CAAC,CAAC;QAEnB,IAAI,MAAM,GAAG,qBAAqB,CAAC,SAAS,EAAE,SAAS,EAAE,gBAAgB,CAAC,CAAC;QAC3E,IAAI,CAAC,gBAAgB,EAAE,CAAC;YACtB,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,6BAA6B,CAAC,CAAC;QAClF,CAAC;QAED,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;YAAE,SAAS;QAElC,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACtC,MAAM,eAAe,GAAG,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;QACjE,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;QAC1B,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,GAAG,eAAe,CAAC;QAE1C,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,WAAW,CAAC,IAAI,CAAC;gBACf,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,QAAQ,EAAE,KAAK,CAAC,QAAQ;gBACxB,OAAO,EAAE,KAAK,CAAC,OAAO;gBACtB,KAAK,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE;gBACrB,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;aACxE,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,WAAW,CAAC;AACrB,CAAC"}