summaryrefslogtreecommitdiff
path: root/cli/lsp/tsc.rs
diff options
context:
space:
mode:
authorNayeem Rahman <nayeemrmn99@gmail.com>2023-10-02 07:32:05 +0100
committerGitHub <noreply@github.com>2023-10-02 07:32:05 +0100
commit6fd2d0841871018bd394ebbdccd4c1f39e5cf773 (patch)
tree635b0402b090a2792be20c2a45850b30ca3cb9b5 /cli/lsp/tsc.rs
parentde25c81fd0860d0fb604d105534721d8b37a4abd (diff)
refactor(lsp): clean up tsc requests (#20743)
Diffstat (limited to 'cli/lsp/tsc.rs')
-rw-r--r--cli/lsp/tsc.rs1338
1 files changed, 496 insertions, 842 deletions
diff --git a/cli/lsp/tsc.rs b/cli/lsp/tsc.rs
index e45d6d52b..e6a161474 100644
--- a/cli/lsp/tsc.rs
+++ b/cli/lsp/tsc.rs
@@ -93,7 +93,7 @@ const FILE_EXTENSION_KIND_MODIFIERS: &[&str] =
&[".d.ts", ".ts", ".tsx", ".js", ".jsx", ".json"];
type Request = (
- RequestMethod,
+ TscRequest,
Arc<StateSnapshot>,
oneshot::Sender<Result<Value, AnyError>>,
CancellationToken,
@@ -149,7 +149,7 @@ pub struct TsServer {
impl TsServer {
pub fn new(performance: Arc<Performance>, cache: Arc<dyn HttpCache>) -> Self {
- let specifier_map = Arc::new(TscSpecifierMap::default());
+ let specifier_map = Arc::new(TscSpecifierMap::new());
let specifier_map_ = specifier_map.clone();
let (tx, mut rx) = mpsc::unbounded_channel::<Request>();
let _join_handle = thread::spawn(move || {
@@ -184,7 +184,13 @@ impl TsServer {
specifiers: Vec<ModuleSpecifier>,
token: CancellationToken,
) -> Result<HashMap<String, Vec<crate::tsc::Diagnostic>>, AnyError> {
- let req = RequestMethod::GetDiagnostics(specifiers);
+ let req = TscRequest {
+ method: "$getDiagnostics",
+ args: json!([specifiers
+ .into_iter()
+ .map(|s| self.specifier_map.denormalize(&s))
+ .collect::<Vec<String>>(),]),
+ };
let diagnostics_map_ = self.request_with_cancellation::<HashMap<String, Vec<crate::tsc::Diagnostic>>>(snapshot, req, token).await?;
let mut diagnostics_map = HashMap::new();
for (mut specifier, mut diagnostics) in diagnostics_map_ {
@@ -203,9 +209,10 @@ impl TsServer {
specifier: ModuleSpecifier,
position: u32,
) -> Result<Option<Vec<ReferencedSymbol>>, LspError> {
- let req = RequestMethod::FindReferences {
- specifier,
- position,
+ let req = TscRequest {
+ method: "findReferences",
+ // https://github.com/denoland/deno/blob/v1.37.1/cli/tsc/dts/typescript.d.ts#L6230
+ args: json!([self.specifier_map.denormalize(&specifier), position]),
};
self
.request::<Option<Vec<ReferencedSymbol>>>(snapshot, req)
@@ -227,9 +234,12 @@ impl TsServer {
snapshot: Arc<StateSnapshot>,
specifier: ModuleSpecifier,
) -> Result<NavigationTree, AnyError> {
- self
- .request(snapshot, RequestMethod::GetNavigationTree(specifier))
- .await
+ let req = TscRequest {
+ method: "getNavigationTree",
+ // https://github.com/denoland/deno/blob/v1.37.1/cli/tsc/dts/typescript.d.ts#L6235
+ args: json!([self.specifier_map.denormalize(&specifier)]),
+ };
+ self.request(snapshot, req).await
}
pub async fn configure(
@@ -237,22 +247,25 @@ impl TsServer {
snapshot: Arc<StateSnapshot>,
tsconfig: TsConfig,
) -> Result<bool, AnyError> {
- self
- .request(snapshot, RequestMethod::Configure(tsconfig))
- .await
+ let req = TscRequest {
+ method: "$configure",
+ args: json!([tsconfig]),
+ };
+ self.request(snapshot, req).await
}
pub async fn get_supported_code_fixes(
&self,
snapshot: Arc<StateSnapshot>,
) -> Result<Vec<String>, LspError> {
- self
- .request(snapshot, RequestMethod::GetSupportedCodeFixes)
- .await
- .map_err(|err| {
- log::error!("Unable to get fixable diagnostics: {}", err);
- LspError::internal_error()
- })
+ let req = TscRequest {
+ method: "$getSupportedCodeFixes",
+ args: json!([]),
+ };
+ self.request(snapshot, req).await.map_err(|err| {
+ log::error!("Unable to get fixable diagnostics: {}", err);
+ LspError::internal_error()
+ })
}
pub async fn get_quick_info(
@@ -261,7 +274,11 @@ impl TsServer {
specifier: ModuleSpecifier,
position: u32,
) -> Result<Option<QuickInfo>, LspError> {
- let req = RequestMethod::GetQuickInfo((specifier, position));
+ let req = TscRequest {
+ method: "getQuickInfoAtPosition",
+ // https://github.com/denoland/deno/blob/v1.37.1/cli/tsc/dts/typescript.d.ts#L6214
+ args: json!([self.specifier_map.denormalize(&specifier), position]),
+ };
self.request(snapshot, req).await.map_err(|err| {
log::error!("Unable to get quick info: {}", err);
LspError::internal_error()
@@ -277,14 +294,21 @@ impl TsServer {
format_code_settings: FormatCodeSettings,
preferences: UserPreferences,
) -> Vec<CodeFixAction> {
- let req = RequestMethod::GetCodeFixes((
- specifier,
- range.start,
- range.end,
- codes,
- format_code_settings,
- preferences,
- ));
+ let mut format_code_settings = json!(format_code_settings);
+ let format_object = format_code_settings.as_object_mut().unwrap();
+ format_object.insert("indentStyle".to_string(), json!(1));
+ let req = TscRequest {
+ method: "getCodeFixesAtPosition",
+ // https://github.com/denoland/deno/blob/v1.37.1/cli/tsc/dts/typescript.d.ts#L6257
+ args: json!([
+ self.specifier_map.denormalize(&specifier),
+ range.start,
+ range.end,
+ codes,
+ format_code_settings,
+ preferences,
+ ]),
+ };
let result = self
.request::<Vec<CodeFixAction>>(snapshot, req)
.await
@@ -315,15 +339,17 @@ impl TsServer {
preferences: Option<UserPreferences>,
only: String,
) -> Result<Vec<ApplicableRefactorInfo>, LspError> {
- let req = RequestMethod::GetApplicableRefactors((
- specifier.clone(),
- TextSpan {
- start: range.start,
- length: range.end - range.start,
- },
- preferences,
- only,
- ));
+ let req = TscRequest {
+ method: "getApplicableRefactors",
+ // https://github.com/denoland/deno/blob/v1.37.1/cli/tsc/dts/typescript.d.ts#L6274
+ args: json!([
+ self.specifier_map.denormalize(&specifier),
+ { "pos": range.start, "end": range.end },
+ preferences.unwrap_or_default(),
+ json!(null),
+ only,
+ ]),
+ };
self.request(snapshot, req).await.map_err(|err| {
log::error!("Failed to request to tsserver {}", err);
LspError::invalid_request()
@@ -337,12 +363,22 @@ impl TsServer {
format_code_settings: FormatCodeSettings,
preferences: UserPreferences,
) -> Result<CombinedCodeActions, LspError> {
- let req = RequestMethod::GetCombinedCodeFix((
- code_action_data.specifier.clone(),
- json!(code_action_data.fix_id.clone()),
- format_code_settings,
- preferences,
- ));
+ let mut format_code_settings = json!(format_code_settings);
+ let format_object = format_code_settings.as_object_mut().unwrap();
+ format_object.insert("indentStyle".to_string(), json!(1));
+ let req = TscRequest {
+ method: "getCombinedCodeFix",
+ // https://github.com/denoland/deno/blob/v1.37.1/cli/tsc/dts/typescript.d.ts#L6258
+ args: json!([
+ {
+ "type": "file",
+ "fileName": self.specifier_map.denormalize(&code_action_data.specifier),
+ },
+ &code_action_data.fix_id,
+ format_code_settings,
+ preferences,
+ ]),
+ };
self
.request::<CombinedCodeActions>(snapshot, req)
.await
@@ -367,17 +403,27 @@ impl TsServer {
action_name: String,
preferences: Option<UserPreferences>,
) -> Result<RefactorEditInfo, LspError> {
- let req = RequestMethod::GetEditsForRefactor((
- specifier,
- format_code_settings,
- TextSpan {
- start: range.start,
- length: range.end - range.start,
- },
- refactor_name,
- action_name,
- preferences,
- ));
+ let mut format_code_settings = json!(format_code_settings);
+ let format_object = format_code_settings.as_object_mut().unwrap();
+ format_object.insert("indentStyle".to_string(), json!(2));
+ format_object.insert(
+ "insertSpaceBeforeAndAfterBinaryOperators".to_string(),
+ json!(true),
+ );
+ format_object
+ .insert("insertSpaceAfterCommaDelimiter".to_string(), json!(true));
+ let req = TscRequest {
+ method: "getEditsForRefactor",
+ // https://github.com/denoland/deno/blob/v1.37.1/cli/tsc/dts/typescript.d.ts#L6275
+ args: json!([
+ self.specifier_map.denormalize(&specifier),
+ format_code_settings,
+ { "pos": range.start, "end": range.end },
+ refactor_name,
+ action_name,
+ preferences,
+ ]),
+ };
self
.request::<RefactorEditInfo>(snapshot, req)
.await
@@ -399,12 +445,16 @@ impl TsServer {
format_code_settings: FormatCodeSettings,
user_preferences: UserPreferences,
) -> Result<Vec<FileTextChanges>, LspError> {
- let req = RequestMethod::GetEditsForFileRename((
- old_specifier,
- new_specifier,
- format_code_settings,
- user_preferences,
- ));
+ let req = TscRequest {
+ method: "getEditsForFileRename",
+ // https://github.com/denoland/deno/blob/v1.37.1/cli/tsc/dts/typescript.d.ts#L6281
+ args: json!([
+ self.specifier_map.denormalize(&old_specifier),
+ self.specifier_map.denormalize(&new_specifier),
+ format_code_settings,
+ user_preferences,
+ ]),
+ };
self
.request::<Vec<FileTextChanges>>(snapshot, req)
.await
@@ -427,11 +477,18 @@ impl TsServer {
position: u32,
files_to_search: Vec<ModuleSpecifier>,
) -> Result<Option<Vec<DocumentHighlights>>, LspError> {
- let req = RequestMethod::GetDocumentHighlights((
- specifier,
- position,
- files_to_search,
- ));
+ let req = TscRequest {
+ method: "getDocumentHighlights",
+ // https://github.com/denoland/deno/blob/v1.37.1/cli/tsc/dts/typescript.d.ts#L6231
+ args: json!([
+ self.specifier_map.denormalize(&specifier),
+ position,
+ files_to_search
+ .into_iter()
+ .map(|s| self.specifier_map.denormalize(&s))
+ .collect::<Vec<_>>(),
+ ]),
+ };
self.request(snapshot, req).await.map_err(|err| {
log::error!("Unable to get document highlights from TypeScript: {}", err);
LspError::internal_error()
@@ -444,7 +501,11 @@ impl TsServer {
specifier: ModuleSpecifier,
position: u32,
) -> Result<Option<DefinitionInfoAndBoundSpan>, LspError> {
- let req = RequestMethod::GetDefinition((specifier, position));
+ let req = TscRequest {
+ method: "getDefinitionAndBoundSpan",
+ // https://github.com/denoland/deno/blob/v1.37.1/cli/tsc/dts/typescript.d.ts#L6226
+ args: json!([self.specifier_map.denormalize(&specifier), position]),
+ };
self
.request::<Option<DefinitionInfoAndBoundSpan>>(snapshot, req)
.await
@@ -466,9 +527,10 @@ impl TsServer {
specifier: ModuleSpecifier,
position: u32,
) -> Result<Option<Vec<DefinitionInfo>>, LspError> {
- let req = RequestMethod::GetTypeDefinition {
- specifier,
- position,
+ let req = TscRequest {
+ method: "getTypeDefinitionAtPosition",
+ // https://github.com/denoland/deno/blob/v1.37.1/cli/tsc/dts/typescript.d.ts#L6227
+ args: json!([self.specifier_map.denormalize(&specifier), position]),
};
self
.request::<Option<Vec<DefinitionInfo>>>(snapshot, req)
@@ -493,12 +555,16 @@ impl TsServer {
options: GetCompletionsAtPositionOptions,
format_code_settings: FormatCodeSettings,
) -> Option<CompletionInfo> {
- let req = RequestMethod::GetCompletions((
- specifier,
- position,
- options,
- format_code_settings,
- ));
+ let req = TscRequest {
+ method: "getCompletionsAtPosition",
+ // https://github.com/denoland/deno/blob/v1.37.1/cli/tsc/dts/typescript.d.ts#L6193
+ args: json!([
+ self.specifier_map.denormalize(&specifier),
+ position,
+ options,
+ format_code_settings,
+ ]),
+ };
match self.request(snapshot, req).await {
Ok(maybe_info) => maybe_info,
Err(err) => {
@@ -513,7 +579,19 @@ impl TsServer {
snapshot: Arc<StateSnapshot>,
args: GetCompletionDetailsArgs,
) -> Result<Option<CompletionEntryDetails>, AnyError> {
- let req = RequestMethod::GetCompletionDetails(args);
+ let req = TscRequest {
+ method: "getCompletionEntryDetails",
+ // https://github.com/denoland/deno/blob/v1.37.1/cli/tsc/dts/typescript.d.ts#L6205
+ args: json!([
+ self.specifier_map.denormalize(&args.specifier),
+ args.position,
+ args.name,
+ args.format_code_settings.unwrap_or_default(),
+ args.source,
+ args.preferences,
+ args.data,
+ ]),
+ };
self
.request::<Option<CompletionEntryDetails>>(snapshot, req)
.await
@@ -531,7 +609,11 @@ impl TsServer {
specifier: ModuleSpecifier,
position: u32,
) -> Result<Option<Vec<ImplementationLocation>>, LspError> {
- let req = RequestMethod::GetImplementation((specifier, position));
+ let req = TscRequest {
+ method: "getImplementationAtPosition",
+ // https://github.com/denoland/deno/blob/v1.37.1/cli/tsc/dts/typescript.d.ts#L6228
+ args: json!([self.specifier_map.denormalize(&specifier), position]),
+ };
self
.request::<Option<Vec<ImplementationLocation>>>(snapshot, req)
.await
@@ -552,7 +634,11 @@ impl TsServer {
snapshot: Arc<StateSnapshot>,
specifier: ModuleSpecifier,
) -> Result<Vec<OutliningSpan>, LspError> {
- let req = RequestMethod::GetOutliningSpans(specifier);
+ let req = TscRequest {
+ method: "getOutliningSpans",
+ // https://github.com/denoland/deno/blob/v1.37.1/cli/tsc/dts/typescript.d.ts#L6240
+ args: json!([self.specifier_map.denormalize(&specifier)]),
+ };
self.request(snapshot, req).await.map_err(|err| {
log::error!("Failed to request to tsserver {}", err);
LspError::invalid_request()
@@ -565,8 +651,11 @@ impl TsServer {
specifier: ModuleSpecifier,
position: u32,
) -> Result<Vec<CallHierarchyIncomingCall>, LspError> {
- let req =
- RequestMethod::ProvideCallHierarchyIncomingCalls((specifier, position));
+ let req = TscRequest {
+ method: "provideCallHierarchyIncomingCalls",
+ // https://github.com/denoland/deno/blob/v1.37.1/cli/tsc/dts/typescript.d.ts#L6237
+ args: json!([self.specifier_map.denormalize(&specifier), position]),
+ };
self
.request::<Vec<CallHierarchyIncomingCall>>(snapshot, req)
.await
@@ -588,8 +677,11 @@ impl TsServer {
specifier: ModuleSpecifier,
position: u32,
) -> Result<Vec<CallHierarchyOutgoingCall>, LspError> {
- let req =
- RequestMethod::ProvideCallHierarchyOutgoingCalls((specifier, position));
+ let req = TscRequest {
+ method: "provideCallHierarchyOutgoingCalls",
+ // https://github.com/denoland/deno/blob/v1.37.1/cli/tsc/dts/typescript.d.ts#L6238
+ args: json!([self.specifier_map.denormalize(&specifier), position]),
+ };
self
.request::<Vec<CallHierarchyOutgoingCall>>(snapshot, req)
.await
@@ -611,7 +703,11 @@ impl TsServer {
specifier: ModuleSpecifier,
position: u32,
) -> Result<Option<OneOrMany<CallHierarchyItem>>, LspError> {
- let req = RequestMethod::PrepareCallHierarchy((specifier, position));
+ let req = TscRequest {
+ method: "prepareCallHierarchy",
+ // https://github.com/denoland/deno/blob/v1.37.1/cli/tsc/dts/typescript.d.ts#L6236
+ args: json!([self.specifier_map.denormalize(&specifier), position]),
+ };
self
.request::<Option<OneOrMany<CallHierarchyItem>>>(snapshot, req)
.await
@@ -641,12 +737,16 @@ impl TsServer {
specifier: ModuleSpecifier,
position: u32,
) -> Result<Option<Vec<RenameLocation>>, LspError> {
- let req = RequestMethod::FindRenameLocations {
- specifier,
- position,
- find_in_strings: false,
- find_in_comments: false,
- provide_prefix_and_suffix_text_for_rename: false,
+ let req = TscRequest {
+ method: "findRenameLocations",
+ // https://github.com/denoland/deno/blob/v1.37.1/cli/tsc/dts/typescript.d.ts#L6221
+ args: json!([
+ self.specifier_map.denormalize(&specifier),
+ position,
+ false,
+ false,
+ false,
+ ]),
};
self
.request::<Option<Vec<RenameLocation>>>(snapshot, req)
@@ -669,8 +769,11 @@ impl TsServer {
specifier: ModuleSpecifier,
position: u32,
) -> Result<SelectionRange, LspError> {
- let req = RequestMethod::GetSmartSelectionRange((specifier, position));
-
+ let req = TscRequest {
+ method: "getSmartSelectionRange",
+ // https://github.com/denoland/deno/blob/v1.37.1/cli/tsc/dts/typescript.d.ts#L6224
+ args: json!([self.specifier_map.denormalize(&specifier), position]),
+ };
self.request(snapshot, req).await.map_err(|err| {
log::error!("Failed to request to tsserver {}", err);
LspError::invalid_request()
@@ -683,13 +786,18 @@ impl TsServer {
specifier: ModuleSpecifier,
range: Range<u32>,
) -> Result<Classifications, LspError> {
- let req = RequestMethod::GetEncodedSemanticClassifications((
- specifier,
- TextSpan {
- start: range.start,
- length: range.end - range.start,
- },
- ));
+ let req = TscRequest {
+ method: "getEncodedSemanticClassifications",
+ // https://github.com/denoland/deno/blob/v1.37.1/cli/tsc/dts/typescript.d.ts#L6183
+ args: json!([
+ self.specifier_map.denormalize(&specifier),
+ TextSpan {
+ start: range.start,
+ length: range.end - range.start,
+ },
+ "2020",
+ ]),
+ };
self.request(snapshot, req).await.map_err(|err| {
log::error!("Failed to request to tsserver {}", err);
LspError::invalid_request()
@@ -703,8 +811,15 @@ impl TsServer {
position: u32,
options: SignatureHelpItemsOptions,
) -> Result<Option<SignatureHelpItems>, LspError> {
- let req =
- RequestMethod::GetSignatureHelpItems((specifier, position, options));
+ let req = TscRequest {
+ method: "getSignatureHelpItems",
+ // https://github.com/denoland/deno/blob/v1.37.1/cli/tsc/dts/typescript.d.ts#L6217
+ args: json!([
+ self.specifier_map.denormalize(&specifier),
+ position,
+ options,
+ ]),
+ };
self.request(snapshot, req).await.map_err(|err| {
log::error!("Failed to request to tsserver: {}", err);
LspError::invalid_request()
@@ -716,7 +831,18 @@ impl TsServer {
snapshot: Arc<StateSnapshot>,
args: GetNavigateToItemsArgs,
) -> Result<Vec<NavigateToItem>, LspError> {
- let req = RequestMethod::GetNavigateToItems(args);
+ let req = TscRequest {
+ method: "getNavigateToItems",
+ // https://github.com/denoland/deno/blob/v1.37.1/cli/tsc/dts/typescript.d.ts#L6233
+ args: json!([
+ args.search,
+ args.max_result_count,
+ args.file.map(|f| match resolve_url(&f) {
+ Ok(s) => self.specifier_map.denormalize(&s),
+ Err(_) => f,
+ }),
+ ]),
+ };
self
.request::<Vec<NavigateToItem>>(snapshot, req)
.await
@@ -739,11 +865,15 @@ impl TsServer {
text_span: TextSpan,
user_preferences: UserPreferences,
) -> Result<Option<Vec<InlayHint>>, LspError> {
- let req = RequestMethod::ProvideInlayHints((
- specifier,
- text_span,
- user_preferences,
- ));
+ let req = TscRequest {
+ method: "provideInlayHints",
+ // https://github.com/denoland/deno/blob/v1.37.1/cli/tsc/dts/typescript.d.ts#L6239
+ args: json!([
+ self.specifier_map.denormalize(&specifier),
+ text_span,
+ user_preferences,
+ ]),
+ };
self.request(snapshot, req).await.map_err(|err| {
log::error!("Unable to get inlay hints: {}", err);
LspError::internal_error()
@@ -751,16 +881,17 @@ impl TsServer {
}
pub async fn restart(&self, snapshot: Arc<StateSnapshot>) {
- let _: bool = self
- .request(snapshot, RequestMethod::Restart)
- .await
- .unwrap();
+ let req = TscRequest {
+ method: "$restart",
+ args: json!([]),
+ };
+ self.request::<bool>(snapshot, req).await.unwrap();
}
async fn request<R>(
&self,
snapshot: Arc<StateSnapshot>,
- req: RequestMethod,
+ req: TscRequest,
) -> Result<R, AnyError>
where
R: de::DeserializeOwned,
@@ -773,7 +904,7 @@ impl TsServer {
async fn request_with_cancellation<R>(
&self,
snapshot: Arc<StateSnapshot>,
- req: RequestMethod,
+ req: TscRequest,
token: CancellationToken,
) -> Result<R, AnyError>
where
@@ -930,10 +1061,11 @@ async fn get_isolate_assets(
ts_server: &TsServer,
state_snapshot: Arc<StateSnapshot>,
) -> Vec<AssetDocument> {
- let res: Value = ts_server
- .request(state_snapshot, RequestMethod::GetAssets)
- .await
- .unwrap();
+ let req = TscRequest {
+ method: "$getAssets",
+ args: json!([]),
+ };
+ let res: Value = ts_server.request(state_snapshot, req).await.unwrap();
let response_assets = match res {
Value::Array(value) => value,
_ => unreachable!(),
@@ -1277,6 +1409,7 @@ pub struct SymbolDisplayPart {
// This is only on `JSDocLinkDisplayPart` which extends `SymbolDisplayPart`
// but is only used as an upcast of a `SymbolDisplayPart` and not explicitly
// returned by any API, so it is safe to add it as an optional value.
+ #[serde(skip_serializing_if = "Option::is_none")]
target: Option<DocumentSpan>,
}
@@ -1442,7 +1575,7 @@ pub struct DocumentSpan {
}
impl DocumentSpan {
- pub fn normalize(
+ fn normalize(
&mut self,
specifier_map: &TscSpecifierMap,
) -> Result<(), AnyError> {
@@ -1457,7 +1590,7 @@ impl DocumentSpan {
line_index: Arc<LineIndex>,
language_server: &language_server::Inner,
) -> Option<lsp::LocationLink> {
- let target_specifier = normalize_specifier(&self.file_name).ok()?;
+ let target_specifier = resolve_url(&self.file_name).ok()?;
let target_asset_or_doc =
language_server.get_maybe_asset_or_document(&target_specifier)?;
let target_line_index = target_asset_or_doc.line_index();
@@ -1502,7 +1635,7 @@ impl DocumentSpan {
&self,
language_server: &language_server::Inner,
) -> Option<ModuleSpecifier> {
- let specifier = normalize_specifier(&self.file_name).ok()?;
+ let specifier = resolve_url(&self.file_name).ok()?;
let asset_or_doc =
language_server.get_maybe_asset_or_document(&specifier)?;
let line_index = asset_or_doc.line_index();
@@ -1549,7 +1682,7 @@ pub struct NavigateToItem {
}
impl NavigateToItem {
- pub fn normalize(
+ fn normalize(
&mut self,
specifier_map: &TscSpecifierMap,
) -> Result<(), AnyError> {
@@ -1563,7 +1696,7 @@ impl NavigateToItem {
&self,
language_server: &language_server::Inner,
) -> Option<lsp::SymbolInformation> {
- let specifier = normalize_specifier(&self.file_name).ok()?;
+ let specifier = resolve_url(&self.file_name).ok()?;
let asset_or_doc =
language_server.get_asset_or_document(&specifier).ok()?;
let line_index = asset_or_doc.line_index();
@@ -1810,7 +1943,7 @@ pub struct ImplementationLocation {
}
impl ImplementationLocation {
- pub fn normalize(
+ fn normalize(
&mut self,
specifier_map: &TscSpecifierMap,
) -> Result<(), AnyError> {
@@ -1823,7 +1956,7 @@ impl ImplementationLocation {
line_index: Arc<LineIndex>,
language_server: &language_server::Inner,
) -> lsp::Location {
- let specifier = normalize_specifier(&self.document_span.file_name)
+ let specifier = resolve_url(&self.document_span.file_name)
.unwrap_or_else(|_| ModuleSpecifier::parse("deno://invalid").unwrap());
let uri = language_server
.url_map
@@ -1857,7 +1990,7 @@ pub struct RenameLocation {
}
impl RenameLocation {
- pub fn normalize(
+ fn normalize(
&mut self,
specifier_map: &TscSpecifierMap,
) -> Result<(), AnyError> {
@@ -1881,7 +2014,7 @@ impl RenameLocations {
lsp::TextDocumentEdit,
> = HashMap::new();
for location in self.locations.iter() {
- let specifier = normalize_specifier(&location.document_span.file_name)?;
+ let specifier = resolve_url(&location.document_span.file_name)?;
let uri = language_server.url_map.normalize_specifier(&specifier)?;
let asset_or_doc = language_server.get_asset_or_document(&specifier)?;
@@ -1955,7 +2088,7 @@ pub struct DefinitionInfo {
}
impl DefinitionInfo {
- pub fn normalize(
+ fn normalize(
&mut self,
specifier_map: &TscSpecifierMap,
) -> Result<(), AnyError> {
@@ -1972,7 +2105,7 @@ pub struct DefinitionInfoAndBoundSpan {
}
impl DefinitionInfoAndBoundSpan {
- pub fn normalize(
+ fn normalize(
&mut self,
specifier_map: &TscSpecifierMap,
) -> Result<(), AnyError> {
@@ -2068,7 +2201,7 @@ pub struct FileTextChanges {
}
impl FileTextChanges {
- pub fn normalize(
+ fn normalize(
&mut self,
specifier_map: &TscSpecifierMap,
) -> Result<(), AnyError> {
@@ -2080,7 +2213,7 @@ impl FileTextChanges {
&self,
language_server: &language_server::Inner,
) -> Result<lsp::TextDocumentEdit, AnyError> {
- let specifier = normalize_specifier(&self.file_name)?;
+ let specifier = resolve_url(&self.file_name)?;
let asset_or_doc = language_server.get_asset_or_document(&specifier)?;
let edits = self
.text_changes
@@ -2101,7 +2234,7 @@ impl FileTextChanges {
language_server: &language_server::Inner,
) -> Result<Vec<lsp::DocumentChangeOperation>, AnyError> {
let mut ops = Vec::<lsp::DocumentChangeOperation>::new();
- let specifier = normalize_specifier(&self.file_name)?;
+ let specifier = resolve_url(&self.file_name)?;
let maybe_asset_or_document = if !self.is_new_file.unwrap_or(false) {
let asset_or_doc = language_server.get_asset_or_document(&specifier)?;
Some(asset_or_doc)
@@ -2355,7 +2488,7 @@ pub struct RefactorEditInfo {
}
impl RefactorEditInfo {
- pub fn normalize(
+ fn normalize(
&mut self,
specifier_map: &TscSpecifierMap,
) -> Result<(), AnyError> {
@@ -2383,7 +2516,7 @@ pub struct CodeAction {
}
impl CodeAction {
- pub fn normalize(
+ fn normalize(
&mut self,
specifier_map: &TscSpecifierMap,
) -> Result<(), AnyError> {
@@ -2416,7 +2549,7 @@ pub struct CodeFixAction {
}
impl CodeFixAction {
- pub fn normalize(
+ fn normalize(
&mut self,
specifier_map: &TscSpecifierMap,
) -> Result<(), AnyError> {
@@ -2435,7 +2568,7 @@ pub struct CombinedCodeActions {
}
impl CombinedCodeActions {
- pub fn normalize(
+ fn normalize(
&mut self,
specifier_map: &TscSpecifierMap,
) -> Result<(), AnyError> {
@@ -2454,7 +2587,7 @@ pub struct ReferencedSymbol {
}
impl ReferencedSymbol {
- pub fn normalize(
+ fn normalize(
&mut self,
specifier_map: &TscSpecifierMap,
) -> Result<(), AnyError> {
@@ -2474,7 +2607,7 @@ pub struct ReferencedSymbolDefinitionInfo {
}
impl ReferencedSymbolDefinitionInfo {
- pub fn normalize(
+ fn normalize(
&mut self,
specifier_map: &TscSpecifierMap,
) -> Result<(), AnyError> {
@@ -2493,7 +2626,7 @@ pub struct ReferencedSymbolEntry {
}
impl ReferencedSymbolEntry {
- pub fn normalize(
+ fn normalize(
&mut self,
specifier_map: &TscSpecifierMap,
) -> Result<(), AnyError> {
@@ -2512,7 +2645,7 @@ pub struct ReferenceEntry {
}
impl ReferenceEntry {
- pub fn normalize(
+ fn normalize(
&mut self,
specifier_map: &TscSpecifierMap,
) -> Result<(), AnyError> {
@@ -2527,7 +2660,7 @@ impl ReferenceEntry {
line_index: Arc<LineIndex>,
url_map: &LspUrlMap,
) -> lsp::Location {
- let specifier = normalize_specifier(&self.document_span.file_name)
+ let specifier = resolve_url(&self.document_span.file_name)
.unwrap_or_else(|_| INVALID_SPECIFIER.clone());
let uri = url_map
.normalize_specifier(&specifier)
@@ -2554,7 +2687,7 @@ pub struct CallHierarchyItem {
}
impl CallHierarchyItem {
- pub fn normalize(
+ fn normalize(
&mut self,
specifier_map: &TscSpecifierMap,
) -> Result<(), AnyError> {
@@ -2567,7 +2700,7 @@ impl CallHierarchyItem {
language_server: &language_server::Inner,
maybe_root_path: Option<&Path>,
) -> Option<lsp::CallHierarchyItem> {
- let target_specifier = normalize_specifier(&self.file).ok()?;
+ let target_specifier = resolve_url(&self.file).ok()?;
let target_asset_or_doc =
language_server.get_maybe_asset_or_document(&target_specifier)?;
@@ -2584,8 +2717,8 @@ impl CallHierarchyItem {
language_server: &language_server::Inner,
maybe_root_path: Option<&Path>,
) -> lsp::CallHierarchyItem {
- let target_specifier = normalize_specifier(&self.file)
- .unwrap_or_else(|_| INVALID_SPECIFIER.clone());
+ let target_specifier =
+ resolve_url(&self.file).unwrap_or_else(|_| INVALID_SPECIFIER.clone());
let uri = language_server
.url_map
.normalize_specifier(&target_specifier)
@@ -2661,7 +2794,7 @@ pub struct CallHierarchyIncomingCall {
}
impl CallHierarchyIncomingCall {
- pub fn normalize(
+ fn normalize(
&mut self,
specifier_map: &TscSpecifierMap,
) -> Result<(), AnyError> {
@@ -2674,7 +2807,7 @@ impl CallHierarchyIncomingCall {
language_server: &language_server::Inner,
maybe_root_path: Option<&Path>,
) -> Option<lsp::CallHierarchyIncomingCall> {
- let target_specifier = normalize_specifier(&self.from.file).ok()?;
+ let target_specifier = resolve_url(&self.from.file).ok()?;
let target_asset_or_doc =
language_server.get_maybe_asset_or_document(&target_specifier)?;
@@ -2701,7 +2834,7 @@ pub struct CallHierarchyOutgoingCall {
}
impl CallHierarchyOutgoingCall {
- pub fn normalize(
+ fn normalize(
&mut self,
specifier_map: &TscSpecifierMap,
) -> Result<(), AnyError> {
@@ -2715,7 +2848,7 @@ impl CallHierarchyOutgoingCall {
language_server: &language_server::Inner,
maybe_root_path: Option<&Path>,
) -> Option<lsp::CallHierarchyOutgoingCall> {
- let target_specifier = normalize_specifier(&self.to.file).ok()?;
+ let target_specifier = resolve_url(&self.to.file).ok()?;
let target_asset_or_doc =
language_server.get_maybe_asset_or_document(&target_specifier)?;
@@ -2753,8 +2886,7 @@ fn parse_code_actions(
let asset_or_doc =
language_server.get_asset_or_document(&data.specifier)?;
for change in &ts_action.changes {
- let change_specifier = normalize_specifier(&change.file_name)?;
- if data.specifier == change_specifier {
+ if data.specifier.as_str() == change.file_name {
additional_text_edits.extend(change.text_changes.iter().map(|tc| {
let mut text_edit = tc.as_text_edit(asset_or_doc.line_index());
if let Some(specifier_rewrite) = &data.specifier_rewrite {
@@ -2779,9 +2911,7 @@ fn parse_code_actions(
.changes
.clone()
.into_iter()
- .filter(|ch| {
- normalize_specifier(&ch.file_name).unwrap() == data.specifier
- })
+ .filter(|ch| ch.file_name == data.specifier.as_str())
.collect();
json!({
"commands": ca.commands,
@@ -2855,16 +2985,19 @@ fn get_parameters_from_parts(parts: &[SymbolDisplayPart]) -> Vec<String> {
pub struct CompletionEntryDetails {
display_parts: Vec<SymbolDisplayPart>,
documentation: Option<Vec<SymbolDisplayPart>>,
+ #[serde(skip_serializing_if = "Option::is_none")]
tags: Option<Vec<JsDocTagInfo>>,
name: String,
kind: ScriptElementKind,
kind_modifiers: String,
+ #[serde(skip_serializing_if = "Option::is_none")]
code_actions: Option<Vec<CodeAction>>,
+ #[serde(skip_serializing_if = "Option::is_none")]
source_display: Option<Vec<SymbolDisplayPart>>,
}
impl CompletionEntryDetails {
- pub fn normalize(
+ fn normalize(
&mut self,
specifier_map: &TscSpecifierMap,
) -> Result<(), AnyError> {
@@ -3211,9 +3344,7 @@ impl CompletionEntry {
if let Ok(import_data) =
serde_json::from_value::<CompletionEntryDataImport>(data.clone())
{
- if let Ok(import_specifier) =
- normalize_specifier(import_data.file_name)
- {
+ if let Ok(import_specifier) = resolve_url(&import_data.file_name) {
if let Some(new_module_specifier) = language_server
.get_ts_response_import_mapper()
.check_specifier(&import_specifier, specifier)
@@ -3521,6 +3652,10 @@ pub struct TscSpecifierMap {
}
impl TscSpecifierMap {
+ pub fn new() -> Self {
+ Self::default()
+ }
+
/// Convert the specifier to one compatible with tsc. Cache the resulting
/// mapping in case it needs to be reversed.
// TODO(nayeemrmn): Factor in out-of-band media type here.
@@ -3632,13 +3767,6 @@ impl State {
}
}
-fn normalize_specifier<S: AsRef<str>>(
- specifier: S,
-) -> Result<ModuleSpecifier, AnyError> {
- resolve_url(specifier.as_ref().replace(".d.ts.d.ts", ".d.ts").as_str())
- .map_err(|err| err.into())
-}
-
#[derive(Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
struct SpecifierArgs {
@@ -4214,404 +4342,20 @@ pub struct GetNavigateToItemsArgs {
pub file: Option<String>,
}
-/// Methods that are supported by the Language Service in the compiler isolate.
-#[derive(Debug)]
-enum RequestMethod {
- /// Configure the compilation settings for the server.
- Configure(TsConfig),
- /// Get rename locations at a given position.
- FindRenameLocations {
- specifier: ModuleSpecifier,
- position: u32,
- find_in_strings: bool,
- find_in_comments: bool,
- provide_prefix_and_suffix_text_for_rename: bool,
- },
- GetAssets,
- /// Retrieve the possible refactor info for a range of a file.
- GetApplicableRefactors(
- (ModuleSpecifier, TextSpan, Option<UserPreferences>, String),
- ),
- /// Retrieve the refactor edit info for a range.
- GetEditsForRefactor(
- (
- ModuleSpecifier,
- FormatCodeSettings,
- TextSpan,
- String,
- String,
- Option<UserPreferences>,
- ),
- ),
- /// Retrieve the refactor edit info for a range.
- GetEditsForFileRename(
- (
- ModuleSpecifier,
- ModuleSpecifier,
- FormatCodeSettings,
- UserPreferences,
- ),
- ),
- /// Retrieve code fixes for a range of a file with the provided error codes.
- GetCodeFixes(
- (
- ModuleSpecifier,
- u32,
- u32,
- Vec<String>,
- FormatCodeSettings,
- UserPreferences,
- ),
- ),
- /// Get completion information at a given position (IntelliSense).
- GetCompletions(
- (
- ModuleSpecifier,
- u32,
- GetCompletionsAtPositionOptions,
- FormatCodeSettings,
- ),
- ),
- /// Get details about a specific completion entry.
- GetCompletionDetails(GetCompletionDetailsArgs),
- /// Retrieve the combined code fixes for a fix id for a module.
- GetCombinedCodeFix(
- (ModuleSpecifier, Value, FormatCodeSettings, UserPreferences),
- ),
- /// Get declaration information for a specific position.
- GetDefinition((ModuleSpecifier, u32)),
- /// Return diagnostics for given file.
- GetDiagnostics(Vec<ModuleSpecifier>),
- /// Return document highlights at position.
- GetDocumentHighlights((ModuleSpecifier, u32, Vec<ModuleSpecifier>)),
- /// Get semantic highlights information for a particular file.
- GetEncodedSemanticClassifications((ModuleSpecifier, TextSpan)),
- /// Get implementation information for a specific position.
- GetImplementation((ModuleSpecifier, u32)),
- /// Get "navigate to" items, which are converted to workspace symbols
- GetNavigateToItems(GetNavigateToItemsArgs),
- /// Get a "navigation tree" for a specifier.
- GetNavigationTree(ModuleSpecifier),
- /// Get outlining spans for a specifier.
- GetOutliningSpans(ModuleSpecifier),
- /// Return quick info at position (hover information).
- GetQuickInfo((ModuleSpecifier, u32)),
- /// Finds the document references for a specific position.
- FindReferences {
- specifier: ModuleSpecifier,
- position: u32,
- },
- /// Get signature help items for a specific position.
- GetSignatureHelpItems((ModuleSpecifier, u32, SignatureHelpItemsOptions)),
- /// Get a selection range for a specific position.
- GetSmartSelectionRange((ModuleSpecifier, u32)),
- /// Get the diagnostic codes that support some form of code fix.
- GetSupportedCodeFixes,
- /// Get the type definition information for a specific position.
- GetTypeDefinition {
- specifier: ModuleSpecifier,
- position: u32,
- },
- /// Resolve a call hierarchy item for a specific position.
- PrepareCallHierarchy((ModuleSpecifier, u32)),
- /// Resolve incoming call hierarchy items for a specific position.
- ProvideCallHierarchyIncomingCalls((ModuleSpecifier, u32)),
- /// Resolve outgoing call hierarchy items for a specific position.
- ProvideCallHierarchyOutgoingCalls((ModuleSpecifier, u32)),
- /// Resolve inlay hints for a specific text span
- ProvideInlayHints((ModuleSpecifier, TextSpan, UserPreferences)),
-
- // Special request, used only internally by the LSP
- Restart,
-}
-
-impl RequestMethod {
- fn to_value(&self, state: &mut State, id: usize) -> Value {
- match self {
- RequestMethod::Configure(config) => json!({
- "id": id,
- "method": "configure",
- "compilerOptions": config,
- }),
- RequestMethod::FindRenameLocations {
- specifier,
- position,
- find_in_strings,
- find_in_comments,
- provide_prefix_and_suffix_text_for_rename,
- } => {
- json!({
- "id": id,
- "method": "findRenameLocations",
- "specifier": state.specifier_map.denormalize(specifier),
- "position": position,
- "findInStrings": find_in_strings,
- "findInComments": find_in_comments,
- "providePrefixAndSuffixTextForRename": provide_prefix_and_suffix_text_for_rename
- })
- }
- RequestMethod::GetAssets => json!({
- "id": id,
- "method": "getAssets",
- }),
- RequestMethod::GetApplicableRefactors((
- specifier,
- span,
- preferences,
- kind,
- )) => json!({
- "id": id,
- "method": "getApplicableRefactors",
- "specifier": state.specifier_map.denormalize(specifier),
- "range": { "pos": span.start, "end": span.start + span.length },
- "preferences": preferences,
- "kind": kind,
- }),
- RequestMethod::GetEditsForRefactor((
- specifier,
- format_code_settings,
- span,
- refactor_name,
- action_name,
- preferences,
- )) => json!({
- "id": id,
- "method": "getEditsForRefactor",
- "specifier": state.specifier_map.denormalize(specifier),
- "formatCodeSettings": format_code_settings,
- "range": { "pos": span.start, "end": span.start + span.length},
- "refactorName": refactor_name,
- "actionName": action_name,
- "preferences": preferences,
- }),
- RequestMethod::GetEditsForFileRename((
- old_specifier,
- new_specifier,
- format_code_settings,
- preferences,
- )) => json!({
- "id": id,
- "method": "getEditsForFileRename",
- "oldSpecifier": state.specifier_map.denormalize(old_specifier),
- "newSpecifier": state.specifier_map.denormalize(new_specifier),
- "formatCodeSettings": format_code_settings,
- "preferences": preferences,
- }),
- RequestMethod::GetCodeFixes((
- specifier,
- start_pos,
- end_pos,
- error_codes,
- format_code_settings,
- preferences,
- )) => json!({
- "id": id,
- "method": "getCodeFixes",
- "specifier": state.specifier_map.denormalize(specifier),
- "startPosition": start_pos,
- "endPosition": end_pos,
- "errorCodes": error_codes,
- "formatCodeSettings": format_code_settings,
- "preferences": preferences,
- }),
- RequestMethod::GetCombinedCodeFix((
- specifier,
- fix_id,
- format_code_settings,
- preferences,
- )) => json!({
- "id": id,
- "method": "getCombinedCodeFix",
- "specifier": state.specifier_map.denormalize(specifier),
- "fixId": fix_id,
- "formatCodeSettings": format_code_settings,
- "preferences": preferences,
- }),
- RequestMethod::GetCompletionDetails(args) => {
- let mut args = json!(args);
- let specifier =
- args.as_object_mut().unwrap().get_mut("specifier").unwrap();
- if let Ok(s) = ModuleSpecifier::parse(specifier.as_str().unwrap()) {
- *specifier = json!(state.specifier_map.denormalize(&s));
- }
- json!({
- "id": id,
- "method": "getCompletionDetails",
- "args": args
- })
- }
- RequestMethod::GetCompletions((
- specifier,
- position,
- preferences,
- format_code_settings,
- )) => {
- json!({
- "id": id,
- "method": "getCompletions",
- "specifier": state.specifier_map.denormalize(specifier),
- "position": position,
- "preferences": preferences,
- "formatCodeSettings": format_code_settings,
- })
- }
- RequestMethod::GetDefinition((specifier, position)) => json!({
- "id": id,
- "method": "getDefinition",
- "specifier": state.specifier_map.denormalize(specifier),
- "position": position,
- }),
- RequestMethod::GetDiagnostics(specifiers) => json!({
- "id": id,
- "method": "getDiagnostics",
- "specifiers": specifiers.iter().map(|s| state.specifier_map.denormalize(s)).collect::<Vec<String>>(),
- }),
- RequestMethod::GetDocumentHighlights((
- specifier,
- position,
- files_to_search,
- )) => json!({
- "id": id,
- "method": "getDocumentHighlights",
- "specifier": state.specifier_map.denormalize(specifier),
- "position": position,
- "filesToSearch": files_to_search.iter().map(|s| state.specifier_map.denormalize(s)).collect::<Vec<_>>(),
- }),
- RequestMethod::GetEncodedSemanticClassifications((specifier, span)) => {
- json!({
- "id": id,
- "method": "getEncodedSemanticClassifications",
- "specifier": state.specifier_map.denormalize(specifier),
- "span": span,
- })
- }
- RequestMethod::GetImplementation((specifier, position)) => json!({
- "id": id,
- "method": "getImplementation",
- "specifier": state.specifier_map.denormalize(specifier),
- "position": position,
- }),
- RequestMethod::GetNavigateToItems(GetNavigateToItemsArgs {
- search,
- max_result_count,
- file,
- }) => json!({
- "id": id,
- "method": "getNavigateToItems",
- "search": search,
- "maxResultCount": max_result_count,
- "file": file,
- }),
- RequestMethod::GetNavigationTree(specifier) => json!({
- "id": id,
- "method": "getNavigationTree",
- "specifier": state.specifier_map.denormalize(specifier),
- }),
- RequestMethod::GetOutliningSpans(specifier) => json!({
- "id": id,
- "method": "getOutliningSpans",
- "specifier": state.specifier_map.denormalize(specifier),
- }),
- RequestMethod::GetQuickInfo((specifier, position)) => json!({
- "id": id,
- "method": "getQuickInfo",
- "specifier": state.specifier_map.denormalize(specifier),
- "position": position,
- }),
- RequestMethod::FindReferences {
- specifier,
- position,
- } => json!({
- "id": id,
- "method": "findReferences",
- "specifier": state.specifier_map.denormalize(specifier),
- "position": position,
- }),
- RequestMethod::GetSignatureHelpItems((specifier, position, options)) => {
- json!({
- "id": id,
- "method": "getSignatureHelpItems",
- "specifier": state.specifier_map.denormalize(specifier),
- "position": position,
- "options": options,
- })
- }
- RequestMethod::GetSmartSelectionRange((specifier, position)) => {
- json!({
- "id": id,
- "method": "getSmartSelectionRange",
- "specifier": state.specifier_map.denormalize(specifier),
- "position": position
- })
- }
- RequestMethod::GetSupportedCodeFixes => json!({
- "id": id,
- "method": "getSupportedCodeFixes",
- }),
- RequestMethod::GetTypeDefinition {
- specifier,
- position,
- } => json!({
- "id": id,
- "method": "getTypeDefinition",
- "specifier": state.specifier_map.denormalize(specifier),
- "position": position
- }),
- RequestMethod::PrepareCallHierarchy((specifier, position)) => {
- json!({
- "id": id,
- "method": "prepareCallHierarchy",
- "specifier": state.specifier_map.denormalize(specifier),
- "position": position
- })
- }
- RequestMethod::ProvideCallHierarchyIncomingCalls((
- specifier,
- position,
- )) => {
- json!({
- "id": id,
- "method": "provideCallHierarchyIncomingCalls",
- "specifier": state.specifier_map.denormalize(specifier),
- "position": position
- })
- }
- RequestMethod::ProvideCallHierarchyOutgoingCalls((
- specifier,
- position,
- )) => {
- json!({
- "id": id,
- "method": "provideCallHierarchyOutgoingCalls",
- "specifier": state.specifier_map.denormalize(specifier),
- "position": position
- })
- }
- RequestMethod::ProvideInlayHints((specifier, span, preferences)) => {
- json!({
- "id": id,
- "method": "provideInlayHints",
- "specifier": state.specifier_map.denormalize(specifier),
- "span": span,
- "preferences": preferences,
- })
- }
- RequestMethod::Restart => json!({
- "id": id,
- "method": "restart",
- }),
- }
- }
+#[derive(Clone, Debug)]
+struct TscRequest {
+ method: &'static str,
+ args: Value,
}
/// Send a request into a runtime and return the JSON value of the response.
fn request(
runtime: &mut JsRuntime,
state_snapshot: Arc<StateSnapshot>,
- method: RequestMethod,
+ request: TscRequest,
token: CancellationToken,
) -> Result<Value, AnyError> {
- let (performance, request_params) = {
+ let (performance, id) = {
let op_state = runtime.op_state();
let mut op_state = op_state.borrow_mut();
let state = op_state.borrow_mut::<State>();
@@ -4619,10 +4363,18 @@ fn request(
state.token = token;
state.last_id += 1;
let id = state.last_id;
- (state.performance.clone(), method.to_value(state, id))
+ (state.performance.clone(), id)
};
- let mark = performance.mark("request", Some(request_params.clone()));
- let request_src = format!("globalThis.serverRequest({request_params});");
+ let mark =
+ performance.mark("request", Some((request.method, request.args.clone())));
+ assert!(
+ request.args.is_array(),
+ "Internal error: expected args to be array"
+ );
+ let request_src = format!(
+ "globalThis.serverRequest({id}, \"{}\", {});",
+ request.method, &request.args
+ );
runtime.execute_script(located_script_name!(), request_src.into())?;
let op_state = runtime.op_state();
@@ -4653,10 +4405,8 @@ mod tests {
use crate::lsp::documents::Documents;
use crate::lsp::documents::LanguageId;
use crate::lsp::text::LineIndex;
- use crate::tsc::AssetText;
use pretty_assertions::assert_eq;
use std::path::Path;
- use std::path::PathBuf;
use test_util::TempDir;
fn mock_state_snapshot(
@@ -4688,30 +4438,23 @@ mod tests {
}
}
- fn setup(
+ async fn setup(
temp_dir: &TempDir,
- debug: bool,
config: Value,
sources: &[(&str, &str, i32, LanguageId)],
- ) -> (JsRuntime, Arc<StateSnapshot>, PathBuf) {
+ ) -> (TsServer, Arc<StateSnapshot>, Arc<GlobalHttpCache>) {
let location = temp_dir.path().join("deps").to_path_buf();
let cache =
Arc::new(GlobalHttpCache::new(location.clone(), RealDenoCacheEnv));
- let state_snapshot = Arc::new(mock_state_snapshot(sources, &location));
- let mut runtime = js_runtime(Default::default(), cache, Default::default());
- start(&mut runtime, debug).unwrap();
+ let snapshot = Arc::new(mock_state_snapshot(sources, &location));
+ let performance = Arc::new(Performance::default());
+ let ts_server = TsServer::new(performance, cache.clone());
let ts_config = TsConfig::new(config);
- assert_eq!(
- request(
- &mut runtime,
- state_snapshot.clone(),
- RequestMethod::Configure(ts_config),
- Default::default(),
- )
- .expect("failed request"),
- json!(true)
- );
- (runtime, state_snapshot, location)
+ assert!(ts_server
+ .configure(snapshot.clone(), ts_config,)
+ .await
+ .unwrap());
+ (ts_server, snapshot, cache)
}
#[test]
@@ -4729,57 +4472,48 @@ mod tests {
assert_eq!(actual, r"test [`a link`](http://deno.land/x/mod.ts) test");
}
- #[test]
- fn test_project_configure() {
+ #[tokio::test]
+ async fn test_project_configure() {
let temp_dir = TempDir::new();
setup(
&temp_dir,
- false,
json!({
"target": "esnext",
"module": "esnext",
"noEmit": true,
}),
&[],
- );
+ )
+ .await;
}
- #[test]
- fn test_project_reconfigure() {
+ #[tokio::test]
+ async fn test_project_reconfigure() {
let temp_dir = TempDir::new();
- let (mut runtime, state_snapshot, _) = setup(
+ let (ts_server, snapshot, _) = setup(
&temp_dir,
- false,
json!({
"target": "esnext",
"module": "esnext",
"noEmit": true,
}),
&[],
- );
+ )
+ .await;
let ts_config = TsConfig::new(json!({
"target": "esnext",
"module": "esnext",
"noEmit": true,
"lib": ["deno.ns", "deno.worker"]
}));
- let result = request(
- &mut runtime,
- state_snapshot,
- RequestMethod::Configure(ts_config),
- Default::default(),
- );
- assert!(result.is_ok());
- let response = result.unwrap();
- assert_eq!(response, json!(true));
+ assert!(ts_server.configure(snapshot, ts_config).await.unwrap());
}
- #[test]
- fn test_get_diagnostics() {
+ #[tokio::test]
+ async fn test_get_diagnostics() {
let temp_dir = TempDir::new();
- let (mut runtime, state_snapshot, _) = setup(
+ let (ts_server, snapshot, _) = setup(
&temp_dir,
- false,
json!({
"target": "esnext",
"module": "esnext",
@@ -4791,18 +4525,15 @@ mod tests {
1,
LanguageId::TypeScript,
)],
- );
+ )
+ .await;
let specifier = resolve_url("file:///a.ts").expect("could not resolve url");
- let result = request(
- &mut runtime,
- state_snapshot,
- RequestMethod::GetDiagnostics(vec![specifier]),
- Default::default(),
- );
- assert!(result.is_ok());
- let response = result.unwrap();
+ let diagnostics = ts_server
+ .get_diagnostics(snapshot, vec![specifier], Default::default())
+ .await
+ .unwrap();
assert_eq!(
- response,
+ json!(diagnostics),
json!({
"file:///a.ts": [
{
@@ -4825,12 +4556,11 @@ mod tests {
);
}
- #[test]
- fn test_get_diagnostics_lib() {
+ #[tokio::test]
+ async fn test_get_diagnostics_lib() {
let temp_dir = TempDir::new();
- let (mut runtime, state_snapshot, _) = setup(
+ let (ts_server, snapshot, _) = setup(
&temp_dir,
- false,
json!({
"target": "esnext",
"module": "esnext",
@@ -4844,25 +4574,21 @@ mod tests {
1,
LanguageId::TypeScript,
)],
- );
+ )
+ .await;
let specifier = resolve_url("file:///a.ts").expect("could not resolve url");
- let result = request(
- &mut runtime,
- state_snapshot,
- RequestMethod::GetDiagnostics(vec![specifier]),
- Default::default(),
- );
- assert!(result.is_ok());
- let response = result.unwrap();
- assert_eq!(response, json!({ "file:///a.ts": [] }));
+ let diagnostics = ts_server
+ .get_diagnostics(snapshot, vec![specifier], Default::default())
+ .await
+ .unwrap();
+ assert_eq!(json!(diagnostics), json!({ "file:///a.ts": [] }));
}
- #[test]
- fn test_module_resolution() {
+ #[tokio::test]
+ async fn test_module_resolution() {
let temp_dir = TempDir::new();
- let (mut runtime, state_snapshot, _) = setup(
+ let (ts_server, snapshot, _) = setup(
&temp_dir,
- false,
json!({
"target": "esnext",
"module": "esnext",
@@ -4881,25 +4607,21 @@ mod tests {
1,
LanguageId::TypeScript,
)],
- );
+ )
+ .await;
let specifier = resolve_url("file:///a.ts").expect("could not resolve url");
- let result = request(
- &mut runtime,
- state_snapshot,
- RequestMethod::GetDiagnostics(vec![specifier]),
- Default::default(),
- );
- assert!(result.is_ok());
- let response = result.unwrap();
- assert_eq!(response, json!({ "file:///a.ts": [] }));
+ let diagnostics = ts_server
+ .get_diagnostics(snapshot, vec![specifier], Default::default())
+ .await
+ .unwrap();
+ assert_eq!(json!(diagnostics), json!({ "file:///a.ts": [] }));
}
- #[test]
- fn test_bad_module_specifiers() {
+ #[tokio::test]
+ async fn test_bad_module_specifiers() {
let temp_dir = TempDir::new();
- let (mut runtime, state_snapshot, _) = setup(
+ let (ts_server, snapshot, _) = setup(
&temp_dir,
- false,
json!({
"target": "esnext",
"module": "esnext",
@@ -4914,18 +4636,15 @@ mod tests {
1,
LanguageId::TypeScript,
)],
- );
+ )
+ .await;
let specifier = resolve_url("file:///a.ts").expect("could not resolve url");
- let result = request(
- &mut runtime,
- state_snapshot,
- RequestMethod::GetDiagnostics(vec![specifier]),
- Default::default(),
- );
- assert!(result.is_ok());
- let response = result.unwrap();
+ let diagnostics = ts_server
+ .get_diagnostics(snapshot, vec![specifier], Default::default())
+ .await
+ .unwrap();
assert_eq!(
- response,
+ json!(diagnostics),
json!({
"file:///a.ts": [{
"start": {
@@ -4941,18 +4660,16 @@ mod tests {
"sourceLine": " import { A } from \".\";",
"category": 2,
"code": 6133,
- "reportsUnnecessary": true,
}]
})
);
}
- #[test]
- fn test_remote_modules() {
+ #[tokio::test]
+ async fn test_remote_modules() {
let temp_dir = TempDir::new();
- let (mut runtime, state_snapshot, _) = setup(
+ let (ts_server, snapshot, _) = setup(
&temp_dir,
- false,
json!({
"target": "esnext",
"module": "esnext",
@@ -4971,25 +4688,21 @@ mod tests {
1,
LanguageId::TypeScript,
)],
- );
+ )
+ .await;
let specifier = resolve_url("file:///a.ts").expect("could not resolve url");
- let result = request(
- &mut runtime,
- state_snapshot,
- RequestMethod::GetDiagnostics(vec![specifier]),
- Default::default(),
- );
- assert!(result.is_ok());
- let response = result.unwrap();
- assert_eq!(response, json!({ "file:///a.ts": [] }));
+ let diagnostics = ts_server
+ .get_diagnostics(snapshot, vec![specifier], Default::default())
+ .await
+ .unwrap();
+ assert_eq!(json!(diagnostics), json!({ "file:///a.ts": [] }));
}
- #[test]
- fn test_partial_modules() {
+ #[tokio::test]
+ async fn test_partial_modules() {
let temp_dir = TempDir::new();
- let (mut runtime, state_snapshot, _) = setup(
+ let (ts_server, snapshot, _) = setup(
&temp_dir,
- false,
json!({
"target": "esnext",
"module": "esnext",
@@ -5011,18 +4724,15 @@ mod tests {
1,
LanguageId::TypeScript,
)],
- );
+ )
+ .await;
let specifier = resolve_url("file:///a.ts").expect("could not resolve url");
- let result = request(
- &mut runtime,
- state_snapshot,
- RequestMethod::GetDiagnostics(vec![specifier]),
- Default::default(),
- );
- assert!(result.is_ok());
- let response = result.unwrap();
+ let diagnostics = ts_server
+ .get_diagnostics(snapshot, vec![specifier], Default::default())
+ .await
+ .unwrap();
assert_eq!(
- response,
+ json!(diagnostics),
json!({
"file:///a.ts": [{
"start": {
@@ -5038,7 +4748,6 @@ mod tests {
"sourceLine": " import {",
"category": 2,
"code": 6192,
- "reportsUnnecessary": true
}, {
"start": {
"line": 8,
@@ -5058,12 +4767,11 @@ mod tests {
);
}
- #[test]
- fn test_no_debug_failure() {
+ #[tokio::test]
+ async fn test_no_debug_failure() {
let temp_dir = TempDir::new();
- let (mut runtime, state_snapshot, _) = setup(
+ let (ts_server, snapshot, _) = setup(
&temp_dir,
- false,
json!({
"target": "esnext",
"module": "esnext",
@@ -5076,18 +4784,15 @@ mod tests {
1,
LanguageId::TypeScript,
)],
- );
+ )
+ .await;
let specifier = resolve_url("file:///a.ts").expect("could not resolve url");
- let result = request(
- &mut runtime,
- state_snapshot,
- RequestMethod::GetDiagnostics(vec![specifier]),
- Default::default(),
- );
- assert!(result.is_ok());
- let response = result.unwrap();
+ let diagnostics = ts_server
+ .get_diagnostics(snapshot, vec![specifier], Default::default())
+ .await
+ .unwrap();
assert_eq!(
- response,
+ json!(diagnostics),
json!({
"file:///a.ts": [
{
@@ -5110,23 +4815,16 @@ mod tests {
);
}
- #[test]
- fn test_request_assets() {
+ #[tokio::test]
+ async fn test_request_assets() {
let temp_dir = TempDir::new();
- let (mut runtime, state_snapshot, _) =
- setup(&temp_dir, false, json!({}), &[]);
- let result = request(
- &mut runtime,
- state_snapshot,
- RequestMethod::GetAssets,
- Default::default(),
- )
- .unwrap();
- let assets: Vec<AssetText> = serde_json::from_value(result).unwrap();
+ let (ts_server, snapshot, _) = setup(&temp_dir, json!({}), &[]).await;
+ let assets = get_isolate_assets(&ts_server, snapshot).await;
let mut asset_names = assets
.iter()
.map(|a| {
- a.specifier
+ a.specifier()
+ .to_string()
.replace("asset:///lib.", "")
.replace(".d.ts", "")
})
@@ -5135,29 +4833,25 @@ mod tests {
include_str!(concat!(env!("OUT_DIR"), "/lib_file_names.json")),
)
.unwrap();
-
asset_names.sort();
- expected_asset_names.sort();
- // You might have found this assertion starts failing after upgrading TypeScript.
- // Ensure build.rs is updated so these match.
+ expected_asset_names.sort();
assert_eq!(asset_names, expected_asset_names);
// get some notification when the size of the assets grows
let mut total_size = 0;
for asset in assets {
- total_size += asset.text.len();
+ total_size += asset.text().len();
}
assert!(total_size > 0);
assert!(total_size < 2_000_000); // currently as of TS 4.6, it's 0.7MB
}
- #[test]
- fn test_modify_sources() {
+ #[tokio::test]
+ async fn test_modify_sources() {
let temp_dir = TempDir::new();
- let (mut runtime, state_snapshot, location) = setup(
+ let (ts_server, snapshot, cache) = setup(
&temp_dir,
- false,
json!({
"target": "esnext",
"module": "esnext",
@@ -5175,8 +4869,8 @@ mod tests {
1,
LanguageId::TypeScript,
)],
- );
- let cache = Arc::new(GlobalHttpCache::new(location, RealDenoCacheEnv));
+ )
+ .await;
let specifier_dep =
resolve_url("https://deno.land/x/example/a.ts").unwrap();
cache
@@ -5187,16 +4881,12 @@ mod tests {
)
.unwrap();
let specifier = resolve_url("file:///a.ts").unwrap();
- let result = request(
- &mut runtime,
- state_snapshot.clone(),
- RequestMethod::GetDiagnostics(vec![specifier]),
- Default::default(),
- );
- assert!(result.is_ok());
- let response = result.unwrap();
+ let diagnostics = ts_server
+ .get_diagnostics(snapshot.clone(), vec![specifier], Default::default())
+ .await
+ .unwrap();
assert_eq!(
- response,
+ json!(diagnostics),
json!({
"file:///a.ts": [
{
@@ -5225,16 +4915,12 @@ mod tests {
)
.unwrap();
let specifier = resolve_url("file:///a.ts").unwrap();
- let result = request(
- &mut runtime,
- state_snapshot,
- RequestMethod::GetDiagnostics(vec![specifier]),
- Default::default(),
- );
- assert!(result.is_ok());
- let response = result.unwrap();
+ let diagnostics = ts_server
+ .get_diagnostics(snapshot.clone(), vec![specifier], Default::default())
+ .await
+ .unwrap();
assert_eq!(
- response,
+ json!(diagnostics),
json!({
"file:///a.ts": []
})
@@ -5270,8 +4956,8 @@ mod tests {
assert_eq!(actual, Some("abc".to_string()));
}
- #[test]
- fn test_completions() {
+ #[tokio::test]
+ async fn test_completions() {
let fixture = r#"
import { B } from "https://deno.land/x/b/mod.ts";
@@ -5287,9 +4973,8 @@ mod tests {
})
.unwrap();
let temp_dir = TempDir::new();
- let (mut runtime, state_snapshot, _) = setup(
+ let (ts_server, snapshot, _) = setup(
&temp_dir,
- false,
json!({
"target": "esnext",
"module": "esnext",
@@ -5297,19 +4982,12 @@ mod tests {
"noEmit": true,
}),
&[("file:///a.ts", fixture, 1, LanguageId::TypeScript)],
- );
+ )
+ .await;
let specifier = resolve_url("file:///a.ts").expect("could not resolve url");
- let result = request(
- &mut runtime,
- state_snapshot.clone(),
- RequestMethod::GetDiagnostics(vec![specifier.clone()]),
- Default::default(),
- );
- assert!(result.is_ok());
- let result = request(
- &mut runtime,
- state_snapshot.clone(),
- RequestMethod::GetCompletions((
+ let info = ts_server
+ .get_completions(
+ snapshot.clone(),
specifier.clone(),
position,
GetCompletionsAtPositionOptions {
@@ -5321,31 +4999,28 @@ mod tests {
trigger_kind: None,
},
Default::default(),
- )),
- Default::default(),
- );
- assert!(result.is_ok());
- let response: CompletionInfo =
- serde_json::from_value(result.unwrap()).unwrap();
- assert_eq!(response.entries.len(), 22);
- let result = request(
- &mut runtime,
- state_snapshot,
- RequestMethod::GetCompletionDetails(GetCompletionDetailsArgs {
- specifier,
- position,
- name: "log".to_string(),
- source: None,
- preferences: None,
- format_code_settings: None,
- data: None,
- }),
- Default::default(),
- );
- assert!(result.is_ok());
- let response = result.unwrap();
+ )
+ .await
+ .unwrap();
+ assert_eq!(info.entries.len(), 22);
+ let details = ts_server
+ .get_completion_details(
+ snapshot.clone(),
+ GetCompletionDetailsArgs {
+ specifier,
+ position,
+ name: "log".to_string(),
+ format_code_settings: None,
+ source: None,
+ preferences: None,
+ data: None,
+ },
+ )
+ .await
+ .unwrap()
+ .unwrap();
assert_eq!(
- response,
+ json!(details),
json!({
"name": "log",
"kindModifiers": "declare",
@@ -5433,8 +5108,8 @@ mod tests {
);
}
- #[test]
- fn test_completions_fmt() {
+ #[tokio::test]
+ async fn test_completions_fmt() {
let fixture_a = r#"
console.log(someLongVaria)
"#;
@@ -5449,9 +5124,8 @@ mod tests {
})
.unwrap();
let temp_dir = TempDir::new();
- let (mut runtime, state_snapshot, _) = setup(
+ let (ts_server, snapshot, _) = setup(
&temp_dir,
- false,
json!({
"target": "esnext",
"module": "esnext",
@@ -5462,24 +5136,17 @@ mod tests {
("file:///a.ts", fixture_a, 1, LanguageId::TypeScript),
("file:///b.ts", fixture_b, 1, LanguageId::TypeScript),
],
- );
+ )
+ .await;
let specifier = resolve_url("file:///a.ts").expect("could not resolve url");
- let result = request(
- &mut runtime,
- state_snapshot.clone(),
- RequestMethod::GetDiagnostics(vec![specifier.clone()]),
- Default::default(),
- );
- assert!(result.is_ok());
let fmt_options_config = FmtOptionsConfig {
semi_colons: Some(false),
single_quote: Some(true),
..Default::default()
};
- let result = request(
- &mut runtime,
- state_snapshot.clone(),
- RequestMethod::GetCompletions((
+ let info = ts_server
+ .get_completions(
+ snapshot.clone(),
specifier.clone(),
position,
GetCompletionsAtPositionOptions {
@@ -5491,37 +5158,36 @@ mod tests {
},
..Default::default()
},
- (&fmt_options_config).into(),
- )),
- Default::default(),
- )
- .unwrap();
- let info: CompletionInfo = serde_json::from_value(result).unwrap();
+ FormatCodeSettings::from(&fmt_options_config),
+ )
+ .await
+ .unwrap();
let entry = info
.entries
.iter()
.find(|e| &e.name == "someLongVariable")
.unwrap();
- let result = request(
- &mut runtime,
- state_snapshot,
- RequestMethod::GetCompletionDetails(GetCompletionDetailsArgs {
- specifier,
- position,
- name: entry.name.clone(),
- source: entry.source.clone(),
- preferences: Some(UserPreferences {
- quote_preference: Some((&fmt_options_config).into()),
- ..Default::default()
- }),
- format_code_settings: Some((&fmt_options_config).into()),
- data: entry.data.clone(),
- }),
- Default::default(),
- )
- .unwrap();
- let details: CompletionEntryDetails =
- serde_json::from_value(result).unwrap();
+ let details = ts_server
+ .get_completion_details(
+ snapshot.clone(),
+ GetCompletionDetailsArgs {
+ specifier,
+ position,
+ name: entry.name.clone(),
+ format_code_settings: Some(FormatCodeSettings::from(
+ &fmt_options_config,
+ )),
+ source: entry.source.clone(),
+ preferences: Some(UserPreferences {
+ quote_preference: Some((&fmt_options_config).into()),
+ ..Default::default()
+ }),
+ data: entry.data.clone(),
+ },
+ )
+ .await
+ .unwrap()
+ .unwrap();
let actions = details.code_actions.unwrap();
let action = actions
.iter()
@@ -5535,12 +5201,11 @@ mod tests {
);
}
- #[test]
- fn test_get_edits_for_file_rename() {
+ #[tokio::test]
+ async fn test_get_edits_for_file_rename() {
let temp_dir = TempDir::new();
- let (mut runtime, state_snapshot, _) = setup(
+ let (ts_server, snapshot, _) = setup(
&temp_dir,
- false,
json!({
"target": "esnext",
"module": "esnext",
@@ -5556,29 +5221,18 @@ mod tests {
),
("file:///b.ts", r#""#, 1, LanguageId::TypeScript),
],
- );
- let specifier = resolve_url("file:///a.ts").expect("could not resolve url");
- let result = request(
- &mut runtime,
- state_snapshot.clone(),
- RequestMethod::GetDiagnostics(vec![specifier.clone()]),
- Default::default(),
- );
- assert!(result.is_ok());
- let changes = request(
- &mut runtime,
- state_snapshot.clone(),
- RequestMethod::GetEditsForFileRename((
+ )
+ .await;
+ let changes = ts_server
+ .get_edits_for_file_rename(
+ snapshot,
resolve_url("file:///b.ts").unwrap(),
resolve_url("file:///c.ts").unwrap(),
- Default::default(),
- Default::default(),
- )),
- Default::default(),
- )
- .unwrap();
- let changes: Vec<FileTextChanges> =
- serde_json::from_value(changes).unwrap();
+ FormatCodeSettings::default(),
+ UserPreferences::default(),
+ )
+ .await
+ .unwrap();
assert_eq!(
changes,
vec![FileTextChanges {