@seljs/editor 1.0.0 → 1.0.1-beta.9

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 (103) hide show
  1. package/dist/completion/completion-items.cjs +36 -0
  2. package/dist/completion/completion-items.mjs +32 -0
  3. package/dist/completion/index.cjs +1 -0
  4. package/dist/completion/index.d.mts +1 -0
  5. package/dist/completion/index.mjs +2 -0
  6. package/dist/completion/schema-completion.cjs +182 -0
  7. package/dist/completion/schema-completion.d.cts +25 -0
  8. package/dist/completion/schema-completion.d.mts +25 -0
  9. package/dist/completion/schema-completion.mjs +181 -0
  10. package/dist/completion/tree-context.cjs +108 -0
  11. package/dist/completion/tree-context.mjs +108 -0
  12. package/dist/editor/create-editor.cjs +16 -0
  13. package/dist/editor/create-editor.d.cts +7 -0
  14. package/dist/editor/create-editor.d.mts +7 -0
  15. package/dist/editor/create-editor.mjs +16 -0
  16. package/dist/editor/editor-config.cjs +49 -0
  17. package/dist/editor/editor-config.d.cts +7 -0
  18. package/dist/editor/editor-config.d.mts +7 -0
  19. package/dist/editor/editor-config.mjs +49 -0
  20. package/dist/editor/index.cjs +3 -0
  21. package/dist/editor/index.d.cts +6 -0
  22. package/dist/editor/index.d.mts +6 -0
  23. package/dist/editor/index.mjs +4 -0
  24. package/dist/editor/theme.cjs +35 -0
  25. package/dist/editor/theme.d.cts +7 -0
  26. package/dist/editor/theme.d.mts +7 -0
  27. package/dist/editor/theme.mjs +34 -0
  28. package/dist/editor/type-display.cjs +71 -0
  29. package/dist/editor/type-display.mjs +71 -0
  30. package/dist/editor/types.d.cts +31 -0
  31. package/dist/editor/types.d.mts +31 -0
  32. package/dist/index.cjs +20 -0
  33. package/dist/index.d.cts +10 -0
  34. package/dist/index.d.mts +10 -0
  35. package/dist/index.mjs +11 -0
  36. package/dist/language/semantic-highlighter.cjs +55 -0
  37. package/dist/language/semantic-highlighter.mjs +55 -0
  38. package/dist/language/tokenizer-config.cjs +9 -0
  39. package/dist/language/tokenizer-config.d.cts +12 -0
  40. package/dist/language/tokenizer-config.d.mts +12 -0
  41. package/dist/language/tokenizer-config.mjs +9 -0
  42. package/dist/linting/diagnostic-mapper.cjs +37 -0
  43. package/dist/linting/{diagnostic-mapper.d.ts → diagnostic-mapper.d.cts} +7 -6
  44. package/dist/linting/diagnostic-mapper.d.mts +29 -0
  45. package/dist/linting/diagnostic-mapper.mjs +37 -0
  46. package/dist/linting/index.cjs +2 -0
  47. package/dist/linting/index.d.mts +2 -0
  48. package/dist/linting/index.mjs +3 -0
  49. package/dist/linting/sel-linter.cjs +28 -0
  50. package/dist/linting/sel-linter.d.cts +13 -0
  51. package/dist/linting/sel-linter.d.mts +13 -0
  52. package/dist/linting/sel-linter.mjs +28 -0
  53. package/package.json +29 -22
  54. package/dist/completion/completion-items.d.ts +0 -8
  55. package/dist/completion/completion-items.d.ts.map +0 -1
  56. package/dist/completion/completion-items.js +0 -29
  57. package/dist/completion/index.d.ts +0 -2
  58. package/dist/completion/index.d.ts.map +0 -1
  59. package/dist/completion/index.js +0 -1
  60. package/dist/completion/schema-completion.d.ts +0 -22
  61. package/dist/completion/schema-completion.d.ts.map +0 -1
  62. package/dist/completion/schema-completion.js +0 -220
  63. package/dist/completion/tree-context.d.ts +0 -23
  64. package/dist/completion/tree-context.d.ts.map +0 -1
  65. package/dist/completion/tree-context.js +0 -154
  66. package/dist/editor/create-editor.d.ts +0 -4
  67. package/dist/editor/create-editor.d.ts.map +0 -1
  68. package/dist/editor/create-editor.js +0 -14
  69. package/dist/editor/editor-config.d.ts +0 -4
  70. package/dist/editor/editor-config.d.ts.map +0 -1
  71. package/dist/editor/editor-config.js +0 -64
  72. package/dist/editor/index.d.ts +0 -6
  73. package/dist/editor/index.d.ts.map +0 -1
  74. package/dist/editor/index.js +0 -3
  75. package/dist/editor/theme.d.ts +0 -3
  76. package/dist/editor/theme.d.ts.map +0 -1
  77. package/dist/editor/theme.js +0 -43
  78. package/dist/editor/type-display.d.ts +0 -4
  79. package/dist/editor/type-display.d.ts.map +0 -1
  80. package/dist/editor/type-display.js +0 -75
  81. package/dist/editor/types.d.ts +0 -28
  82. package/dist/editor/types.d.ts.map +0 -1
  83. package/dist/editor/types.js +0 -1
  84. package/dist/index.d.ts +0 -5
  85. package/dist/index.d.ts.map +0 -1
  86. package/dist/index.js +0 -4
  87. package/dist/language/index.d.ts +0 -2
  88. package/dist/language/index.d.ts.map +0 -1
  89. package/dist/language/index.js +0 -1
  90. package/dist/language/semantic-highlighter.d.ts +0 -4
  91. package/dist/language/semantic-highlighter.d.ts.map +0 -1
  92. package/dist/language/semantic-highlighter.js +0 -76
  93. package/dist/language/tokenizer-config.d.ts +0 -9
  94. package/dist/language/tokenizer-config.d.ts.map +0 -1
  95. package/dist/language/tokenizer-config.js +0 -6
  96. package/dist/linting/diagnostic-mapper.d.ts.map +0 -1
  97. package/dist/linting/diagnostic-mapper.js +0 -46
  98. package/dist/linting/index.d.ts +0 -3
  99. package/dist/linting/index.d.ts.map +0 -1
  100. package/dist/linting/index.js +0 -2
  101. package/dist/linting/sel-linter.d.ts +0 -12
  102. package/dist/linting/sel-linter.d.ts.map +0 -1
  103. package/dist/linting/sel-linter.js +0 -28
