@volar/typescript 1.7.6 → 1.7.8

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/out/dtsHost.d.ts CHANGED
@@ -4,23 +4,5 @@ export interface IDtsHost {
4
4
  readFile(fileName: string): Promise<string | undefined>;
5
5
  readDirectory(dirName: string): Promise<[string, FileType][]>;
6
6
  }
7
- export declare function createJsDelivrDtsHost(versions?: Record<string, string>, onFetch?: (fileName: string, text: string) => void): DtsHost;
8
- declare class DtsHost implements IDtsHost {
9
- private fetchText;
10
- private flat;
11
- fetchResults: Map<string, Promise<string | undefined>>;
12
- flatResults: Map<string, Promise<string[]>>;
13
- constructor(fetchText: (path: string) => Promise<string | undefined>, flat: (pkg: string) => Promise<string[]>);
14
- stat(fileName: string): Promise<{
15
- type: number;
16
- ctime: number;
17
- mtime: number;
18
- size: number;
19
- } | undefined>;
20
- readDirectory(dirName: string): Promise<[string, FileType][]>;
21
- readFile(fileName: string): Promise<string | undefined>;
22
- fetchFile(fileName: string): Promise<string | undefined>;
23
- valid(fileName: string): Promise<boolean>;
24
- }
7
+ export declare function createJsDelivrDtsHost(versions?: Record<string, string>, onFetch?: (fileName: string, text: string) => void): IDtsHost;
25
8
  export declare function getPackageNameOfDtsPath(path: string): string | undefined;
26
- export {};
@@ -1,3 +1,3 @@
1
1
  import type * as ts from 'typescript/lib/tsserverlibrary';
2
2
  import type * as embedded from '@volar/language-core';
