@ripple-ts/language-server 0.2.192 → 0.2.193
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.
- package/package.json +3 -3
- package/src/autoInsertPlugin.js +1 -1
- package/src/compileErrorDiagnosticPlugin.js +115 -132
- package/src/completionPlugin.js +1 -1
- package/src/definitionPlugin.js +1 -1
- package/src/documentHighlightPlugin.js +1 -1
- package/src/hoverPlugin.js +1 -1
- package/src/typescriptDiagnosticPlugin.js +7 -2
- package/src/utils.js +12 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ripple-ts/language-server",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.193",
|
|
4
4
|
"description": "Language Server Protocol implementation for Ripple",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -19,10 +19,10 @@
|
|
|
19
19
|
"volar-service-typescript": "0.0.65",
|
|
20
20
|
"vscode-languageserver-textdocument": "^1.0.12",
|
|
21
21
|
"vscode-uri": "^3.1.0",
|
|
22
|
-
"@ripple-ts/typescript-plugin": "0.2.
|
|
22
|
+
"@ripple-ts/typescript-plugin": "0.2.193"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
|
-
"ripple": "0.2.
|
|
25
|
+
"ripple": "0.2.193"
|
|
26
26
|
},
|
|
27
27
|
"peerDependencies": {
|
|
28
28
|
"typescript": "^5.9.2"
|
package/src/autoInsertPlugin.js
CHANGED
|
@@ -64,7 +64,7 @@ function createAutoInsertPlugin() {
|
|
|
64
64
|
return null;
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
const
|
|
67
|
+
const { virtualCode } = getVirtualCode(document, context);
|
|
68
68
|
|
|
69
69
|
if (virtualCode.languageId !== 'ripple') {
|
|
70
70
|
log(`Skipping auto-insert processing in the '${virtualCode.languageId}' context`);
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @import {Diagnostic, LanguageServicePlugin, LanguageServiceContext} from '@volar/language-server'
|
|
3
|
-
* @import {TextDocument} from 'vscode-languageserver-textdocument'
|
|
2
|
+
* @import {Diagnostic, Range, LanguageServicePlugin, LanguageServiceContext, Position, Mapper} from '@volar/language-server';
|
|
3
|
+
* @import {TextDocument} from 'vscode-languageserver-textdocument';
|
|
4
|
+
* @import {RippleVirtualCode} from '@ripple-ts/typescript-plugin/src/language.js';
|
|
4
5
|
*/
|
|
6
|
+
// @ts-expect-error: ESM type import is fine
|
|
7
|
+
/** @import {RippleCompileError} from 'ripple/compiler'; */
|
|
5
8
|
|
|
6
9
|
const { getVirtualCode, createLogging } = require('./utils.js');
|
|
7
10
|
|
|
8
|
-
const { log
|
|
11
|
+
const { log } = createLogging('[Ripple Compile Error Diagnostic Plugin]');
|
|
9
12
|
const { DiagnosticSeverity } = require('@volar/language-server');
|
|
10
13
|
|
|
11
14
|
/**
|
|
@@ -25,154 +28,134 @@ function createCompileErrorDiagnosticPlugin() {
|
|
|
25
28
|
create(/** @type {LanguageServiceContext} */ context) {
|
|
26
29
|
return {
|
|
27
30
|
provideDiagnostics(document, _token) {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
// Convert each stored error to a diagnostic
|
|
42
|
-
for (const error of virtualCode.errors) {
|
|
43
|
-
try {
|
|
44
|
-
// Use the actual snapshot text that Volar is working with
|
|
45
|
-
const snapshotText = virtualCode.snapshot.getText(
|
|
46
|
-
0,
|
|
47
|
-
virtualCode.snapshot.getLength(),
|
|
48
|
-
);
|
|
49
|
-
const diagnostic = parseCompilationErrorWithDocument(
|
|
50
|
-
error,
|
|
51
|
-
virtualCode.fileName,
|
|
52
|
-
snapshotText,
|
|
53
|
-
document,
|
|
54
|
-
);
|
|
55
|
-
diagnostics.push(diagnostic);
|
|
56
|
-
} catch (parseError) {
|
|
57
|
-
logError('Failed to parse compilation error:', parseError);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
log('Generated', diagnostics.length, 'diagnostics');
|
|
31
|
+
log('Providing Ripple diagnostics for:', document.uri);
|
|
32
|
+
|
|
33
|
+
/** @type {Diagnostic[]} */
|
|
34
|
+
const diagnostics = [];
|
|
35
|
+
const { virtualCode, sourceMap } = getVirtualCode(document, context);
|
|
36
|
+
|
|
37
|
+
if (!virtualCode || virtualCode.languageId !== 'ripple') {
|
|
38
|
+
// skip if it's like embedded css
|
|
39
|
+
return diagnostics;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (!virtualCode.fatalErrors.length && !virtualCode.usageErrors.length) {
|
|
62
43
|
return diagnostics;
|
|
63
|
-
} catch (err) {
|
|
64
|
-
logError('Failed to provide diagnostics:', err);
|
|
65
|
-
return [];
|
|
66
44
|
}
|
|
45
|
+
|
|
46
|
+
for (const error of [...virtualCode.fatalErrors, ...virtualCode.usageErrors]) {
|
|
47
|
+
const diagnostic = parseCompilationErrorWithDocument(
|
|
48
|
+
error,
|
|
49
|
+
virtualCode,
|
|
50
|
+
sourceMap,
|
|
51
|
+
document,
|
|
52
|
+
);
|
|
53
|
+
diagnostics.push(diagnostic);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
log('Generated', diagnostics.length, 'diagnostics');
|
|
57
|
+
return diagnostics;
|
|
67
58
|
},
|
|
68
59
|
};
|
|
69
60
|
},
|
|
70
61
|
};
|
|
71
62
|
}
|
|
72
63
|
|
|
73
|
-
// Helper function to parse compilation errors using document.positionAt (Glint style)
|
|
74
64
|
/**
|
|
75
|
-
* @param {
|
|
76
|
-
* @param {
|
|
77
|
-
* @param {
|
|
65
|
+
* @param {RippleCompileError} error
|
|
66
|
+
* @param {RippleVirtualCode} virtualCode
|
|
67
|
+
* @param {Mapper | undefined} sourceMap
|
|
78
68
|
* @param {TextDocument} document
|
|
79
69
|
* @returns {Diagnostic}
|
|
80
70
|
*/
|
|
81
|
-
function parseCompilationErrorWithDocument(error,
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
// Use the GitHub range data directly
|
|
92
|
-
const startLine = parseInt(githubRangeMatch[2]);
|
|
93
|
-
const startColumn = parseInt(githubRangeMatch[3]);
|
|
94
|
-
const endLine = parseInt(githubRangeMatch[4]);
|
|
95
|
-
const endColumn = parseInt(githubRangeMatch[5]);
|
|
96
|
-
|
|
97
|
-
// Convert to zero-based
|
|
98
|
-
const zeroBasedStartLine = Math.max(0, startLine - 1);
|
|
99
|
-
const zeroBasedStartColumn = Math.max(0, startColumn);
|
|
100
|
-
const zeroBasedEndLine = Math.max(0, endLine - 1);
|
|
101
|
-
const zeroBasedEndColumn = Math.max(0, endColumn);
|
|
71
|
+
function parseCompilationErrorWithDocument(error, virtualCode, sourceMap, document) {
|
|
72
|
+
if (error.type === 'fatal') {
|
|
73
|
+
return {
|
|
74
|
+
severity: DiagnosticSeverity.Error,
|
|
75
|
+
range: get_error_range_from_source(error, document),
|
|
76
|
+
message: error.message,
|
|
77
|
+
source: 'Ripple',
|
|
78
|
+
code: 'ripple-compile-error',
|
|
79
|
+
};
|
|
80
|
+
}
|
|
102
81
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
82
|
+
/** @type {Position | null} */
|
|
83
|
+
let start = null;
|
|
84
|
+
/** @type {Position | null} */
|
|
85
|
+
let end = null;
|
|
86
|
+
|
|
87
|
+
if (error.pos) {
|
|
88
|
+
const start_offset = get_start_offset_from_error(error);
|
|
89
|
+
const end_offset = get_end_offset_from_error(error, start_offset);
|
|
90
|
+
// try to find exact mapping
|
|
91
|
+
// TODO: perhaps it's best to just switch to sourceMap entirely?
|
|
92
|
+
const mapping = virtualCode.findMappingBySourceRange(start_offset, end_offset);
|
|
93
|
+
|
|
94
|
+
if (mapping) {
|
|
95
|
+
start = document.positionAt(mapping.generatedOffsets[0]);
|
|
96
|
+
end = document.positionAt(
|
|
97
|
+
mapping.generatedOffsets[0] +
|
|
98
|
+
(mapping.generatedLengths || mapping.data.customData.generatedLengths)[0],
|
|
99
|
+
);
|
|
100
|
+
} else if (sourceMap) {
|
|
101
|
+
// try to find the match even across multiple mappings
|
|
102
|
+
const result = sourceMap.toGeneratedRange(start_offset, end_offset, true).next().value;
|
|
103
|
+
|
|
104
|
+
if (result) {
|
|
105
|
+
const [gen_start_offset, gen_end_offset] = result;
|
|
106
|
+
start = document.positionAt(gen_start_offset);
|
|
107
|
+
end = document.positionAt(gen_end_offset);
|
|
108
|
+
}
|
|
113
109
|
}
|
|
110
|
+
}
|
|
114
111
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
if (locationMatch) {
|
|
121
|
-
const [, fileName, lineStr, columnStr] = locationMatch;
|
|
122
|
-
const line = parseInt(lineStr, 10);
|
|
123
|
-
const column = parseInt(columnStr, 10);
|
|
124
|
-
|
|
125
|
-
// Extract the main error message (without location)
|
|
126
|
-
const cleanMessage = message.replace(/\s*\([^:]+:\d+:\d+\)$/, '');
|
|
127
|
-
|
|
128
|
-
// Convert 1-based line/column to 0-based for VS Code
|
|
129
|
-
const zeroBasedLine = Math.max(0, line - 1);
|
|
130
|
-
const actualColumn = Math.max(0, column - 1);
|
|
112
|
+
if (!start || !end) {
|
|
113
|
+
start = { line: 0, character: 0 };
|
|
114
|
+
end = { line: 0, character: 1 };
|
|
115
|
+
}
|
|
131
116
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
117
|
+
return {
|
|
118
|
+
severity: DiagnosticSeverity.Error,
|
|
119
|
+
range: { start, end },
|
|
120
|
+
message: error.message,
|
|
121
|
+
source: 'Ripple',
|
|
122
|
+
code: 'ripple-usage-error',
|
|
123
|
+
};
|
|
124
|
+
}
|
|
135
125
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
const startPosition = document.positionAt(0);
|
|
149
|
-
const endPosition = document.positionAt(Math.min(1, sourceText.length));
|
|
126
|
+
/**
|
|
127
|
+
* @param {RippleCompileError} error
|
|
128
|
+
* @param {TextDocument} document
|
|
129
|
+
* @returns {Range}
|
|
130
|
+
*/
|
|
131
|
+
function get_error_range_from_source(error, document) {
|
|
132
|
+
const start_offset = get_start_offset_from_error(error);
|
|
133
|
+
return {
|
|
134
|
+
start: document.positionAt(start_offset),
|
|
135
|
+
end: document.positionAt(get_end_offset_from_error(error, start_offset)),
|
|
136
|
+
};
|
|
137
|
+
}
|
|
150
138
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
139
|
+
/**
|
|
140
|
+
* @param {RippleCompileError} error
|
|
141
|
+
* @param {number} [start_offset]
|
|
142
|
+
* @returns {number}
|
|
143
|
+
*/
|
|
144
|
+
function get_end_offset_from_error(error, start_offset) {
|
|
145
|
+
start_offset = start_offset ?? get_start_offset_from_error(error);
|
|
146
|
+
return error.end
|
|
147
|
+
? error.end
|
|
148
|
+
: error.raisedAt && (error.raisedAt ?? 0) > start_offset
|
|
149
|
+
? error.raisedAt
|
|
150
|
+
: start_offset + 1;
|
|
151
|
+
}
|
|
164
152
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
message: `Ripple compilation error: ${message}`,
|
|
172
|
-
source: 'Ripple',
|
|
173
|
-
code: 'ripple-parse-error',
|
|
174
|
-
};
|
|
175
|
-
}
|
|
153
|
+
/**
|
|
154
|
+
* @param {RippleCompileError} error
|
|
155
|
+
* @returns {number}
|
|
156
|
+
*/
|
|
157
|
+
function get_start_offset_from_error(error) {
|
|
158
|
+
return error.pos ?? 0;
|
|
176
159
|
}
|
|
177
160
|
|
|
178
161
|
module.exports = {
|
package/src/completionPlugin.js
CHANGED
|
@@ -410,7 +410,7 @@ function createCompletionPlugin() {
|
|
|
410
410
|
return { items: [], isIncomplete: false };
|
|
411
411
|
}
|
|
412
412
|
|
|
413
|
-
const
|
|
413
|
+
const { virtualCode } = getVirtualCode(document, context);
|
|
414
414
|
|
|
415
415
|
if (virtualCode.languageId !== 'ripple') {
|
|
416
416
|
// Check if we're inside an embedded code (like CSS in <style> blocks)
|
package/src/definitionPlugin.js
CHANGED
|
@@ -43,7 +43,7 @@ function createDefinitionPlugin() {
|
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
const
|
|
46
|
+
const { virtualCode, sourceUri } = getVirtualCode(document, context);
|
|
47
47
|
|
|
48
48
|
if (virtualCode.languageId !== 'ripple') {
|
|
49
49
|
// like embedded css
|
|
@@ -56,7 +56,7 @@ function createDocumentHighlightPlugin() {
|
|
|
56
56
|
return tsHighlights;
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
const
|
|
59
|
+
const { virtualCode } = getVirtualCode(document, context);
|
|
60
60
|
|
|
61
61
|
if (virtualCode.languageId !== 'ripple') {
|
|
62
62
|
log(`Skipping highlight processing in the '${virtualCode.languageId}' context`);
|
package/src/hoverPlugin.js
CHANGED
|
@@ -35,9 +35,9 @@ function processDiagnostics(document, context, diagnostics) {
|
|
|
35
35
|
|
|
36
36
|
log(`Filtering ${diagnostics.length} TypeScript diagnostics for ${document.uri}`);
|
|
37
37
|
|
|
38
|
-
const
|
|
38
|
+
const { virtualCode } = getVirtualCode(document, context);
|
|
39
39
|
|
|
40
|
-
if (!virtualCode) {
|
|
40
|
+
if (!virtualCode || virtualCode.languageId !== 'ripple') {
|
|
41
41
|
return diagnostics;
|
|
42
42
|
}
|
|
43
43
|
|
|
@@ -45,6 +45,11 @@ function processDiagnostics(document, context, diagnostics) {
|
|
|
45
45
|
const result = [];
|
|
46
46
|
|
|
47
47
|
for (const diagnostic of diagnostics) {
|
|
48
|
+
if (virtualCode.fatalErrors.length > 0 && diagnostic.code !== 'ripple-compile-error') {
|
|
49
|
+
// skip all TS diagnostics since we're dealing directly with the source code
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
|
|
48
53
|
const range = diagnostic.range;
|
|
49
54
|
const rangeStart = document.offsetAt(range.start);
|
|
50
55
|
const rangeEnd = document.offsetAt(range.end);
|
package/src/utils.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** @import { TextDocument } from 'vscode-languageserver-textdocument' */
|
|
2
|
-
/** @import { LanguageServiceContext } from '@volar/language-server' */
|
|
2
|
+
/** @import { LanguageServiceContext, Mapper, SourceScript } from '@volar/language-server' */
|
|
3
3
|
/** @import {RippleVirtualCode} from '@ripple-ts/typescript-plugin/src/language.js' */
|
|
4
4
|
// @ts-expect-error: ESM type import is fine
|
|
5
5
|
/** @import {is_identifier_obfuscated, deobfuscate_identifier, IDENTIFIER_OBFUSCATION_PREFIX} from 'ripple/compiler/internal/identifier/utils' */
|
|
@@ -68,7 +68,13 @@ function concatMarkdownContents(...contents) {
|
|
|
68
68
|
* Get virtual code from the encoded document URI
|
|
69
69
|
* @param {LanguageServiceContext} context
|
|
70
70
|
* @param {TextDocument} document
|
|
71
|
-
* @returns
|
|
71
|
+
* @returns
|
|
72
|
+
{{
|
|
73
|
+
virtualCode: RippleVirtualCode;
|
|
74
|
+
sourceUri: URI;
|
|
75
|
+
sourceScript: SourceScript<URI> | undefined;
|
|
76
|
+
sourceMap: Mapper | undefined;
|
|
77
|
+
}}
|
|
72
78
|
*/
|
|
73
79
|
function getVirtualCode(document, context) {
|
|
74
80
|
const uri = URI.parse(document.uri);
|
|
@@ -81,7 +87,10 @@ function getVirtualCode(document, context) {
|
|
|
81
87
|
sourceScript?.generated?.embeddedCodes.get(virtualCodeId)
|
|
82
88
|
);
|
|
83
89
|
|
|
84
|
-
|
|
90
|
+
const sourceMap =
|
|
91
|
+
sourceScript && virtualCode ? context.language.maps.get(virtualCode, sourceScript) : undefined;
|
|
92
|
+
|
|
93
|
+
return { virtualCode, sourceUri, sourceScript, sourceMap };
|
|
85
94
|
}
|
|
86
95
|
|
|
87
96
|
/**
|