@ripple-ts/language-server 0.3.41 → 0.3.42
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/dist/language-server.js +9 -0
- package/dist/language-server.js.map +1 -0
- package/dist/package.json +1 -0
- package/dist/server.js +111 -0
- package/dist/server.js.map +1 -0
- package/dist/typescriptService-CWMxKghf.js +21866 -0
- package/dist/typescriptService-CWMxKghf.js.map +1 -0
- package/package.json +8 -5
- package/CHANGELOG.md +0 -513
- package/bin/language-server.js +0 -5
- package/src/autoInsertPlugin.js +0 -163
- package/src/compileErrorDiagnosticPlugin.js +0 -155
- package/src/completionPlugin.js +0 -508
- package/src/definitionPlugin.js +0 -208
- package/src/documentHighlightPlugin.js +0 -118
- package/src/hoverPlugin.js +0 -146
- package/src/server.js +0 -155
- package/src/typescriptDiagnosticPlugin.js +0 -139
- package/src/typescriptService.js +0 -49
- package/src/utils.js +0 -162
- package/tsconfig.json +0 -17
- package/tsconfig.typecheck.json +0 -7
- package/tsdown.config.js +0 -41
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
@import {
|
|
3
|
-
LanguageServicePlugin,
|
|
4
|
-
LanguageServicePluginInstance,
|
|
5
|
-
LanguageServiceContext,
|
|
6
|
-
Diagnostic,
|
|
7
|
-
} from '@volar/language-server';
|
|
8
|
-
@import {TextDocument} from 'vscode-languageserver-textdocument';
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import { getVirtualCode, createLogging, deobfuscateIdentifiers } from './utils.js';
|
|
12
|
-
|
|
13
|
-
const { log, logError } = createLogging('[Ripple TypeScript Diagnostic Plugin]');
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* @param {Diagnostic} diagnostic
|
|
17
|
-
* @param {Diagnostic[]} items
|
|
18
|
-
*/
|
|
19
|
-
function process(diagnostic, items) {
|
|
20
|
-
diagnostic.message = deobfuscateIdentifiers(diagnostic.message);
|
|
21
|
-
items.push(diagnostic);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Filter diagnostics based on suppressed diagnostic codes in mappings.
|
|
26
|
-
* @param {TextDocument} document
|
|
27
|
-
* @param {LanguageServiceContext} context
|
|
28
|
-
* @param {Diagnostic[]} diagnostics
|
|
29
|
-
* @returns {Diagnostic[]}
|
|
30
|
-
*/
|
|
31
|
-
function processDiagnostics(document, context, diagnostics) {
|
|
32
|
-
if (!diagnostics || diagnostics.length === 0) {
|
|
33
|
-
return diagnostics;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
log(`Filtering ${diagnostics.length} TypeScript diagnostics for ${document.uri}`);
|
|
37
|
-
|
|
38
|
-
const { virtualCode } = getVirtualCode(document, context);
|
|
39
|
-
|
|
40
|
-
if (!virtualCode || virtualCode.languageId !== 'ripple') {
|
|
41
|
-
return diagnostics;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/** @type {Diagnostic[]} */
|
|
45
|
-
const result = [];
|
|
46
|
-
|
|
47
|
-
for (const diagnostic of diagnostics) {
|
|
48
|
-
if (virtualCode.fatalErrors.length > 0 && diagnostic.code !== 'tsrx-compile-error') {
|
|
49
|
-
// skip all TS diagnostics since we're dealing directly with the source code
|
|
50
|
-
continue;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const range = diagnostic.range;
|
|
54
|
-
const rangeStart = document.offsetAt(range.start);
|
|
55
|
-
const rangeEnd = document.offsetAt(range.end);
|
|
56
|
-
const mapping = virtualCode.findMappingByGeneratedRange(rangeStart, rangeEnd);
|
|
57
|
-
|
|
58
|
-
if (!mapping) {
|
|
59
|
-
process(diagnostic, result);
|
|
60
|
-
continue;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const suppressedCodes = mapping.data.customData?.suppressedDiagnostics;
|
|
64
|
-
|
|
65
|
-
if (!suppressedCodes || suppressedCodes.length === 0) {
|
|
66
|
-
process(diagnostic, result);
|
|
67
|
-
continue;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const diagnosticCode =
|
|
71
|
-
typeof diagnostic.code === 'number'
|
|
72
|
-
? diagnostic.code
|
|
73
|
-
: typeof diagnostic.code === 'string'
|
|
74
|
-
? parseInt(diagnostic.code)
|
|
75
|
-
: null;
|
|
76
|
-
|
|
77
|
-
if (diagnosticCode && suppressedCodes.includes(diagnosticCode)) {
|
|
78
|
-
log(`Suppressing diagnostic ${diagnosticCode}: ${diagnostic.message}`);
|
|
79
|
-
continue;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
process(diagnostic, result);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
log(`Filtered from ${diagnostics.length} to ${result.length} diagnostics`);
|
|
86
|
-
return result;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Creates a plugin that wraps typescript-semantic's provideDiagnostics
|
|
91
|
-
* to filter out suppressed diagnostics while maintaining the original
|
|
92
|
-
* plugin association. This is crucial for code actions (like "Add import")
|
|
93
|
-
* to work correctly, as volar matches diagnostics by pluginIndex.
|
|
94
|
-
* @returns {LanguageServicePlugin}
|
|
95
|
-
*/
|
|
96
|
-
export function createTypeScriptDiagnosticFilterPlugin() {
|
|
97
|
-
log('Creating TypeScript diagnostic filter plugin...');
|
|
98
|
-
|
|
99
|
-
return {
|
|
100
|
-
name: 'ripple-typescript-diagnostic-filter',
|
|
101
|
-
// No capabilities - this plugin only wraps typescript-semantic
|
|
102
|
-
capabilities: {},
|
|
103
|
-
create(context) {
|
|
104
|
-
/** @type {LanguageServicePluginInstance['provideDiagnostics'] | undefined} */
|
|
105
|
-
let originalProvider;
|
|
106
|
-
/** @type {LanguageServicePluginInstance | undefined} */
|
|
107
|
-
let originalInstance;
|
|
108
|
-
|
|
109
|
-
for (const [plugin, instance] of context.plugins) {
|
|
110
|
-
if (plugin.name === 'typescript-semantic') {
|
|
111
|
-
originalInstance = instance;
|
|
112
|
-
originalProvider = instance.provideDiagnostics;
|
|
113
|
-
|
|
114
|
-
// Wrap the original function to filter diagnostics
|
|
115
|
-
// This maintains the plugin association for code actions
|
|
116
|
-
instance.provideDiagnostics = async function (document, token) {
|
|
117
|
-
const diagnostics = await originalProvider?.call(originalInstance, document, token);
|
|
118
|
-
return processDiagnostics(document, context, diagnostics ?? []);
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
log('Successfully wrapped typescript-semantic provideDiagnostics');
|
|
122
|
-
|
|
123
|
-
break;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
if (!originalProvider) {
|
|
128
|
-
logError(
|
|
129
|
-
"'typescript-semantic plugin' was not found or has no 'provideDiagnostics'. \
|
|
130
|
-
This plugin must be loaded after Volar's typescript-semantic plugin.",
|
|
131
|
-
);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// This plugin doesn't provide any functionality itself,
|
|
135
|
-
// it only wraps typescript-semantic
|
|
136
|
-
return {};
|
|
137
|
-
},
|
|
138
|
-
};
|
|
139
|
-
}
|
package/src/typescriptService.js
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @import {LanguageServiceContext} from '@volar/language-server'
|
|
3
|
-
* @import {TextDocument} from 'vscode-languageserver-textdocument'
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { createRequire } from 'node:module';
|
|
7
|
-
|
|
8
|
-
// Monkey-patch getUserPreferences to inject Ripple-specific defaults.
|
|
9
|
-
// We use createRequire to get the raw CJS module.exports object, bypassing
|
|
10
|
-
// the bundler's __toESM wrapper which interferes with property assignment.
|
|
11
|
-
// volar-service-typescript is also externalized (via regex in tsdown config)
|
|
12
|
-
// so that its internal consumers (semantic.js, codeAction.js, etc.) load
|
|
13
|
-
// getUserPreferences from the same Node module cache entry we patch here.
|
|
14
|
-
const require = createRequire(import.meta.url);
|
|
15
|
-
const getUserPreferencesModule = require('volar-service-typescript/lib/configs/getUserPreferences');
|
|
16
|
-
const { create } = require('volar-service-typescript');
|
|
17
|
-
|
|
18
|
-
const originalGetUserPreferences = getUserPreferencesModule.getUserPreferences;
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Enhanced getUserPreferences to add all ts and ripple preferences
|
|
22
|
-
* Specifically makes preferTypeOnlyAutoImports true if not set
|
|
23
|
-
* @param {LanguageServiceContext} context
|
|
24
|
-
* @param {TextDocument} document
|
|
25
|
-
*/
|
|
26
|
-
getUserPreferencesModule.getUserPreferences = async function (context, document) {
|
|
27
|
-
const origPreferences = await originalGetUserPreferences.call(this, context, document);
|
|
28
|
-
|
|
29
|
-
const [tsConfig, rippleConfig] = await Promise.all([
|
|
30
|
-
context.env.getConfiguration?.('typescript'),
|
|
31
|
-
context.env.getConfiguration?.('ripple'),
|
|
32
|
-
]);
|
|
33
|
-
|
|
34
|
-
return {
|
|
35
|
-
preferTypeOnlyAutoImports: true,
|
|
36
|
-
...origPreferences,
|
|
37
|
-
.../** @type {any} */ (tsConfig)?.preferences,
|
|
38
|
-
.../** @type {any} */ (rippleConfig)?.preferences,
|
|
39
|
-
};
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Create TypeScript services with Ripple-specific enhancements.
|
|
44
|
-
* @param {typeof import('typescript')} ts
|
|
45
|
-
* @returns {ReturnType<typeof create>}
|
|
46
|
-
*/
|
|
47
|
-
export function createTypeScriptServices(ts) {
|
|
48
|
-
return create(ts);
|
|
49
|
-
}
|
package/src/utils.js
DELETED
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
/** @import { TextDocument } from 'vscode-languageserver-textdocument' */
|
|
2
|
-
/** @import { LanguageServiceContext, Mapper, SourceScript } from '@volar/language-server' */
|
|
3
|
-
/** @import {TSRXVirtualCodeInstance} from '@tsrx/typescript-plugin/src/language.js'; */
|
|
4
|
-
/** @import { isIdentifierObfuscated, deobfuscateIdentifier, IDENTIFIER_OBFUSCATION_PREFIX } from '@tsrx/core' */
|
|
5
|
-
|
|
6
|
-
import { URI } from 'vscode-uri';
|
|
7
|
-
import {
|
|
8
|
-
createLogging,
|
|
9
|
-
getWordFromPosition,
|
|
10
|
-
charAllowedWordRegex,
|
|
11
|
-
DEBUG,
|
|
12
|
-
} from '@tsrx/typescript-plugin/src/utils.js';
|
|
13
|
-
|
|
14
|
-
const IMPORT_EXPORT_REGEX = {
|
|
15
|
-
import: {
|
|
16
|
-
findBefore: /import\s+(?:\{[^}]*|\*\s+as\s+\w*|\w*)$/s,
|
|
17
|
-
sameLine: /^import\s/,
|
|
18
|
-
},
|
|
19
|
-
export: {
|
|
20
|
-
findBefore: /export\s+(?:\{[^}]*|\*\s+as\s+\w*|\w*)$/s,
|
|
21
|
-
sameLine: /^export\s/,
|
|
22
|
-
},
|
|
23
|
-
from: /from\s*['"][^'"]*['"]\s*;?/,
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
export const RIPPLE_EXTENSIONS = ['.tsrx'];
|
|
27
|
-
|
|
28
|
-
/** @type {typeof isIdentifierObfuscated} */
|
|
29
|
-
let is_identifier_obfuscated;
|
|
30
|
-
/** @type {typeof deobfuscateIdentifier} */
|
|
31
|
-
let deobfuscate_identifier;
|
|
32
|
-
/** @type {typeof IDENTIFIER_OBFUSCATION_PREFIX} */
|
|
33
|
-
let identifier_obfuscation_prefix;
|
|
34
|
-
/** @type {RegExp} */
|
|
35
|
-
let obfuscated_identifier_regex;
|
|
36
|
-
|
|
37
|
-
import('@tsrx/core').then((imports) => {
|
|
38
|
-
is_identifier_obfuscated = imports.isIdentifierObfuscated;
|
|
39
|
-
deobfuscate_identifier = imports.deobfuscateIdentifier;
|
|
40
|
-
identifier_obfuscation_prefix = imports.IDENTIFIER_OBFUSCATION_PREFIX;
|
|
41
|
-
obfuscated_identifier_regex = new RegExp(
|
|
42
|
-
escapeRegExp(identifier_obfuscation_prefix) + charAllowedWordRegex.source + '+',
|
|
43
|
-
'gm',
|
|
44
|
-
);
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* @param {string} source
|
|
49
|
-
* @returns {string}
|
|
50
|
-
*/
|
|
51
|
-
function escapeRegExp(source) {
|
|
52
|
-
// $& means the whole matched source
|
|
53
|
-
return source.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* @param {string} text
|
|
58
|
-
* @returns {string}
|
|
59
|
-
*/
|
|
60
|
-
export function deobfuscateIdentifiers(text) {
|
|
61
|
-
return text.replace(obfuscated_identifier_regex, (match) => deobfuscate_identifier(match));
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* @param {...string} contents
|
|
66
|
-
* @returns string
|
|
67
|
-
*/
|
|
68
|
-
export function concatMarkdownContents(...contents) {
|
|
69
|
-
return contents.join('\n\n<br>\n\n---\n\n<br><br>\n\n');
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Get virtual code from the encoded document URI
|
|
74
|
-
* @param {LanguageServiceContext} context
|
|
75
|
-
* @param {TextDocument} document
|
|
76
|
-
* @returns
|
|
77
|
-
{{
|
|
78
|
-
virtualCode: TSRXVirtualCodeInstance;
|
|
79
|
-
sourceUri: URI;
|
|
80
|
-
sourceScript: SourceScript<URI> | undefined;
|
|
81
|
-
sourceMap: Mapper | undefined;
|
|
82
|
-
}}
|
|
83
|
-
*/
|
|
84
|
-
export function getVirtualCode(document, context) {
|
|
85
|
-
const uri = URI.parse(document.uri);
|
|
86
|
-
const decoded = /** @type {[documentUri: URI, embeddedCodeId: string]} */ (
|
|
87
|
-
context.decodeEmbeddedDocumentUri(uri)
|
|
88
|
-
);
|
|
89
|
-
const [sourceUri, virtualCodeId] = decoded;
|
|
90
|
-
const sourceScript = context.language.scripts.get(sourceUri);
|
|
91
|
-
const virtualCode = /** @type {TSRXVirtualCodeInstance} */ (
|
|
92
|
-
sourceScript?.generated?.embeddedCodes.get(virtualCodeId)
|
|
93
|
-
);
|
|
94
|
-
|
|
95
|
-
const sourceMap =
|
|
96
|
-
sourceScript && virtualCode ? context.language.maps.get(virtualCode, sourceScript) : undefined;
|
|
97
|
-
|
|
98
|
-
return { virtualCode, sourceUri, sourceScript, sourceMap };
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* @param {'import' | 'export'} type
|
|
103
|
-
* @param {string} text
|
|
104
|
-
* @param {number} start
|
|
105
|
-
* @returns {boolean}
|
|
106
|
-
*/
|
|
107
|
-
function isInsideImportOrExport(type, text, start) {
|
|
108
|
-
const textBeforeCursor = text.slice(0, start);
|
|
109
|
-
|
|
110
|
-
// Find the last 'import' keyword before cursor
|
|
111
|
-
const lastImportMatch = textBeforeCursor.match(IMPORT_EXPORT_REGEX[type].findBefore);
|
|
112
|
-
if (!lastImportMatch) {
|
|
113
|
-
// Check if we're on a line that starts with import
|
|
114
|
-
const lineStart = textBeforeCursor.lastIndexOf('\n') + 1;
|
|
115
|
-
const lineBeforeCursor = textBeforeCursor.slice(lineStart);
|
|
116
|
-
return IMPORT_EXPORT_REGEX[type].sameLine.test(lineBeforeCursor.trim());
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// We found an import - check if it's been closed with 'from'
|
|
120
|
-
const importStart = textBeforeCursor.lastIndexOf(type);
|
|
121
|
-
const textFromImport = text.slice(importStart);
|
|
122
|
-
|
|
123
|
-
// Find the end of this import statement (semicolon or newline after 'from "..."')
|
|
124
|
-
const fromMatch = textFromImport.match(IMPORT_EXPORT_REGEX.from);
|
|
125
|
-
if (!fromMatch || fromMatch.index === undefined) {
|
|
126
|
-
// No 'from' found yet - we're inside an incomplete import
|
|
127
|
-
return true;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
const importEndOffset = importStart + fromMatch.index + fromMatch[0].length;
|
|
131
|
-
|
|
132
|
-
// If cursor is before the import ends, we're inside it
|
|
133
|
-
return start < importEndOffset;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* @param {string} text
|
|
138
|
-
* @param {number} start
|
|
139
|
-
* @returns {boolean}
|
|
140
|
-
*/
|
|
141
|
-
export function isInsideImport(text, start) {
|
|
142
|
-
return isInsideImportOrExport('import', text, start);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* @param {string} text
|
|
147
|
-
* @param {number} start
|
|
148
|
-
* @returns {boolean}
|
|
149
|
-
*/
|
|
150
|
-
export function isInsideExport(text, start) {
|
|
151
|
-
return isInsideImportOrExport('export', text, start);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
/**
|
|
155
|
-
* @param {string} document_uri
|
|
156
|
-
* @returns {boolean}
|
|
157
|
-
*/
|
|
158
|
-
export function is_ripple_document(document_uri) {
|
|
159
|
-
return RIPPLE_EXTENSIONS.some((extension) => document_uri.endsWith(extension));
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
export { createLogging, getWordFromPosition, DEBUG };
|
package/tsconfig.json
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"module": "esnext",
|
|
4
|
-
"moduleResolution": "bundler",
|
|
5
|
-
"target": "esnext",
|
|
6
|
-
"lib": ["esnext"],
|
|
7
|
-
"allowJs": true,
|
|
8
|
-
"checkJs": true,
|
|
9
|
-
"noEmit": true,
|
|
10
|
-
"strict": true,
|
|
11
|
-
"esModuleInterop": true,
|
|
12
|
-
"resolveJsonModule": true,
|
|
13
|
-
"types": []
|
|
14
|
-
},
|
|
15
|
-
"include": ["src/**/*.js", "index.js", "bin/**/*.js"],
|
|
16
|
-
"exclude": ["node_modules", "dist"]
|
|
17
|
-
}
|
package/tsconfig.typecheck.json
DELETED
package/tsdown.config.js
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { defineConfig } from 'tsdown';
|
|
2
|
-
import fs from 'fs';
|
|
3
|
-
import path from 'path';
|
|
4
|
-
import { fileURLToPath } from 'url';
|
|
5
|
-
|
|
6
|
-
const dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
7
|
-
const isDev = process.env.NODE_ENV !== 'production';
|
|
8
|
-
const ROOT_EXTERNAL_PACKAGES = [
|
|
9
|
-
'@tsrx/react',
|
|
10
|
-
'@tsrx/ripple',
|
|
11
|
-
'@tsrx/core',
|
|
12
|
-
'typescript',
|
|
13
|
-
'vscode-uri',
|
|
14
|
-
// need this for monkey patching
|
|
15
|
-
'volar-service-typescript',
|
|
16
|
-
/* also definitely need it for monkey patching */
|
|
17
|
-
/^volar-service-typescript(?:\/.*)?$/,
|
|
18
|
-
];
|
|
19
|
-
|
|
20
|
-
export default defineConfig({
|
|
21
|
-
inlineOnly: false,
|
|
22
|
-
entry: ['src/server.js', 'bin/language-server.js'],
|
|
23
|
-
format: ['cjs'],
|
|
24
|
-
outExtensions: () => ({ js: '.js' }),
|
|
25
|
-
platform: 'node',
|
|
26
|
-
target: 'node20',
|
|
27
|
-
outDir: 'dist',
|
|
28
|
-
sourcemap: isDev,
|
|
29
|
-
outputOptions: {
|
|
30
|
-
legalComments: 'inline',
|
|
31
|
-
minify: false,
|
|
32
|
-
},
|
|
33
|
-
external: [...ROOT_EXTERNAL_PACKAGES],
|
|
34
|
-
clean: true,
|
|
35
|
-
noExternal: /.+/,
|
|
36
|
-
hooks: {
|
|
37
|
-
'build:done': () => {
|
|
38
|
-
fs.writeFileSync(path.join(dirname, 'dist', 'package.json'), '{"type":"commonjs"}\n');
|
|
39
|
-
},
|
|
40
|
-
},
|
|
41
|
-
});
|