@@ -16,7 +16,8 @@ import { normalize, sep } from 'path';
16
16
17
17
import * as ts from 'typescript' ;
18
18
import { getSemanticTokens , getSemanticTokenLegend } from './javascriptSemanticTokens' ;
19
- import { statSync } from 'fs' ;
19
+ import { RequestService } from '../requests' ;
20
+ import { NodeRequestService } from '../node/nodeFs' ;
20
21
21
22
const JS_WORD_REGEX = / ( - ? \d * \. \d \w * ) | ( [ ^ \` \~ \! \@ \# \% \^ \& \* \( \) \- \= \+ \[ \{ \] \} \\ \| \; \: \' \" \, \. \< \> \/ \? \s ] + ) / g;
22
23
@@ -32,13 +33,13 @@ function deschemeURI(uri: string) {
32
33
// Both \ and / must be escaped in regular expressions
33
34
newPath = newPath . replace ( new RegExp ( '\\' + sep , 'g' ) , '/' ) ;
34
35
35
- if ( process . platform !== 'win32' ) { return newPath ; }
36
+ if ( process . platform !== 'win32' ) return newPath ;
36
37
37
38
// Windows URIs come in like '/c%3A/Users/orta/dev/...', we need to switch it to 'c:/Users/orta/dev/...'
38
39
return newPath . slice ( 1 ) . replace ( '%3A' , ':' ) ;
39
40
}
40
41
41
- function getLanguageServiceHost ( scriptKind : ts . ScriptKind ) {
42
+ function getLanguageServiceHost ( scriptKind : ts . ScriptKind , fs : NodeRequestService ) {
42
43
const compilerOptions : ts . CompilerOptions = { allowNonTsExtensions : true , allowJs : true , lib : [ 'lib.es6.d.ts' ] , target : ts . ScriptTarget . Latest , moduleResolution : ts . ModuleResolutionKind . Classic , experimentalDecorators : false } ;
43
44
44
45
let currentTextDocument = TextDocument . create ( 'init' , 'javascript' , 1 , '' ) ;
@@ -64,15 +65,15 @@ function getLanguageServiceHost(scriptKind: ts.ScriptKind) {
64
65
return '1' ;
65
66
}
66
67
// Unsure how this could occur, but better to not raise with statSync
67
- if ( ! ts . sys . fileExists ( fileName ) ) { return '1' ; }
68
+ if ( currentWorkspace && ! ts . sys . fileExists ( fileName ) ) { return '1' ; }
68
69
// Use mtime from the fs
69
- return String ( statSync ( fileName ) . mtimeMs ) ;
70
+ return String ( fs . statSync ( fileName ) . mtime ) ;
70
71
} ,
71
72
getScriptSnapshot : ( fileName : string ) => {
72
73
let text = '' ;
73
74
if ( fileName === deschemeURI ( currentTextDocument . uri ) ) {
74
75
text = currentTextDocument . getText ( ) ;
75
- } else if ( ts . sys . fileExists ( fileName ) ) {
76
+ } else if ( currentWorkspace && ts . sys . fileExists ( fileName ) ) {
76
77
text = ts . sys . readFile ( fileName , 'utf8' ) ! ;
77
78
} else {
78
79
text = libs . loadLibrary ( fileName ) ;
@@ -83,24 +84,27 @@ function getLanguageServiceHost(scriptKind: ts.ScriptKind) {
83
84
getChangeRange : ( ) => undefined
84
85
} ;
85
86
} ,
87
+
88
+ // Realistically the TSServer can only run on file:// workspaces, because it is entirely sync API
89
+ // and so `currentWorkspace` is only set when there is at least one root folder in a workspace with a file:// uri
86
90
getCurrentDirectory : ( ) => {
87
91
const workspace = currentWorkspace && currentWorkspace . folders . find ( ws => deschemeURI ( currentTextDocument . uri ) . startsWith ( deschemeURI ( ws . uri ) ) ) ;
88
92
return workspace ? deschemeURI ( workspace . uri ) : '' ;
89
93
} ,
90
94
getDefaultLibFileName : ( _options : ts . CompilerOptions ) => 'es6' ,
91
- fileExists : ts . sys . fileExists ,
92
- readFile : ts . sys . readFile ,
93
- readDirectory : ts . sys . readDirectory ,
94
- directoryExists : ts . sys . directoryExists ,
95
- getDirectories : ts . sys . getDirectories ,
95
+ fileExists : currentWorkspace && ts . sys . fileExists ,
96
+ readFile : currentWorkspace && ts . sys . readFile ,
97
+ readDirectory : currentWorkspace && ts . sys . readDirectory ,
98
+ directoryExists : currentWorkspace && ts . sys . directoryExists ,
99
+ getDirectories : currentWorkspace && ts . sys . getDirectories ,
96
100
} ;
97
101
98
102
return ts . createLanguageService ( host ) ;
99
103
} ) ;
100
104
return {
101
105
async getLanguageService ( jsDocument : TextDocument , workspace : Workspace ) : Promise < ts . LanguageService > {
102
106
currentTextDocument = jsDocument ;
103
- currentWorkspace = workspace ;
107
+ if ( workspace . folders . find ( f => f . uri . startsWith ( 'file://' ) ) ) currentWorkspace = workspace ;
104
108
return jsLanguageService ;
105
109
} ,
106
110
getCompilationSettings ( ) {
@@ -113,10 +117,10 @@ function getLanguageServiceHost(scriptKind: ts.ScriptKind) {
113
117
}
114
118
115
119
116
- export function getJavaScriptMode ( documentRegions : LanguageModelCache < HTMLDocumentRegions > , languageId : 'javascript' | 'typescript' , workspace : Workspace ) : LanguageMode {
120
+ export function getJavaScriptMode ( documentRegions : LanguageModelCache < HTMLDocumentRegions > , languageId : 'javascript' | 'typescript' , workspace : Workspace , fs : RequestService ) : LanguageMode {
117
121
let jsDocuments = getLanguageModelCache < TextDocument > ( 10 , 60 , document => documentRegions . get ( document ) . getEmbeddedDocument ( languageId ) ) ;
118
122
119
- const host = getLanguageServiceHost ( languageId === 'javascript' ? ts . ScriptKind . JS : ts . ScriptKind . TS ) ;
123
+ const host = getLanguageServiceHost ( languageId === 'javascript' ? ts . ScriptKind . JS : ts . ScriptKind . TS , fs as NodeRequestService ) ;
120
124
let globalSettings : Settings = { } ;
121
125
122
126
return {
@@ -146,7 +150,7 @@ export function getJavaScriptMode(documentRegions: LanguageModelCache<HTMLDocume
146
150
const filePath = deschemeURI ( jsDocument . uri ) ;
147
151
148
152
let offset = jsDocument . offsetAt ( position ) ;
149
- let completions = jsLanguageService . getCompletionsAtPosition ( filePath , offset , { includeExternalModuleExports : false , includeInsertTextCompletions : false , importModuleSpecifierEnding : 'js' } ) ;
153
+ let completions = jsLanguageService . getCompletionsAtPosition ( filePath , offset , { includeExternalModuleExports : false , includeInsertTextCompletions : false } ) ;
150
154
151
155
if ( ! completions ) {
152
156
return { isIncomplete : false , items : [ ] } ;
0 commit comments