@@ -0,0 +1,36 @@
1
+ //#region src/completion/completion-items.ts
2
+ const createContractCompletions = (contracts) => contracts.map((c) => ({
3
+ label: c.name,
4
+ type: "class",
5
+ detail: c.description
6
+ }));
7
+ const createMethodCompletions = (contract) => contract.methods.map((m) => ({
8
+ label: m.name,
9
+ type: "method",
10
+ detail: `(${m.params.map((p) => `${p.name}: ${p.type}`).join(", ")}): ${m.returns}`,
11
+ info: m.description
12
+ }));
13
+ const createFunctionCompletions = (functions) => functions.map((f) => ({
14
+ label: f.name,
15
+ type: "function",
16
+ detail: f.signature,
17
+ info: f.description
18
+ }));
19
+ const createMacroCompletions = (macros) => macros.map((m) => ({
20
+ label: m.name,
21
+ type: "keyword",
22
+ detail: m.pattern,
23
+ info: m.description
24
+ }));
25
+ const createVariableCompletions = (variables) => variables.map((v) => ({
26
+ label: v.name,
27
+ type: "variable",
28
+ detail: v.type,
29
+ info: v.description
30
+ }));
31
+ //#endregion
32
+ exports.createContractCompletions = createContractCompletions;
33
+ exports.createFunctionCompletions = createFunctionCompletions;
34
+ exports.createMacroCompletions = createMacroCompletions;
35
+ exports.createMethodCompletions = createMethodCompletions;
36
+ exports.createVariableCompletions = createVariableCompletions;
@@ -0,0 +1,32 @@
1
+ //#region src/completion/completion-items.ts
2
+ const createContractCompletions = (contracts) => contracts.map((c) => ({
3
+ label: c.name,
4
+ type: "class",
5
+ detail: c.description
6
+ }));
7
+ const createMethodCompletions = (contract) => contract.methods.map((m) => ({
8
+ label: m.name,
9
+ type: "method",
10
+ detail: `(${m.params.map((p) => `${p.name}: ${p.type}`).join(", ")}): ${m.returns}`,
11
+ info: m.description
12
+ }));
13
+ const createFunctionCompletions = (functions) => functions.map((f) => ({
14
+ label: f.name,
15
+ type: "function",
16
+ detail: f.signature,
17
+ info: f.description
18
+ }));
19
+ const createMacroCompletions = (macros) => macros.map((m) => ({
20
+ label: m.name,
21
+ type: "keyword",
22
+ detail: m.pattern,
23
+ info: m.description
24
+ }));
25
+ const createVariableCompletions = (variables) => variables.map((v) => ({
26
+ label: v.name,
27
+ type: "variable",
28
+ detail: v.type,
29
+ info: v.description
30
+ }));
31
+ //#endregion
32
+ export { createContractCompletions, createFunctionCompletions, createMacroCompletions, createMethodCompletions, createVariableCompletions };
@@ -0,0 +1 @@
1
+ require("./schema-completion.cjs");
@@ -0,0 +1 @@
1
+ import { SchemaCompletionProvider, createSchemaCompletion } from "./schema-completion.mjs";
@@ -0,0 +1,2 @@
1
+ import "./schema-completion.mjs";
2
+ export {};
@@ -0,0 +1,182 @@
1
+ const require_completion_items = require("./completion-items.cjs");
2
+ const require_tree_context = require("./tree-context.cjs");
3
+ let _codemirror_autocomplete = require("@codemirror/autocomplete");
4
+ let _seljs_checker = require("@seljs/checker");
5
+ //#region src/completion/schema-completion.ts
6
+ /**
7
+ * Determine the CodeMirror completion type from a checker CompletionItem.
8
+ * Method details start with "(" (e.g., "(owner: sol_address): sol_int"),
9
+ * while struct field details are plain type names (e.g., "sol_int").
10
+ */
11
+ const completionKind = (item) => item.detail?.startsWith("(") ? "method" : "property";
12
+ var SchemaCompletionProvider = class {
13
+ topLevelCompletions;
14
+ allDotCompletions;
15
+ checker;
16
+ constructor(schema, checker) {
17
+ this.checker = checker;
18
+ const contractCompletions = require_completion_items.createContractCompletions(schema.contracts);
19
+ const variableCompletions = require_completion_items.createVariableCompletions(schema.variables);
20
+ const functionCompletions = require_completion_items.createFunctionCompletions(schema.functions.filter((f) => !f.receiverType));
21
+ const macroCompletions = require_completion_items.createMacroCompletions(schema.macros);
22
+ const atomCompletions = [
23
+ {
24
+ label: "true",
25
+ type: "keyword"
26
+ },
27
+ {
28
+ label: "false",
29
+ type: "keyword"
30
+ },
31
+ {
32
+ label: "null",
33
+ type: "keyword"
34
+ }
35
+ ];
36
+ this.topLevelCompletions = [
37
+ ...contractCompletions,
38
+ ...variableCompletions,
39
+ ...functionCompletions,
40
+ ...atomCompletions
41
+ ];
42
+ const allMethods = [];
43
+ for (const contract of schema.contracts) allMethods.push(...require_completion_items.createMethodCompletions(contract));
44
+ const structFields = [];
45
+ for (const type of schema.types) if (type.kind === "struct" && type.fields) for (const field of type.fields) structFields.push({
46
+ label: field.name,
47
+ type: "property",
48
+ detail: field.type,
49
+ info: field.description
50
+ });
51
+ const receiverMethods = [];
52
+ for (const fn of schema.functions) if (fn.receiverType) receiverMethods.push({
53
+ label: fn.name,
54
+ type: "method",
55
+ detail: fn.signature,
56
+ info: fn.description
57
+ });
58
+ this.allDotCompletions = [
59
+ ...allMethods,
60
+ ...macroCompletions,
61
+ ...structFields,
62
+ ...receiverMethods
63
+ ];
64
+ }
65
+ completionSource = (context) => {
66
+ const treeCtx = require_tree_context.getCompletionContext(context.state, context.pos);
67
+ switch (treeCtx.kind) {
68
+ case "dot-access": return this.handleDotAccess(context, treeCtx);
69
+ case "call-arg": return this.handleCallArg(context, treeCtx);
70
+ case "top-level": return this.handleTopLevel(context, treeCtx);
71
+ }
72
+ };
73
+ handleDotAccess(context, treeCtx) {
74
+ const { receiverText, from } = treeCtx;
75
+ if (/^\d+$/.test(receiverText)) return this.handleTopLevel(context, {
76
+ kind: "top-level",
77
+ from
78
+ });
79
+ const info = this.checker.dotCompletions(receiverText);
80
+ if (info.items.length > 0) return {
81
+ from,
82
+ options: info.items.map((item) => ({
83
+ label: item.label,
84
+ type: completionKind(item),
85
+ detail: item.detail,
86
+ info: item.description
87
+ })),
88
+ filter: true
89
+ };
90
+ if (info.receiverType !== receiverText) return null;
91
+ return this.allDotCompletions.length ? {
92
+ from,
93
+ options: this.allDotCompletions,
94
+ filter: true
95
+ } : null;
96
+ }
97
+ handleCallArg(context, treeCtx) {
98
+ const expectedType = this.checker.expectedTypeFor({
99
+ kind: "function-arg",
100
+ functionName: treeCtx.functionName,
101
+ receiverName: treeCtx.receiverName,
102
+ paramIndex: treeCtx.paramIndex
103
+ });
104
+ if (expectedType) {
105
+ const filtered = this.topLevelCompletions.filter((c) => {
106
+ if (c.type === "keyword") {
107
+ if (c.label === "null") return true;
108
+ if (c.label === "true" || c.label === "false") return (0, _seljs_checker.isTypeCompatible)("bool", expectedType);
109
+ }
110
+ if (c.type === "variable" && c.detail) return (0, _seljs_checker.isTypeCompatible)(c.detail, expectedType);
111
+ if (c.type === "class" && c.label) return (0, _seljs_checker.isTypeCompatible)(`SEL_Contract_${c.label}`, expectedType);
112
+ return true;
113
+ });
114
+ if (filtered.length > 0) return {
115
+ from: context.matchBefore(/\w+/)?.from ?? treeCtx.from,
116
+ options: filtered,
117
+ filter: true
118
+ };
119
+ }
120
+ return this.handleTopLevel(context, {
121
+ kind: "top-level",
122
+ from: treeCtx.from
123
+ });
124
+ }
125
+ handleTopLevel(context, treeCtx) {
126
+ const wordMatch = context.matchBefore(/\w+/);
127
+ const from = wordMatch?.from ?? treeCtx.from;
128
+ const hasText = !!wordMatch;
129
+ const narrowed = this.narrowByExpectedType(context, from);
130
+ if (narrowed && narrowed.length > 0) return {
131
+ from,
132
+ options: narrowed,
133
+ filter: true
134
+ };
135
+ if (hasText) return this.topLevelCompletions.length ? {
136
+ from,
137
+ options: this.topLevelCompletions,
138
+ filter: true
139
+ } : null;
140
+ if (context.explicit && this.topLevelCompletions.length) return {
141
+ from: context.pos,
142
+ options: this.topLevelCompletions,
143
+ filter: true
144
+ };
145
+ return null;
146
+ }
147
+ /**
148
+ * Use the checker to infer the expected type at cursor position
149
+ * and filter completions to only type-compatible items.
150
+ * Returns undefined when narrowing is not possible.
151
+ */
152
+ narrowByExpectedType(context, from) {
153
+ const doc = context.state.doc.toString();
154
+ const info = this.checker.completionsAt(doc, from);
155
+ if (!info.expectedType) return;
156
+ const expectedType = info.expectedType;
157
+ const filtered = info.items.filter((item) => (0, _seljs_checker.isTypeCompatible)(item.type, expectedType)).map((item) => ({
158
+ label: item.label,
159
+ type: item.type.startsWith("SEL_Contract_") ? "class" : item.detail ? "function" : "variable",
160
+ detail: item.detail ?? item.type,
161
+ info: item.description
162
+ }));
163
+ if ((0, _seljs_checker.isTypeCompatible)("bool", expectedType)) filtered.push({
164
+ label: "true",
165
+ type: "keyword"
166
+ }, {
167
+ label: "false",
168
+ type: "keyword"
169
+ });
170
+ filtered.push({
171
+ label: "null",
172
+ type: "keyword"
173
+ });
174
+ return filtered.length > 0 ? filtered : void 0;
175
+ }
176
+ };
177
+ const createSchemaCompletion = (schema, checker) => {
178
+ return (0, _codemirror_autocomplete.autocompletion)({ override: [new SchemaCompletionProvider(schema, checker).completionSource] });
179
+ };
180
+ //#endregion
181
+ exports.SchemaCompletionProvider = SchemaCompletionProvider;
182
+ exports.createSchemaCompletion = createSchemaCompletion;
@@ -0,0 +1,25 @@
1
+ import { SELSchema } from "@seljs/schema";
2
+ import { CompletionContext, CompletionResult } from "@codemirror/autocomplete";
3
+ import { Extension } from "@codemirror/state";
4
+ import { SELChecker } from "@seljs/checker";
5
+
6
+ //#region src/completion/schema-completion.d.ts
7
+ declare class SchemaCompletionProvider {
8
+ private topLevelCompletions;
9
+ private allDotCompletions;
10
+ private checker;
11
+ constructor(schema: SELSchema, checker: SELChecker);
12
+ completionSource: (context: CompletionContext) => CompletionResult | null;
13
+ private handleDotAccess;
14
+ private handleCallArg;
15
+ private handleTopLevel;
16
+ /**
17
+ * Use the checker to infer the expected type at cursor position
18
+ * and filter completions to only type-compatible items.
19
+ * Returns undefined when narrowing is not possible.
20
+ */
21
+ private narrowByExpectedType;
22
+ }
23
+ declare const createSchemaCompletion: (schema: SELSchema, checker: SELChecker) => Extension;
24
+ //#endregion
25
+ export { SchemaCompletionProvider, createSchemaCompletion };
@@ -0,0 +1,25 @@
1
+ import { CompletionContext, CompletionResult } from "@codemirror/autocomplete";
2
+ import { SELChecker } from "@seljs/checker";
3
+ import { Extension } from "@codemirror/state";
4
+ import { SELSchema } from "@seljs/schema";
5
+
6
+ //#region src/completion/schema-completion.d.ts
7
+ declare class SchemaCompletionProvider {
8
+ private topLevelCompletions;
9
+ private allDotCompletions;
10
+ private checker;
11
+ constructor(schema: SELSchema, checker: SELChecker);
12
+ completionSource: (context: CompletionContext) => CompletionResult | null;
13
+ private handleDotAccess;
14
+ private handleCallArg;
15
+ private handleTopLevel;
16
+ /**
17
+ * Use the checker to infer the expected type at cursor position
18
+ * and filter completions to only type-compatible items.
19
+ * Returns undefined when narrowing is not possible.
20
+ */
21
+ private narrowByExpectedType;
22
+ }
23
+ declare const createSchemaCompletion: (schema: SELSchema, checker: SELChecker) => Extension;
24
+ //#endregion
25
+ export { SchemaCompletionProvider, createSchemaCompletion };
@@ -0,0 +1,181 @@
1
+ import { createContractCompletions, createFunctionCompletions, createMacroCompletions, createMethodCompletions, createVariableCompletions } from "./completion-items.mjs";
2
+ import { getCompletionContext } from "./tree-context.mjs";
3
+ import { autocompletion } from "@codemirror/autocomplete";
4
+ import { isTypeCompatible } from "@seljs/checker";
5
+ //#region src/completion/schema-completion.ts
6
+ /**
7
+ * Determine the CodeMirror completion type from a checker CompletionItem.
8
+ * Method details start with "(" (e.g., "(owner: sol_address): sol_int"),
9
+ * while struct field details are plain type names (e.g., "sol_int").
10
+ */
11
+ const completionKind = (item) => item.detail?.startsWith("(") ? "method" : "property";
12
+ var SchemaCompletionProvider = class {
13
+ topLevelCompletions;
14
+ allDotCompletions;
15
+ checker;
16
+ constructor(schema, checker) {
17
+ this.checker = checker;
18
+ const contractCompletions = createContractCompletions(schema.contracts);
19
+ const variableCompletions = createVariableCompletions(schema.variables);
20
+ const functionCompletions = createFunctionCompletions(schema.functions.filter((f) => !f.receiverType));
21
+ const macroCompletions = createMacroCompletions(schema.macros);
22
+ const atomCompletions = [
23
+ {
24
+ label: "true",
25
+ type: "keyword"
26
+ },
27
+ {
28
+ label: "false",
29
+ type: "keyword"
30
+ },
31
+ {
32
+ label: "null",
33
+ type: "keyword"
34
+ }
35
+ ];
36
+ this.topLevelCompletions = [
37
+ ...contractCompletions,
38
+ ...variableCompletions,
39
+ ...functionCompletions,
40
+ ...atomCompletions
41
+ ];
42
+ const allMethods = [];
43
+ for (const contract of schema.contracts) allMethods.push(...createMethodCompletions(contract));
44
+ const structFields = [];
45
+ for (const type of schema.types) if (type.kind === "struct" && type.fields) for (const field of type.fields) structFields.push({
46
+ label: field.name,
47
+ type: "property",
48
+ detail: field.type,
49
+ info: field.description
50
+ });
51
+ const receiverMethods = [];
52
+ for (const fn of schema.functions) if (fn.receiverType) receiverMethods.push({
53
+ label: fn.name,
54
+ type: "method",
55
+ detail: fn.signature,
56
+ info: fn.description
57
+ });
58
+ this.allDotCompletions = [
59
+ ...allMethods,
60
+ ...macroCompletions,
61
+ ...structFields,
62
+ ...receiverMethods
63
+ ];
64
+ }
65
+ completionSource = (context) => {
66
+ const treeCtx = getCompletionContext(context.state, context.pos);
67
+ switch (treeCtx.kind) {
68
+ case "dot-access": return this.handleDotAccess(context, treeCtx);
69
+ case "call-arg": return this.handleCallArg(context, treeCtx);
70
+ case "top-level": return this.handleTopLevel(context, treeCtx);
71
+ }
72
+ };
73
+ handleDotAccess(context, treeCtx) {
74
+ const { receiverText, from } = treeCtx;
75
+ if (/^\d+$/.test(receiverText)) return this.handleTopLevel(context, {
76
+ kind: "top-level",
77
+ from
78
+ });
79
+ const info = this.checker.dotCompletions(receiverText);
80
+ if (info.items.length > 0) return {
81
+ from,
82
+ options: info.items.map((item) => ({
83
+ label: item.label,
84
+ type: completionKind(item),
85
+ detail: item.detail,
86
+ info: item.description
87
+ })),
88
+ filter: true
89
+ };
90
+ if (info.receiverType !== receiverText) return null;
91
+ return this.allDotCompletions.length ? {
92
+ from,
93
+ options: this.allDotCompletions,
94
+ filter: true
95
+ } : null;
96
+ }
97
+ handleCallArg(context, treeCtx) {
98
+ const expectedType = this.checker.expectedTypeFor({
99
+ kind: "function-arg",
100
+ functionName: treeCtx.functionName,
101
+ receiverName: treeCtx.receiverName,
102
+ paramIndex: treeCtx.paramIndex
103
+ });
104
+ if (expectedType) {
105
+ const filtered = this.topLevelCompletions.filter((c) => {
106
+ if (c.type === "keyword") {
107
+ if (c.label === "null") return true;
108
+ if (c.label === "true" || c.label === "false") return isTypeCompatible("bool", expectedType);
109
+ }
110
+ if (c.type === "variable" && c.detail) return isTypeCompatible(c.detail, expectedType);
111
+ if (c.type === "class" && c.label) return isTypeCompatible(`SEL_Contract_${c.label}`, expectedType);
112
+ return true;
113
+ });
114
+ if (filtered.length > 0) return {
115
+ from: context.matchBefore(/\w+/)?.from ?? treeCtx.from,
116
+ options: filtered,
117
+ filter: true
118
+ };
119
+ }
120
+ return this.handleTopLevel(context, {
121
+ kind: "top-level",
122
+ from: treeCtx.from
123
+ });
124
+ }
125
+ handleTopLevel(context, treeCtx) {
126
+ const wordMatch = context.matchBefore(/\w+/);
127
+ const from = wordMatch?.from ?? treeCtx.from;
128
+ const hasText = !!wordMatch;
129
+ const narrowed = this.narrowByExpectedType(context, from);
130
+ if (narrowed && narrowed.length > 0) return {
131
+ from,
132
+ options: narrowed,
133
+ filter: true
134
+ };
135
+ if (hasText) return this.topLevelCompletions.length ? {
136
+ from,
137
+ options: this.topLevelCompletions,
138
+ filter: true
139
+ } : null;
140
+ if (context.explicit && this.topLevelCompletions.length) return {
141
+ from: context.pos,
142
+ options: this.topLevelCompletions,
143
+ filter: true
144
+ };
145
+ return null;
146
+ }
147
+ /**
148
+ * Use the checker to infer the expected type at cursor position
149
+ * and filter completions to only type-compatible items.
150
+ * Returns undefined when narrowing is not possible.
151
+ */
152
+ narrowByExpectedType(context, from) {
153
+ const doc = context.state.doc.toString();
154
+ const info = this.checker.completionsAt(doc, from);
155
+ if (!info.expectedType) return;
156
+ const expectedType = info.expectedType;
157
+ const filtered = info.items.filter((item) => isTypeCompatible(item.type, expectedType)).map((item) => ({
158
+ label: item.label,
159
+ type: item.type.startsWith("SEL_Contract_") ? "class" : item.detail ? "function" : "variable",
160
+ detail: item.detail ?? item.type,
161
+ info: item.description
162
+ }));
163
+ if (isTypeCompatible("bool", expectedType)) filtered.push({
164
+ label: "true",
165
+ type: "keyword"
166
+ }, {
167
+ label: "false",
168
+ type: "keyword"
169
+ });
170
+ filtered.push({
171
+ label: "null",
172
+ type: "keyword"
173
+ });
174
+ return filtered.length > 0 ? filtered : void 0;
175
+ }
176
+ };
177
+ const createSchemaCompletion = (schema, checker) => {
178
+ return autocompletion({ override: [new SchemaCompletionProvider(schema, checker).completionSource] });
179
+ };
180
+ //#endregion
181
+ export { SchemaCompletionProvider, createSchemaCompletion };
@@ -0,0 +1,108 @@
1
+ let _codemirror_language = require("@codemirror/language");
2
+ //#region src/completion/tree-context.ts
3
+ /**
4
+ * Walk up the tree looking for a MemberExpression ancestor.
5
+ * A MemberExpression has two Identifier children (or child nodes) separated by ".".
6
+ * The dot position is: firstChild.to + 1 (the "." character is between them).
7
+ * We are in dot-access context when pos >= dotPos.
8
+ */
9
+ const findDotAccess = (state, node, pos) => {
10
+ let current = node;
11
+ while (current) {
12
+ if (current.name === "ArgList") break;
13
+ if (current.name === "MemberExpression" || current.name === "OptionalExpression") {
14
+ const firstChild = current.firstChild;
15
+ if (firstChild) {
16
+ const dotPos = firstChild.to + 1;
17
+ if (pos >= dotPos) return {
18
+ kind: "dot-access",
19
+ receiverText: state.doc.sliceString(current.from, firstChild.to),
20
+ from: dotPos
21
+ };
22
+ }
23
+ }
24
+ current = current.parent;
25
+ }
26
+ };
27
+ /**
28
+ * Count commas in ArgList text that appear before pos.
29
+ * Commas are anonymous tokens not exposed as named children,
30
+ * so we scan the raw source text.
31
+ */
32
+ const countCommasBefore = (argList, state, pos) => {
33
+ const open = argList.from + 1;
34
+ const end = Math.min(pos, argList.to);
35
+ const text = state.doc.sliceString(open, end);
36
+ let count = 0;
37
+ for (const ch of text) if (ch === ",") count++;
38
+ return count;
39
+ };
40
+ /**
41
+ * Extract function name and optional receiver name from a CallExpression node.
42
+ *
43
+ * Tree shapes:
44
+ * foo(...) → CallExpression > Identifier, ArgList
45
+ * erc20.foo(...) → CallExpression > MemberExpression(Identifier "erc20", Identifier "foo"), ArgList
46
+ */
47
+ const extractCallInfo = (state, callExpr) => {
48
+ const callee = callExpr.firstChild;
49
+ if (!callee) return;
50
+ if (callee.name === "Identifier") return { functionName: state.doc.sliceString(callee.from, callee.to) };
51
+ if (callee.name === "MemberExpression") {
52
+ const lastChild = callee.lastChild;
53
+ if (lastChild?.name === "Identifier") {
54
+ const functionName = state.doc.sliceString(lastChild.from, lastChild.to);
55
+ const receiverNode = callee.firstChild;
56
+ return {
57
+ functionName,
58
+ receiverName: receiverNode?.name === "Identifier" ? state.doc.sliceString(receiverNode.from, receiverNode.to) : void 0
59
+ };
60
+ }
61
+ }
62
+ };
63
+ const findWordStart = (state, pos) => {
64
+ const text = state.doc.sliceString(0, pos);
65
+ const match = /\w+$/.exec(text);
66
+ return match ? pos - match[0].length : pos;
67
+ };
68
+ /**
69
+ * Walk up the tree looking for an ArgList ancestor.
70
+ * When found, count commas before pos to get paramIndex,
71
+ * then extract function name and optional receiver from the CallExpression.
72
+ */
73
+ const findCallArg = (state, node, pos) => {
74
+ let current = node;
75
+ while (current) {
76
+ if (current.name === "ArgList") {
77
+ const paramIndex = countCommasBefore(current, state, pos);
78
+ const callExpr = current.parent;
79
+ if (callExpr?.name === "CallExpression") {
80
+ const info = extractCallInfo(state, callExpr);
81
+ if (info) return {
82
+ kind: "call-arg",
83
+ functionName: info.functionName,
84
+ receiverName: info.receiverName,
85
+ paramIndex,
86
+ from: pos
87
+ };
88
+ }
89
+ }
90
+ current = current.parent;
91
+ }
92
+ };
93
+ /**
94
+ * Extract completion context from the Lezer syntax tree at the given position.
95
+ */
96
+ const getCompletionContext = (state, pos) => {
97
+ const node = (0, _codemirror_language.syntaxTree)(state).resolveInner(pos, -1);
98
+ const dotAccess = findDotAccess(state, node, pos);
99
+ if (dotAccess) return dotAccess;
100
+ const callArg = findCallArg(state, node, pos);
101
+ if (callArg) return callArg;
102
+ return {
103
+ kind: "top-level",
104
+ from: findWordStart(state, pos)
105
+ };
106
+ };
107
+ //#endregion
108
+ exports.getCompletionContext = getCompletionContext;