@ripple-ts/language-server 0.2.177 → 0.2.178
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
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ripple-ts/language-server",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.178",
|
|
4
4
|
"description": "Language Server Protocol implementation for Ripple",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -19,7 +19,7 @@
|
|
|
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.178"
|
|
23
23
|
},
|
|
24
24
|
"peerDependencies": {
|
|
25
25
|
"typescript": "^5.9.2"
|
|
@@ -31,7 +31,7 @@ function logError(...args) {
|
|
|
31
31
|
/**
|
|
32
32
|
* @returns {LanguageServicePlugin}
|
|
33
33
|
*/
|
|
34
|
-
function
|
|
34
|
+
function createCompileErrorDiagnosticPlugin() {
|
|
35
35
|
log('Creating Ripple diagnostic plugin...');
|
|
36
36
|
|
|
37
37
|
return {
|
|
@@ -55,37 +55,37 @@ function createDiagnosticPlugin() {
|
|
|
55
55
|
|
|
56
56
|
const info = getEmbeddedInfo(context, document);
|
|
57
57
|
|
|
58
|
-
if (info
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
log('Processing', virtualCode.errors.length, 'errors');
|
|
63
|
-
|
|
64
|
-
// Convert each stored error to a diagnostic
|
|
65
|
-
for (const error of virtualCode.errors) {
|
|
66
|
-
try {
|
|
67
|
-
// Use the actual snapshot text that Volar is working with
|
|
68
|
-
const snapshotText = virtualCode.snapshot.getText(
|
|
69
|
-
0,
|
|
70
|
-
virtualCode.snapshot.getLength(),
|
|
71
|
-
);
|
|
72
|
-
const diagnostic = parseCompilationErrorWithDocument(
|
|
73
|
-
error,
|
|
74
|
-
virtualCode.fileName,
|
|
75
|
-
snapshotText,
|
|
76
|
-
document,
|
|
77
|
-
);
|
|
78
|
-
diagnostics.push(diagnostic);
|
|
79
|
-
} catch (parseError) {
|
|
80
|
-
logError('Failed to parse compilation error:', parseError);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
58
|
+
if (!info || !info.virtualCode.errors || info.virtualCode.errors.length === 0) {
|
|
59
|
+
return [];
|
|
60
|
+
}
|
|
83
61
|
|
|
84
|
-
|
|
85
|
-
|
|
62
|
+
const virtualCode = info.virtualCode;
|
|
63
|
+
const diagnostics = [];
|
|
64
|
+
|
|
65
|
+
log('Processing', virtualCode.errors.length, 'errors');
|
|
66
|
+
|
|
67
|
+
// Convert each stored error to a diagnostic
|
|
68
|
+
for (const error of virtualCode.errors) {
|
|
69
|
+
try {
|
|
70
|
+
// Use the actual snapshot text that Volar is working with
|
|
71
|
+
const snapshotText = virtualCode.snapshot.getText(
|
|
72
|
+
0,
|
|
73
|
+
virtualCode.snapshot.getLength(),
|
|
74
|
+
);
|
|
75
|
+
const diagnostic = parseCompilationErrorWithDocument(
|
|
76
|
+
error,
|
|
77
|
+
virtualCode.fileName,
|
|
78
|
+
snapshotText,
|
|
79
|
+
document,
|
|
80
|
+
);
|
|
81
|
+
diagnostics.push(diagnostic);
|
|
82
|
+
} catch (parseError) {
|
|
83
|
+
logError('Failed to parse compilation error:', parseError);
|
|
84
|
+
}
|
|
86
85
|
}
|
|
87
86
|
|
|
88
|
-
|
|
87
|
+
log('Generated', diagnostics.length, 'diagnostics');
|
|
88
|
+
return diagnostics;
|
|
89
89
|
} catch (err) {
|
|
90
90
|
logError('Failed to provide diagnostics:', err);
|
|
91
91
|
return [];
|
|
@@ -236,5 +236,5 @@ function getEmbeddedInfo(context, document) {
|
|
|
236
236
|
}
|
|
237
237
|
|
|
238
238
|
module.exports = {
|
|
239
|
-
|
|
239
|
+
createCompileErrorDiagnosticPlugin,
|
|
240
240
|
};
|
package/src/hoverPlugin.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** @import { LanguageServicePlugin } from '@volar/language-server' */
|
|
2
2
|
/** @import { RippleVirtualCode } from '@ripple-ts/typescript-plugin/src/language.js') */
|
|
3
|
-
/** @
|
|
3
|
+
/** @import { LanguageServicePluginInstance } from '@volar/language-server' */
|
|
4
4
|
|
|
5
5
|
const { URI } = require('vscode-uri');
|
|
6
6
|
|
|
@@ -95,6 +95,26 @@ function createHoverPlugin() {
|
|
|
95
95
|
return tsHover;
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
+
const customHover = mapping?.data?.customData?.hover;
|
|
99
|
+
if (customHover) {
|
|
100
|
+
log('Found custom hover data in mapping');
|
|
101
|
+
return {
|
|
102
|
+
contents: {
|
|
103
|
+
kind: 'markdown',
|
|
104
|
+
value: customHover.contents,
|
|
105
|
+
},
|
|
106
|
+
range: {
|
|
107
|
+
start: position,
|
|
108
|
+
end: position,
|
|
109
|
+
},
|
|
110
|
+
};
|
|
111
|
+
} else if (customHover === false) {
|
|
112
|
+
log(
|
|
113
|
+
`Hover explicitly suppressed in mapping at range start: ${rangeStart}, end: ${rangeEnd}`,
|
|
114
|
+
);
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
|
|
98
118
|
log('Found mapping for hover at range', 'start: ', rangeStart, 'end: ', rangeEnd);
|
|
99
119
|
|
|
100
120
|
// Check if source length is greater than generated length (component -> function)
|
package/src/server.js
CHANGED
|
@@ -3,11 +3,12 @@
|
|
|
3
3
|
createServer,
|
|
4
4
|
createTypeScriptProject,
|
|
5
5
|
} = require('@volar/language-server/node');
|
|
6
|
-
const {
|
|
6
|
+
const { createCompileErrorDiagnosticPlugin } = require('./compileErrorDiagnosticPlugin.js');
|
|
7
7
|
const { createDefinitionPlugin } = require('./definitionPlugin.js');
|
|
8
8
|
const { createHoverPlugin } = require('./hoverPlugin.js');
|
|
9
9
|
const { createCompletionPlugin } = require('./completionPlugin.js');
|
|
10
10
|
const { createAutoInsertPlugin } = require('./autoInsertPlugin.js');
|
|
11
|
+
const { createTypeScriptDiagnosticFilterPlugin } = require('./typescriptDiagnosticPlugin.js');
|
|
11
12
|
const {
|
|
12
13
|
getRippleLanguagePlugin,
|
|
13
14
|
resolveConfig,
|
|
@@ -110,12 +111,14 @@ function createRippleLanguageServer() {
|
|
|
110
111
|
[
|
|
111
112
|
createAutoInsertPlugin(),
|
|
112
113
|
createCompletionPlugin(),
|
|
113
|
-
|
|
114
|
+
createCompileErrorDiagnosticPlugin(),
|
|
114
115
|
createDefinitionPlugin(),
|
|
115
116
|
createCssService(),
|
|
116
117
|
...createTypeScriptServices(ts),
|
|
117
|
-
// !IMPORTANT
|
|
118
|
-
//
|
|
118
|
+
// !IMPORTANT 'createTypeScriptDiagnosticFilterPlugin' and 'createHoverPlugin'
|
|
119
|
+
// must come after TypeScript services
|
|
120
|
+
// to intercept volar's and vscode default providers
|
|
121
|
+
createTypeScriptDiagnosticFilterPlugin(),
|
|
119
122
|
createHoverPlugin(),
|
|
120
123
|
],
|
|
121
124
|
);
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/** @import { LanguageServicePlugin } from '@volar/language-server' */
|
|
2
|
+
/** @import { LanguageServicePluginInstance } from '@volar/language-server' */
|
|
3
|
+
|
|
4
|
+
// @ts-expect-error type-only import from ESM module into CJS is fine
|
|
5
|
+
/** @import { CodeMapping } from 'ripple/compiler' */
|
|
6
|
+
|
|
7
|
+
const { getVirtualCode } = require('./utils.js');
|
|
8
|
+
|
|
9
|
+
const DEBUG = process.env.RIPPLE_DEBUG === 'true';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @param {...unknown} args
|
|
13
|
+
*/
|
|
14
|
+
function log(...args) {
|
|
15
|
+
if (DEBUG) {
|
|
16
|
+
console.log('[Ripple Typescript Diagnostics]', ...args);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @param {...unknown} args
|
|
22
|
+
*/
|
|
23
|
+
function logError(...args) {
|
|
24
|
+
console.error('[Ripple Typescript Diagnostics]', ...args);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Create a plugin to filter TypeScript diagnostics based on customData in mappings
|
|
29
|
+
* @returns {LanguageServicePlugin}
|
|
30
|
+
*/
|
|
31
|
+
function createTypeScriptDiagnosticFilterPlugin() {
|
|
32
|
+
log('Creating TypeScript diagnostic filter plugin...');
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
name: 'ripple-typescript-diagnostic-filter',
|
|
36
|
+
capabilities: {
|
|
37
|
+
diagnosticProvider: {
|
|
38
|
+
interFileDependencies: false,
|
|
39
|
+
workspaceDiagnostics: false,
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
create(context) {
|
|
43
|
+
/** @type {LanguageServicePluginInstance['provideDiagnostics']} */
|
|
44
|
+
let originalProvideDiagnostics;
|
|
45
|
+
/** @type {LanguageServicePluginInstance} */
|
|
46
|
+
let originalInstance;
|
|
47
|
+
|
|
48
|
+
// Disable typescript-semantic's provideHover so it doesn't merge with ours
|
|
49
|
+
for (const [plugin, instance] of context.plugins) {
|
|
50
|
+
if (plugin.name === 'typescript-semantic') {
|
|
51
|
+
originalInstance = instance;
|
|
52
|
+
originalProvideDiagnostics = instance.provideDiagnostics;
|
|
53
|
+
instance.provideDiagnostics = undefined;
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (!originalProvideDiagnostics) {
|
|
59
|
+
logError(
|
|
60
|
+
"'typescript-semantic plugin' was not found or has no 'provideDiagnostics'. \
|
|
61
|
+
This plugin must be loaded after Volar's typescript-semantic plugin.",
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return {
|
|
66
|
+
async provideDiagnostics(document, token) {
|
|
67
|
+
let diagnostics;
|
|
68
|
+
|
|
69
|
+
if (originalProvideDiagnostics) {
|
|
70
|
+
diagnostics = await originalProvideDiagnostics.call(originalInstance, document, token);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (!diagnostics || diagnostics.length === 0) {
|
|
74
|
+
return diagnostics;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
log(`Filtering ${diagnostics.length} TypeScript diagnostics for ${document.uri}`);
|
|
78
|
+
|
|
79
|
+
const virtualCode = getVirtualCode(document, context);
|
|
80
|
+
|
|
81
|
+
const filtered = diagnostics.filter((diagnostic) => {
|
|
82
|
+
const range = diagnostic.range;
|
|
83
|
+
const rangeStart = document.offsetAt(range.start);
|
|
84
|
+
const rangeEnd = document.offsetAt(range.end);
|
|
85
|
+
// Get the mapping at this diagnostic position
|
|
86
|
+
const mapping = virtualCode.findMappingByGeneratedRange(rangeStart, rangeEnd);
|
|
87
|
+
|
|
88
|
+
if (!mapping) {
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const suppressedCodes = mapping.data.customData?.suppressedDiagnostics;
|
|
93
|
+
|
|
94
|
+
if (!suppressedCodes || suppressedCodes.length === 0) {
|
|
95
|
+
return true;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const diagnosticCode =
|
|
99
|
+
typeof diagnostic.code === 'number'
|
|
100
|
+
? diagnostic.code
|
|
101
|
+
: typeof diagnostic.code === 'string'
|
|
102
|
+
? parseInt(diagnostic.code)
|
|
103
|
+
: null;
|
|
104
|
+
|
|
105
|
+
if (diagnosticCode && suppressedCodes.includes(diagnosticCode)) {
|
|
106
|
+
log(`Suppressing diagnostic ${diagnosticCode}: ${diagnostic.message}`);
|
|
107
|
+
return false; // Filter out this diagnostic
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return true; // Keep this diagnostic
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
log(`Filtered from ${diagnostics.length} to ${filtered.length} diagnostics`);
|
|
114
|
+
return filtered;
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Get the mapping at a specific position in the document
|
|
123
|
+
* @param {import('@volar/language-server').LanguageServiceContext} context
|
|
124
|
+
* @param {import('vscode-languageserver-textdocument').TextDocument} document
|
|
125
|
+
* @param {import('@volar/language-server').Position} position
|
|
126
|
+
* @returns {CodeMapping | null}
|
|
127
|
+
*/
|
|
128
|
+
function getMappingAtPosition(context, document, position) {
|
|
129
|
+
try {
|
|
130
|
+
const { URI } = require('vscode-uri');
|
|
131
|
+
const { RippleVirtualCode } = require('@ripple-ts/typescript-plugin/src/language.js');
|
|
132
|
+
|
|
133
|
+
const uri = URI.parse(document.uri);
|
|
134
|
+
const decoded = context.decodeEmbeddedDocumentUri(uri);
|
|
135
|
+
if (!decoded) {
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const [sourceUri, virtualCodeId] = decoded;
|
|
140
|
+
const sourceScript = context.language.scripts.get(sourceUri);
|
|
141
|
+
const virtualCode = /** @type {RippleVirtualCode} */ (
|
|
142
|
+
sourceScript?.generated?.embeddedCodes.get(virtualCodeId)
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
if (!virtualCode?.mappings) {
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Convert position to offset in the virtual document
|
|
150
|
+
const offset = document.offsetAt(position);
|
|
151
|
+
|
|
152
|
+
// Find mapping that contains this offset
|
|
153
|
+
for (const mapping of virtualCode.mappings) {
|
|
154
|
+
const genStart = mapping.generatedOffsets[0];
|
|
155
|
+
const genEnd = genStart + mapping.lengths[0];
|
|
156
|
+
|
|
157
|
+
if (offset >= genStart && offset < genEnd) {
|
|
158
|
+
return mapping;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return null;
|
|
163
|
+
} catch (err) {
|
|
164
|
+
log('Error getting mapping at position:', err);
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
module.exports = {
|
|
170
|
+
createTypeScriptDiagnosticFilterPlugin,
|
|
171
|
+
};
|
package/src/utils.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/** @import { TextDocument } from 'vscode-languageserver-textdocument' */
|
|
2
|
+
/** @import { LanguageServiceContext } from '@volar/language-server' */
|
|
3
|
+
/** @import {RippleVirtualCode} from '@ripple-ts/typescript-plugin/src/language.js' */
|
|
4
|
+
|
|
5
|
+
const { URI } = require('vscode-uri');
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Get virtual code from the encoded document URI
|
|
9
|
+
* @param {LanguageServiceContext} context
|
|
10
|
+
* @param {TextDocument} document
|
|
11
|
+
* @returns {RippleVirtualCode}
|
|
12
|
+
*/
|
|
13
|
+
function getVirtualCode(document, context) {
|
|
14
|
+
const uri = URI.parse(document.uri);
|
|
15
|
+
const decoded = /** @type {[documentUri: URI, embeddedCodeId: string]} */ (
|
|
16
|
+
context.decodeEmbeddedDocumentUri(uri)
|
|
17
|
+
);
|
|
18
|
+
const [sourceUri, virtualCodeId] = decoded;
|
|
19
|
+
const sourceScript = context.language.scripts.get(sourceUri);
|
|
20
|
+
const virtualCode = /** @type {RippleVirtualCode} */ (
|
|
21
|
+
sourceScript?.generated?.embeddedCodes.get(virtualCodeId)
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
return virtualCode;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
module.exports = {
|
|
28
|
+
getVirtualCode,
|
|
29
|
+
};
|