3
- export declare function getProgram(ts: typeof import('typescript/lib/tsserverlibrary'), core: embedded.LanguageContext, ls: ts.LanguageService, lsHost: ts.LanguageServiceHost): any;
3
+ export declare function getProgram(ts: typeof import('typescript/lib/tsserverlibrary'), core: embedded.LanguageContext, ls: ts.LanguageService, sys: ts.System): ts.Program;
package/out/getProgram.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getProgram = void 0;
4
- function getProgram(ts, core, ls, lsHost) {
4
+ function getProgram(ts, core, ls, sys) {
5
5
  const proxy = {
6
6
  getRootFileNames,
7
7
  emit,
@@ -34,7 +34,7 @@ function getProgram(ts, core, ls, lsHost) {
34
34
  return ls.getProgram();
35
35
  }
36
36
  function getRootFileNames() {
37
- return getProgram().getRootFileNames().filter(fileName => lsHost.fileExists?.(fileName));
37
+ return getProgram().getRootFileNames().filter(fileName => sys.fileExists?.(fileName));
38
38
  }
39
39
  // for vue-tsc --noEmit --watch
40
40
  function getBindAndCheckDiagnostics(sourceFile, cancellationToken) {
@@ -63,7 +63,7 @@ function getProgram(ts, core, ls, lsHost) {
63
63
  return transformDiagnostics(getProgram().getGlobalDiagnostics(cancellationToken) ?? []);
64
64
  }
65
65
  function emit(targetSourceFile, _writeFile, cancellationToken, emitOnlyDtsFiles, customTransformers) {
66
- const scriptResult = getProgram().emit(targetSourceFile, (lsHost.writeFile ?? ts.sys.writeFile), cancellationToken, emitOnlyDtsFiles, customTransformers);
66
+ const scriptResult = getProgram().emit(targetSourceFile, (sys.writeFile ?? ts.sys.writeFile), cancellationToken, emitOnlyDtsFiles, customTransformers);
67
67
  return {
68
68
  emitSkipped: scriptResult.emitSkipped,
69
69
  emittedFiles: scriptResult.emittedFiles,
@@ -79,7 +79,7 @@ function getProgram(ts, core, ls, lsHost) {
79
79
  && diagnostic.length !== undefined) {
80
80
  const [virtualFile, source] = core.virtualFiles.getVirtualFile(diagnostic.file.fileName);
81
81
  if (virtualFile && source) {
82
- if (lsHost.fileExists?.(source.fileName) === false)
82
+ if (sys.fileExists?.(source.fileName) === false)
83
83
  continue;
84
84
  for (const [_, [sourceSnapshot, map]] of core.virtualFiles.getMaps(virtualFile)) {
85
85
  if (sourceSnapshot !== source.snapshot)
@@ -100,7 +100,7 @@ function getProgram(ts, core, ls, lsHost) {
100
100
  }
101
101
  }
102
102
  else {
103
- if (lsHost.fileExists?.(diagnostic.file.fileName) === false)
103
+ if (sys.fileExists?.(diagnostic.file.fileName) === false)
104
104
  continue;
105
105
  onMapping(diagnostic, diagnostic.file.fileName, diagnostic.start, diagnostic.start + diagnostic.length, diagnostic.file.text);
106
106
  }
@@ -116,7 +116,7 @@ function getProgram(ts, core, ls, lsHost) {
116
116
  : undefined;
117
117
  if (!file) {
118
118
  if (docText === undefined) {
119
- const snapshot = lsHost.getScriptSnapshot(fileName);
119
+ const snapshot = core.host.getScriptSnapshot(fileName);
120
120
  if (snapshot) {
121
121
  docText = snapshot.getText(0, snapshot.getLength());
122
122
  }
package/out/index.d.ts CHANGED
@@ -3,3 +3,5 @@ export * from './dtsHost';
3
3
  export * from './languageService';
4
4
  export * from './languageServiceHost';
5
5
  export * from './sys';
6
+ export * from './getProgram';
7
+ export * from './serverPlugin';
package/out/index.js CHANGED
@@ -19,4 +19,6 @@ __exportStar(require("./dtsHost"), exports);
19
19
  __exportStar(require("./languageService"), exports);
20
20
  __exportStar(require("./languageServiceHost"), exports);
21
21
  __exportStar(require("./sys"), exports);
22
+ __exportStar(require("./getProgram"), exports);
23
+ __exportStar(require("./serverPlugin"), exports);
22
24
  //# sourceMappingURL=index.js.map
@@ -1,9 +1,3 @@
1
- import { LanguageContext } from '@volar/language-core';
1
+ import { VirtualFiles } from '@volar/language-core';
2
2
  import type * as ts from 'typescript/lib/tsserverlibrary';
3
- export declare function createLanguageService(core: LanguageContext, ts: typeof import('typescript/lib/tsserverlibrary'), sys: ts.System): {
4
- __internal__: {
5
- languageServiceHost: ts.LanguageServiceHost;
6
- languageService: ts.LanguageService;
7
- context: LanguageContext;
8
- };
9
- } & ts.LanguageService;
3
+ export declare function decorateLanguageService(virtualFiles: VirtualFiles, languageService: ts.LanguageService, isTsPlugin: boolean): void;
@@ -1,59 +1,32 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createLanguageService = void 0;
3
+ exports.decorateLanguageService = void 0;
4
4
  const language_core_1 = require("@volar/language-core");
5
- const getProgram_1 = require("./getProgram");
6
- const languageServiceHost_1 = require("./languageServiceHost");
7
- const documentRegistry_1 = require("./documentRegistry");
8
- function createLanguageService(core, ts, sys) {
9
- if (!ts) {
10
- throw new Error('TypeScript module not provided.');
11
- }
12
- const lsHost = (0, languageServiceHost_1.createLanguageServiceHost)(core, ts, sys);
13
- const ls = ts.createLanguageService(lsHost, (0, documentRegistry_1.getDocumentRegistry)(ts, sys.useCaseSensitiveFileNames, core.host.getCurrentDirectory()));
14
- return new Proxy({
15
- organizeImports,
16
- // only support for .ts for now, not support for .vue
17
- getDefinitionAtPosition,
18
- getDefinitionAndBoundSpan,
19
- getTypeDefinitionAtPosition,
20
- getImplementationAtPosition,
21
- findRenameLocations,
22
- getReferencesAtPosition,
23
- findReferences,
24
- // TODO: now is handled by vue server
25
- // prepareCallHierarchy: tsLanguageService.rawLs.prepareCallHierarchy,
26
- // provideCallHierarchyIncomingCalls: tsLanguageService.rawLs.provideCallHierarchyIncomingCalls,
27
- // provideCallHierarchyOutgoingCalls: tsLanguageService.rawLs.provideCallHierarchyOutgoingCalls,
28
- // getEditsForFileRename: tsLanguageService.rawLs.getEditsForFileRename,
29
- // TODO
30
- // getCodeFixesAtPosition: tsLanguageService.rawLs.getCodeFixesAtPosition,
31
- // getCombinedCodeFix: tsLanguageService.rawLs.getCombinedCodeFix,
32
- // applyCodeActionCommand: tsLanguageService.rawLs.applyCodeActionCommand,
33
- // getApplicableRefactors: tsLanguageService.rawLs.getApplicableRefactors,
34
- // getEditsForRefactor: tsLanguageService.rawLs.getEditsForRefactor,
35
- getProgram: () => (0, getProgram_1.getProgram)(ts, core, ls, lsHost),
36
- __internal__: {
37
- context: core,
38
- languageService: ls,
39
- languageServiceHost: lsHost,
40
- },
41
- }, {
42
- get: (target, property) => {
43
- if (property in target) {
44
- return target[property];
45
- }
46
- return ls[property];
47
- },
48
- });
5
+ function decorateLanguageService(virtualFiles, languageService, isTsPlugin) {
6
+ const _organizeImports = languageService.organizeImports.bind(languageService);
7
+ const _getDefinitionAtPosition = languageService.getDefinitionAtPosition.bind(languageService);
8
+ const _getDefinitionAndBoundSpan = languageService.getDefinitionAndBoundSpan.bind(languageService);
9
+ const _getTypeDefinitionAtPosition = languageService.getTypeDefinitionAtPosition.bind(languageService);
10
+ const _getImplementationAtPosition = languageService.getImplementationAtPosition.bind(languageService);
11
+ const _findRenameLocations = languageService.findRenameLocations.bind(languageService);
12
+ const _getReferencesAtPosition = languageService.getReferencesAtPosition.bind(languageService);
13
+ const _findReferences = languageService.findReferences.bind(languageService);
14
+ languageService.organizeImports = organizeImports;
15
+ languageService.getDefinitionAtPosition = getDefinitionAtPosition;
16
+ languageService.getDefinitionAndBoundSpan = getDefinitionAndBoundSpan;
17
+ languageService.getTypeDefinitionAtPosition = getTypeDefinitionAtPosition;
18
+ languageService.getImplementationAtPosition = getImplementationAtPosition;
19
+ languageService.findRenameLocations = findRenameLocations;
20
+ languageService.getReferencesAtPosition = getReferencesAtPosition;
21
+ languageService.findReferences = findReferences;
49
22
  // apis
50
23
  function organizeImports(args, formatOptions, preferences) {
51
24
  let edits = [];
52
- const file = core.virtualFiles.getSource(args.fileName)?.root;
25
+ const file = virtualFiles.getSource(args.fileName)?.root;
53
26
  if (file) {
54
27
  (0, language_core_1.forEachEmbeddedFile)(file, embeddedFile => {
55
28
  if (embeddedFile.kind === language_core_1.FileKind.TypeScriptHostFile && embeddedFile.capabilities.codeAction) {
56
- edits = edits.concat(ls.organizeImports({
29
+ edits = edits.concat(_organizeImports({
57
30
  ...args,
58
31
  fileName: embeddedFile.fileName,
59
32
  }, formatOptions, preferences));
@@ -61,7 +34,7 @@ function createLanguageService(core, ts, sys) {
61
34
  });
62
35
  }
63
36
  else {
64
- return ls.organizeImports(args, formatOptions, preferences);
37
+ return _organizeImports(args, formatOptions, preferences);
65
38
  }
66
39
  return edits.map(transformFileTextChanges).filter(notEmpty);
67
40
  }
@@ -84,26 +57,26 @@ function createLanguageService(core, ts, sys) {
84
57
  const loopChecker = new Set();
85
58
  let symbols = [];
86
59
  withMirrors(fileName, position);
87
- return symbols.map(s => transformDocumentSpanLike(s)).filter(notEmpty);
60
+ return symbols.map(s => transformDocumentSpanLike(s, mode === 'definition')).filter(notEmpty);
88
61
  function withMirrors(fileName, position) {
89
62
  if (loopChecker.has(fileName + ':' + position))
90
63
  return;
91
64
  loopChecker.add(fileName + ':' + position);
92
- const _symbols = mode === 'definition' ? ls.getDefinitionAtPosition(fileName, position)
93
- : mode === 'typeDefinition' ? ls.getTypeDefinitionAtPosition(fileName, position)
94
- : mode === 'references' ? ls.getReferencesAtPosition(fileName, position)
95
- : mode === 'implementation' ? ls.getImplementationAtPosition(fileName, position)
96
- : mode === 'rename' && preferences ? ls.findRenameLocations(fileName, position, findInStrings, findInComments, preferences)
65
+ const _symbols = mode === 'definition' ? _getDefinitionAtPosition(fileName, position)
66
+ : mode === 'typeDefinition' ? _getTypeDefinitionAtPosition(fileName, position)
67
+ : mode === 'references' ? _getReferencesAtPosition(fileName, position)
68
+ : mode === 'implementation' ? _getImplementationAtPosition(fileName, position)
69
+ : mode === 'rename' && preferences ? _findRenameLocations(fileName, position, findInStrings, findInComments, preferences)
97
70
  : undefined;
98
71
  if (!_symbols)
99
72
  return;
100
73
  symbols = symbols.concat(_symbols);
101
74
  for (const ref of _symbols) {
102
75
  loopChecker.add(ref.fileName + ':' + ref.textSpan.start);
103
- const [virtualFile] = core.virtualFiles.getVirtualFile(ref.fileName);
76
+ const [virtualFile] = getVirtualFile(ref.fileName);
104
77
  if (!virtualFile)
105
78
  continue;
106
- const mirrorMap = core.virtualFiles.getMirrorMap(virtualFile);
79
+ const mirrorMap = virtualFiles.getMirrorMap(virtualFile);
107
80
  if (!mirrorMap)
108
81
  continue;
109
82
  for (const [mirrorOffset, data] of mirrorMap.findMirrorOffsets(ref.textSpan.start)) {
@@ -129,13 +102,13 @@ function createLanguageService(core, ts, sys) {
129
102
  return;
130
103
  return {
131
104
  textSpan: textSpan,
132
- definitions: symbols?.map(s => transformDocumentSpanLike(s)).filter(notEmpty),
105
+ definitions: symbols?.map(s => transformDocumentSpanLike(s, true)).filter(notEmpty),
133
106
  };
134
107
  function withMirrors(fileName, position) {
135
108
  if (loopChecker.has(fileName + ':' + position))
136
109
  return;
137
110
  loopChecker.add(fileName + ':' + position);
138
- const _symbols = ls.getDefinitionAndBoundSpan(fileName, position);
111
+ const _symbols = _getDefinitionAndBoundSpan(fileName, position);
139
112
  if (!_symbols)
140
113
  return;
141
114
  if (!textSpan) {
@@ -146,10 +119,10 @@ function createLanguageService(core, ts, sys) {
146
119
  symbols = symbols.concat(_symbols.definitions);
147
120
  for (const ref of _symbols.definitions) {
148
121
  loopChecker.add(ref.fileName + ':' + ref.textSpan.start);
149
- const [virtualFile] = core.virtualFiles.getVirtualFile(ref.fileName);
122
+ const [virtualFile] = getVirtualFile(ref.fileName);
150
123
  if (!virtualFile)
151
124
  continue;
152
- const mirrorMap = core.virtualFiles.getMirrorMap(virtualFile);
125
+ const mirrorMap = virtualFiles.getMirrorMap(virtualFile);
153
126
  if (!mirrorMap)
154
127
  continue;
155
128
  for (const [mirrorOffset, data] of mirrorMap.findMirrorOffsets(ref.textSpan.start)) {
@@ -171,17 +144,17 @@ function createLanguageService(core, ts, sys) {
171
144
  if (loopChecker.has(fileName + ':' + position))
172
145
  return;
173
146
  loopChecker.add(fileName + ':' + position);
174
- const _symbols = ls.findReferences(fileName, position);
147
+ const _symbols = _findReferences(fileName, position);
175
148
  if (!_symbols)
176
149
  return;
177
150
  symbols = symbols.concat(_symbols);
178
151
  for (const symbol of _symbols) {
179
152
  for (const ref of symbol.references) {
180
153
  loopChecker.add(ref.fileName + ':' + ref.textSpan.start);
181
- const [virtualFile] = core.virtualFiles.getVirtualFile(ref.fileName);
154
+ const [virtualFile] = getVirtualFile(ref.fileName);
182
155
  if (!virtualFile)
183
156
  continue;
184
- const mirrorMap = core.virtualFiles.getMirrorMap(virtualFile);
157
+ const mirrorMap = virtualFiles.getMirrorMap(virtualFile);
185
158
  if (!mirrorMap)
186
159
  continue;
187
160
  for (const [mirrorOffset, data] of mirrorMap.findMirrorOffsets(ref.textSpan.start)) {
@@ -197,7 +170,7 @@ function createLanguageService(core, ts, sys) {
197
170
  }
198
171
  // transforms
199
172
  function transformFileTextChanges(changes) {
200
- const [_, source] = core.virtualFiles.getVirtualFile(changes.fileName);
173
+ const [_, source] = getVirtualFile(changes.fileName);
201
174
  if (source) {
202
175
  return {
203
176
  ...changes,
@@ -218,8 +191,8 @@ function createLanguageService(core, ts, sys) {
218
191
  }
219
192
  }
220
193
  function transformReferencedSymbol(symbol) {
221
- const definition = transformDocumentSpanLike(symbol.definition);
222
- const references = symbol.references.map(r => transformDocumentSpanLike(r)).filter(notEmpty);
194
+ const definition = transformDocumentSpanLike(symbol.definition, false);
195
+ const references = symbol.references.map(r => transformDocumentSpanLike(r, false)).filter(notEmpty);
223
196
  if (definition) {
224
197
  return {
225
198
  definition,
@@ -237,8 +210,17 @@ function createLanguageService(core, ts, sys) {
237
210
  };
238
211
  }
239
212
  }
240
- function transformDocumentSpanLike(documentSpan) {
241
- const textSpan = transformSpan(documentSpan.fileName, documentSpan.textSpan);
213
+ function transformDocumentSpanLike(documentSpan, isDefinition) {
214
+ let textSpan = transformSpan(documentSpan.fileName, documentSpan.textSpan);
215
+ if (isDefinition && !textSpan) {
216
+ const [virtualFile, source] = getVirtualFile(documentSpan.fileName);
217
+ if (virtualFile && source) {
218
+ textSpan = {
219
+ fileName: source.fileName,
220
+ textSpan: { start: 0, length: 0 },
221
+ };
222
+ }
223
+ }
242
224
  if (!textSpan)
243
225
  return;
244
226
  const contextSpan = transformSpan(documentSpan.fileName, documentSpan.contextSpan);
@@ -259,9 +241,15 @@ function createLanguageService(core, ts, sys) {
259
241
  return;
260
242
  if (!textSpan)
261
243
  return;
262
- const [virtualFile, source] = core.virtualFiles.getVirtualFile(fileName);
244
+ const [virtualFile, source] = getVirtualFile(fileName);
263
245
  if (virtualFile && source) {
264
- for (const [_, [sourceSnapshot, map]] of core.virtualFiles.getMaps(virtualFile)) {
246
+ if (isTsPlugin) {
247
+ textSpan = {
248
+ start: textSpan.start - source.snapshot.getLength(),
249
+ length: textSpan.length,
250
+ };
251
+ }
252
+ for (const [_, [sourceSnapshot, map]] of virtualFiles.getMaps(virtualFile)) {
265
253
  if (source.snapshot !== sourceSnapshot)
266
254
  continue;
267
255
  const sourceLoc = map.toSourceOffset(textSpan.start);
@@ -283,8 +271,26 @@ function createLanguageService(core, ts, sys) {
283
271
  };
284
272
  }
285
273
  }
274
+ function getVirtualFile(fileName) {
275
+ if (isTsPlugin) {
276
+ let result;
277
+ const source = virtualFiles.getSource(fileName);
278
+ if (source) {
279
+ (0, language_core_1.forEachEmbeddedFile)(source.root, file => {
280
+ const ext = file.fileName.replace(fileName, '');
281
+ if (file.kind === language_core_1.FileKind.TypeScriptHostFile && (ext === '.d.ts' || ext.match(/^\.(js|ts)x?$/))) {
282
+ result = file;
283
+ }
284
+ });
285
+ }
286
+ return [result, source];
287
+ }
288
+ else {
289
+ return virtualFiles.getVirtualFile(fileName);
290
+ }
291
+ }
286
292
  }
287
- exports.createLanguageService = createLanguageService;
293
+ exports.decorateLanguageService = decorateLanguageService;
288
294
  function notEmpty(value) {
289
295
  return value !== null && value !== undefined;
290
296
  }
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createLanguageServiceHost = void 0;
4
4
  const path_1 = require("path");
5
+ const utilities_1 = require("./typescript/utilities");
5
6
  function createLanguageServiceHost(ctx, ts, sys) {
6
7
  let lastProjectVersion;
7
8
  let tsProjectVersion = 0;
@@ -31,9 +32,12 @@ function createLanguageServiceHost(ctx, ts, sys) {
31
32
  return snapshot.getText(0, snapshot.getLength());
32
33
  }
33
34
  },
35
+ readDirectory,
36
+ getDirectories,
37
+ directoryExists,
34
38
  fileExists,
35
39
  getProjectVersion: () => {
36
- return tsProjectVersion.toString() + ':' + sys.version;
40
+ return tsProjectVersion + ':' + sys.version;
37
41
  },
38
42
  getTypeRootsVersion: () => {
39
43
  return sys.version ?? -1; // TODO: only update for /node_modules changes?
@@ -99,6 +103,54 @@ function createLanguageServiceHost(ctx, ts, sys) {
99
103
  oldTsVirtualFileSnapshots = newTsVirtualFileSnapshots;
100
104
  oldOtherVirtualFileSnapshots = newOtherVirtualFileSnapshots;
101
105
  }
106
+ function readDirectory(dirName, extensions, excludes, includes, depth) {
107
+ let matches = (0, utilities_1.matchFiles)(dirName, extensions, excludes, includes, sys?.useCaseSensitiveFileNames ?? false, ctx.host.getCurrentDirectory(), depth, (dirPath) => {
108
+ const files = [];
109
+ for (const fileName of getScriptFileNames()) {
110
+ if (fileName.toLowerCase().startsWith(dirPath.toLowerCase())) {
111
+ const baseName = fileName.substring(dirPath.length);
112
+ if (baseName.indexOf('/') === -1) {
113
+ files.push(baseName);
114
+ }
115
+ }
116
+ }
117
+ return {
118
+ files,
119
+ directories: getVirtualFileDirectories(dirPath),
120
+ };
121
+ }, sys?.realpath ? (path => sys.realpath(path)) : (path => path));
122
+ if (ctx) {
123
+ matches = matches.map(match => {
124
+ const [_, source] = ctx.virtualFiles.getVirtualFile(match);
125
+ if (source) {
126
+ return source.fileName;
127
+ }
128
+ return match;
129
+ });
130
+ }
131
+ return [...new Set([
132
+ ...matches,
133
+ ...sys.readDirectory(dirName, extensions, excludes, includes, depth),
134
+ ])];
135
+ }
136
+ function getDirectories(dirName) {
137
+ return [...new Set([
138
+ ...getVirtualFileDirectories(dirName),
139
+ ...sys.getDirectories(dirName),
140
+ ])];
141
+ }
142
+ function getVirtualFileDirectories(dirName) {
143
+ const names = new Set();
144
+ for (const fileName of getScriptFileNames()) {
145
+ if (fileName.toLowerCase().startsWith(dirName.toLowerCase())) {
146
+ const path = fileName.substring(dirName.length);
147
+ if (path.indexOf('/') >= 0) {
148
+ names.add(path.split('/')[0]);
149
+ }
150
+ }
151
+ }
152
+ return [...names];
153
+ }
102
154
  function getScriptFileNames() {
103
155
  const tsFileNames = new Set();
104
156
  for (const { root } of ctx.virtualFiles.allSources()) {
@@ -159,6 +211,12 @@ function createLanguageServiceHost(ctx, ts, sys) {
159
211
  // fs files
160
212
  return sys.getModifiedTime?.(fileName)?.valueOf().toString() ?? '';
161
213
  }
214
+ function directoryExists(dirName) {
215
+ if (getScriptFileNames().some(fileName => fileName.toLowerCase().startsWith(dirName.toLowerCase()))) {
216
+ return true;
217
+ }
218
+ return sys.directoryExists(dirName);
219
+ }
162
220
  function fileExists(fileName) {
163
221
  // fill external virtual files
164
222
  const ext = fileName.substring(fileName.lastIndexOf('.'));
@@ -0,0 +1,3 @@
1
+ import { VirtualFiles } from '@volar/language-core';
2
+ import type * as ts from 'typescript/lib/tsserverlibrary';
3
+ export declare function decorateLanguageServiceHost(virtualFiles: VirtualFiles, languageServiceHost: ts.LanguageServiceHost, ts: typeof import('typescript/lib/tsserverlibrary'), exts: string[]): void;
@@ -0,0 +1,92 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.decorateLanguageServiceHost = void 0;
4
+ const language_core_1 = require("@volar/language-core");
5
+ function decorateLanguageServiceHost(virtualFiles, languageServiceHost, ts, exts) {
6
+ const scripts = new Map();
7
+ const resolveModuleNameLiterals = languageServiceHost.resolveModuleNameLiterals?.bind(languageServiceHost);
8
+ const resolveModuleNames = languageServiceHost.resolveModuleNames?.bind(languageServiceHost);
9
+ const getScriptSnapshot = languageServiceHost.getScriptSnapshot.bind(languageServiceHost);
10
+ if (resolveModuleNameLiterals) {
11
+ languageServiceHost.resolveModuleNameLiterals = (moduleNames, containingFile, redirectedReference, options, ...rest) => {
12
+ const resolvedModules = resolveModuleNameLiterals(moduleNames, containingFile, redirectedReference, options, ...rest);
13
+ return moduleNames.map((name, i) => {
14
+ if (exts.some(ext => name.text.endsWith(ext))) {
15
+ return resolveModuleName(name.text, containingFile, options, redirectedReference);
16
+ }
17
+ return resolvedModules[i];
18
+ });
19
+ };
20
+ }
21
+ else if (resolveModuleNames) {
22
+ languageServiceHost.resolveModuleNames = (moduleNames, containingFile, reusedNames, redirectedReference, options, containingSourceFile) => {
23
+ const resolvedModules = resolveModuleNames(moduleNames, containingFile, reusedNames, redirectedReference, options, containingSourceFile);
24
+ return moduleNames.map((name, i) => {
25
+ if (exts.some(ext => name.endsWith(ext))) {
26
+ return resolveModuleName(name, containingFile, options, redirectedReference).resolvedModule;
27
+ }
28
+ return resolvedModules[i];
29
+ });
30
+ };
31
+ }
32
+ languageServiceHost.getScriptSnapshot = (fileName) => {
33
+ if (scripts.has(fileName)) {
34
+ updateScript(fileName);
35
+ }
36
+ return scripts.get(fileName)?.snapshot ?? getScriptSnapshot(fileName);
37
+ };
38
+ function resolveModuleName(name, containingFile, options, redirectedReference) {
39
+ const resolved = ts.resolveModuleName(name, containingFile, options, {
40
+ readFile(fileName) {
41
+ return languageServiceHost.readFile(fileName);
42
+ },
43
+ fileExists(fileName) {
44
+ if (exts.some(ext => fileName.endsWith(ext + '.d.ts'))) {
45
+ return languageServiceHost.fileExists(fileName.slice(0, -'.d.ts'.length));
46
+ }
47
+ return languageServiceHost.fileExists(fileName);
48
+ },
49
+ }, undefined, redirectedReference);
50
+ if (resolved.resolvedModule) {
51
+ resolved.resolvedModule.resolvedFileName = resolved.resolvedModule.resolvedFileName.slice(0, -'.d.ts'.length);
52
+ const script = updateScript(resolved.resolvedModule.resolvedFileName);
53
+ if (script) {
54
+ resolved.resolvedModule.extension = script.extension;
55
+ }
56
+ }
57
+ return resolved;
58
+ }
59
+ function updateScript(fileName) {
60
+ const version = languageServiceHost.getScriptVersion(fileName);
61
+ if (version !== scripts.get(fileName)?.version) {
62
+ const text = languageServiceHost.readFile(fileName);
63
+ let snapshot;
64
+ let extension = '.ts';
65
+ if (text !== undefined) {
66
+ const virtualFile = virtualFiles.updateSource(fileName, ts.ScriptSnapshot.fromString(text), undefined);
67
+ if (virtualFile) {
68
+ let patchedText = text.split('\n').map(line => ' '.repeat(line.length)).join('\n');
69
+ (0, language_core_1.forEachEmbeddedFile)(virtualFile, file => {
70
+ const ext = file.fileName.replace(fileName, '');
71
+ if (file.kind === language_core_1.FileKind.TypeScriptHostFile && (ext === '.d.ts' || ext.match(/^\.(js|ts)x?$/))) {
72
+ extension = ext;
73
+ patchedText += file.snapshot.getText(0, file.snapshot.getLength());
74
+ }
75
+ });
76
+ snapshot = ts.ScriptSnapshot.fromString(patchedText);
77
+ }
78
+ }
79
+ else {
80
+ virtualFiles.deleteSource(fileName);
81
+ }
82
+ scripts.set(fileName, {
83
+ version,
84
+ snapshot,
85
+ extension,
86
+ });
87
+ }
88
+ return scripts.get(fileName);
89
+ }
90
+ }
91
+ exports.decorateLanguageServiceHost = decorateLanguageServiceHost;
92
+ //# sourceMappingURL=serverPlugin.js.map
package/out/sys.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- import type { ServiceEnvironment, Disposable, LanguageContext } from '@volar/language-service';
1
+ import type { ServiceEnvironment, Disposable } from '@volar/language-service';
2
2
  import type * as ts from 'typescript/lib/tsserverlibrary';
3
3
  import { IDtsHost } from './dtsHost';
4
- export declare function createSys(ctx: LanguageContext | undefined, ts: typeof import('typescript/lib/tsserverlibrary'), env: ServiceEnvironment, dtsHost?: IDtsHost): ts.System & {
4
+ export declare function createSys(ts: typeof import('typescript/lib/tsserverlibrary'), env: ServiceEnvironment, dtsHost?: IDtsHost): ts.System & {
5
5
  version: number;
6
6
  sync(): Promise<number>;
7
7
  } & Disposable;
package/out/sys.js CHANGED
@@ -1,12 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createSys = void 0;
4
- const language_core_1 = require("@volar/language-core");
5
4
  const path_1 = require("path");
6
5
  const utilities_1 = require("./typescript/utilities");
7
6
  const dtsHost_1 = require("./dtsHost");
8
7
  let currentCwd = '';
9
- function createSys(ctx, ts, env, dtsHost) {
8
+ function createSys(ts, env, dtsHost) {
10
9
  let version = 0;
11
10
  const rootPath = env.uriToFileName(env.rootUri.toString());
12
11
  const sys = ts.sys;
@@ -150,16 +149,16 @@ function createSys(ctx, ts, env, dtsHost) {
150
149
  promises.add(promise);
151
150
  result.then(result => {
152
151
  promises.delete(promise);
153
- file.exists = result?.type === 1 || result?.type === 64;
152
+ file.exists = result?.type === 1;
154
153
  if (file.exists) {
155
154
  const time = Date.now();
156
- file.modifiedTime = time !== file.modifiedTime ? time : time + 1;
155
+ file.modifiedTime = time !== file.modifiedTime ? time : file.modifiedTime + 1;
157
156
  version++;
158
157
  }
159
158
  });
160
159
  }
161
160
  else {
162
- file.exists = result?.type === 1 || result?.type === 64;
161
+ file.exists = result?.type === 1;
163
162
  }
164
163
  }
165
164
  return file.exists;
@@ -173,40 +172,15 @@ function createSys(ctx, ts, env, dtsHost) {
173
172
  }
174
173
  function readDirectory(dirName, extensions, excludes, includes, depth) {
175
174
  dirName = resolvePath(dirName);
176
- let matches = (0, utilities_1.matchFiles)(dirName, extensions, excludes, includes, sys?.useCaseSensitiveFileNames ?? false, rootPath, depth, (dirPath) => {
175
+ const matches = (0, utilities_1.matchFiles)(dirName, extensions, excludes, includes, sys?.useCaseSensitiveFileNames ?? false, rootPath, depth, (dirPath) => {
177
176
  dirPath = resolvePath(dirPath);
178
177
  readDirectoryWorker(dirPath);
179
178
  const dir = getDir(dirPath);
180
- const virtualFiles = [];
181
- if (ctx) {
182
- for (const { root } of ctx.virtualFiles.allSources()) {
183
- (0, language_core_1.forEachEmbeddedFile)(root, file => {
184
- if (file.kind === language_core_1.FileKind.TypeScriptHostFile) {
185
- const fileDirName = path_1.posix.dirname(file.fileName);
186
- if (fileDirName.toLowerCase() === dirPath.toLowerCase()) {
187
- virtualFiles.push(path_1.posix.basename(file.fileName));
188
- }
189
- }
190
- });
191
- }
192
- }
193
179
  return {
194
- files: [
195
- ...[...Object.entries(dir.files)].filter(([_, file]) => file.exists).map(([name]) => name),
196
- ...virtualFiles,
197
- ],
180
+ files: [...Object.entries(dir.files)].filter(([_, file]) => file.exists).map(([name]) => name),
198
181
  directories: [...Object.entries(dir.dirs)].filter(([_, dir]) => dir.exists).map(([name]) => name),
199
182
  };
200
183
  }, sys?.realpath ? (path => sys.realpath(path)) : (path => path));
201
- if (ctx) {
202
- matches = matches.map(match => {
203
- const [_, source] = ctx.virtualFiles.getVirtualFile(match);
204
- if (source) {
205
- return source.fileName;
206
- }
207
- return match;
208
- });
209
- }
210
184
  return [...new Set(matches)];
211
185
  }
212
186
  function readFileWorker(fileName, encoding, dir) {
@@ -254,30 +228,57 @@ function createSys(ctx, ts, env, dtsHost) {
254
228
  return;
255
229
  }
256
230
  dir.requested = true;
257
- const uri = env.fileNameToUri(dirName);
258
231
  const result = dirName.startsWith('/node_modules/') && dtsHost
259
232
  ? dtsHost.readDirectory(dirName)
260
- : env.fs?.readDirectory(uri);
233
+ : env.fs?.readDirectory(env.fileNameToUri(dirName || '.'));
261
234
  if (typeof result === 'object' && 'then' in result) {
262
235
  const promise = result;
263
236
  promises.add(promise);
264
237
  result.then((result) => {
265
238
  promises.delete(promise);
266
- if (onReadDirectoryResult(dir, result)) {
239
+ if (onReadDirectoryResult(dirName, dir, result)) {
267
240
  version++;
268
241
  }
269
242
  });
270
243
  }
271
244
  else {
272
- onReadDirectoryResult(dir, result ?? []);
245
+ onReadDirectoryResult(dirName, dir, result ?? []);
273
246
  }
274
247
  }
275
- function onReadDirectoryResult(dir, result) {
248
+ function onReadDirectoryResult(dirName, dir, result) {
276
249
  // See https://github.com/microsoft/TypeScript/blob/e1a9290051a3b0cbdfbadc3adbcc155a4641522a/src/compiler/sys.ts#L1853-L1857
277
250
  result = result.filter(([name]) => name !== '.' && name !== '..');
278
251
  let updated = false;
279
- for (const [name, fileType] of result) {
280
- if (fileType === 1 || fileType === 64) {
252
+ for (const [name, _fileType] of result) {
253
+ let fileType = _fileType;
254
+ if (fileType === 64) {
255
+ const stat = env.fs?.stat(env.fileNameToUri(dirName + '/' + name));
256
+ if (typeof stat === 'object' && 'then' in stat) {
257
+ const promise = stat;
258
+ promises.add(promise);
259
+ stat.then((stat) => {
260
+ promises.delete(promise);
261
+ if (stat?.type === 1) {
262
+ dir.files[name] ??= {};
263
+ if (!dir.files[name].exists) {
264
+ dir.files[name].exists = true;
265
+ version++;
266
+ }
267
+ }
268
+ else if (stat?.type === 2) {
269
+ const childDir = getDirFromDir(dir, name);
270
+ if (!childDir.exists) {
271
+ childDir.exists = true;
272
+ version++;
273
+ }
274
+ }
275
+ });
276
+ }
277
+ else if (stat) {
278
+ fileType = stat.type;
279
+ }
280
+ }
281
+ if (fileType === 1) {
281
282
  dir.files[name] ??= {};
282
283
  if (!dir.files[name].exists) {
283
284
  dir.files[name].exists = true;
@@ -298,9 +299,9 @@ function createSys(ctx, ts, env, dtsHost) {
298
299
  const dirNames = [];
299
300
  let currentDirPath = dirName;
300
301
  let currentDirName = path_1.posix.basename(currentDirPath);
301
- let lastDirName;
302
- while (lastDirName !== currentDirName) {
303
- lastDirName = currentDirName;
302
+ let lastDirPath;
303
+ while (lastDirPath !== currentDirPath) {
304
+ lastDirPath = currentDirPath;
304
305
  dirNames.push(currentDirName);
305
306
  currentDirPath = path_1.posix.dirname(currentDirPath);
306
307
  currentDirName = path_1.posix.basename(currentDirPath);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@volar/typescript",
3
- "version": "1.7.6",
3
+ "version": "1.7.8",
4
4
  "main": "out/index.js",
5
5
  "license": "MIT",
6
6
  "files": [
@@ -13,10 +13,10 @@
13
13
  "directory": "packages/typescript"
14
14
  },
15
15
  "dependencies": {
16
- "@volar/language-core": "1.7.6"
16
+ "@volar/language-core": "1.7.8"
17
17
  },
18
18
  "devDependencies": {
19
- "@volar/language-service": "1.7.6"
19
+ "@volar/language-service": "1.7.8"
20
20
  },
21
- "gitHead": "b2dbe05318c06658ae97a65f9bc6d1badc55a81b"
21
+ "gitHead": "e7c1b16e5c78702de6986eafa17ae96000ffe0cb"
22
22
  }