@volar/typescript 2.2.0-alpha.1 → 2.2.0-alpha.10

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.
@@ -29,7 +29,7 @@ function decorateLanguageService(language, languageService) {
29
29
  }
30
30
  };
31
31
  // methods
32
- const { findReferences, findRenameLocations, getCompletionEntryDetails, getCompletionsAtPosition, getDefinitionAndBoundSpan, getDefinitionAtPosition, getFileReferences, getFormattingEditsForDocument, getFormattingEditsForRange, getFormattingEditsAfterKeystroke, getImplementationAtPosition, getLinkedEditingRangeAtPosition, getQuickInfoAtPosition, getReferencesAtPosition, getSemanticDiagnostics, getSyntacticDiagnostics, getSuggestionDiagnostics, getTypeDefinitionAtPosition, getEncodedSemanticClassifications, getDocumentHighlights, getApplicableRefactors, getEditsForFileRename, getEditsForRefactor, getRenameInfo, getCodeFixesAtPosition, prepareCallHierarchy, provideCallHierarchyIncomingCalls, provideCallHierarchyOutgoingCalls, provideInlayHints, organizeImports, } = languageService;
32
+ const { findReferences, findRenameLocations, getCompletionEntryDetails, getCompletionsAtPosition, getDefinitionAndBoundSpan, getDefinitionAtPosition, getFileReferences, getFormattingEditsForDocument, getFormattingEditsForRange, getFormattingEditsAfterKeystroke, getImplementationAtPosition, getLinkedEditingRangeAtPosition, getQuickInfoAtPosition, getSignatureHelpItems, getReferencesAtPosition, getSemanticDiagnostics, getSyntacticDiagnostics, getSuggestionDiagnostics, getTypeDefinitionAtPosition, getEncodedSemanticClassifications, getDocumentHighlights, getApplicableRefactors, getEditsForFileRename, getEditsForRefactor, getRenameInfo, getCodeFixesAtPosition, prepareCallHierarchy, provideCallHierarchyIncomingCalls, provideCallHierarchyOutgoingCalls, provideInlayHints, organizeImports, } = languageService;
33
33
  languageService.getFormattingEditsForDocument = (fileName, options) => {
34
34
  const [serviceScript, sourceScript, map] = (0, utils_1.getServiceScript)(language, fileName);
35
35
  if (serviceScript) {
@@ -200,6 +200,27 @@ function decorateLanguageService(language, languageService) {
200
200
  return getQuickInfoAtPosition(fileName, position);
201
201
  }
202
202
  };
203
+ languageService.getSignatureHelpItems = (fileName, position, options) => {
204
+ const [serviceScript, sourceScript, map] = (0, utils_1.getServiceScript)(language, fileName);
205
+ if (serviceScript) {
206
+ const generatePosition = (0, transform_1.toGeneratedOffset)(sourceScript, map, position, language_core_1.isSignatureHelpEnabled);
207
+ if (generatePosition !== undefined) {
208
+ const result = getSignatureHelpItems(fileName, generatePosition, options);
209
+ if (result) {
210
+ const applicableSpan = (0, transform_1.transformTextSpan)(sourceScript, map, result.applicableSpan, language_core_1.isSignatureHelpEnabled);
211
+ if (applicableSpan) {
212
+ return {
213
+ ...result,
214
+ applicableSpan,
215
+ };
216
+ }
217
+ }
218
+ }
219
+ }
220
+ else {
221
+ return getSignatureHelpItems(fileName, position, options);
222
+ }
223
+ };
203
224
  languageService.getDocumentHighlights = (fileName, position, filesToSearch) => {
204
225
  const unresolved = linkedCodeFeatureWorker(fileName, position, language_core_1.isHighlightEnabled, position => getDocumentHighlights(fileName, position, filesToSearch), function* (result) {
205
226
  for (const ref of result) {
@@ -356,17 +377,17 @@ function decorateLanguageService(language, languageService) {
356
377
  };
357
378
  languageService.getSyntacticDiagnostics = fileName => {
358
379
  return getSyntacticDiagnostics(fileName)
359
- .map(d => (0, transform_1.transformDiagnostic)(language, d))
380
+ .map(d => (0, transform_1.transformDiagnostic)(language, d, false))
360
381
  .filter(utils_1.notEmpty);
361
382
  };
362
383
  languageService.getSemanticDiagnostics = fileName => {
363
384
  return getSemanticDiagnostics(fileName)
364
- .map(d => (0, transform_1.transformDiagnostic)(language, d))
385
+ .map(d => (0, transform_1.transformDiagnostic)(language, d, false))
365
386
  .filter(utils_1.notEmpty);
366
387
  };
367
388
  languageService.getSuggestionDiagnostics = fileName => {
368
389
  return getSuggestionDiagnostics(fileName)
369
- .map(d => (0, transform_1.transformDiagnostic)(language, d))
390
+ .map(d => (0, transform_1.transformDiagnostic)(language, d, false))
370
391
  .filter(utils_1.notEmpty);
371
392
  };
372
393
  languageService.getDefinitionAndBoundSpan = (fileName, position) => {
@@ -403,18 +424,15 @@ function decorateLanguageService(language, languageService) {
403
424
  const resolved = unresolved
404
425
  .flat()
405
426
  .map(symbol => {
406
- const definition = (0, transform_1.transformDocumentSpan)(language, symbol.definition, language_core_1.isDefinitionEnabled);
407
- if (definition) {
408
- return {
409
- definition,
410
- references: symbol.references
411
- .map(r => (0, transform_1.transformDocumentSpan)(language, r, language_core_1.isReferencesEnabled))
412
- .filter(utils_1.notEmpty),
413
- };
414
- }
415
- })
416
- .filter(utils_1.notEmpty);
417
- return (0, dedupe_1.dedupeReferencedSymbols)(resolved);
427
+ const definition = (0, transform_1.transformDocumentSpan)(language, symbol.definition, language_core_1.isDefinitionEnabled, true);
428
+ return {
429
+ definition,
430
+ references: symbol.references
431
+ .map(r => (0, transform_1.transformDocumentSpan)(language, r, language_core_1.isReferencesEnabled))
432
+ .filter(utils_1.notEmpty),
433
+ };
434
+ });
435
+ return resolved;
418
436
  };
419
437
  languageService.getDefinitionAtPosition = (fileName, position) => {
420
438
  const unresolved = linkedCodeFeatureWorker(fileName, position, language_core_1.isDefinitionEnabled, position => getDefinitionAtPosition(fileName, position), function* (result) {
@@ -587,7 +605,7 @@ function decorateLanguageService(language, languageService) {
587
605
  return (0, dedupe_1.dedupeDocumentSpans)(resolved);
588
606
  };
589
607
  function linkedCodeFeatureWorker(fileName, position, filter, worker, getLinkedCodes) {
590
- let results = [];
608
+ const results = [];
591
609
  const processedFilePositions = new Set();
592
610
  const [serviceScript, sourceScript, map] = (0, utils_1.getServiceScript)(language, fileName);
593
611
  if (serviceScript) {
@@ -610,7 +628,7 @@ function decorateLanguageService(language, languageService) {
610
628
  if (!result) {
611
629
  return;
612
630
  }
613
- results = results.concat(result);
631
+ results.push(result);
614
632
  for (const ref of getLinkedCodes(result)) {
615
633
  processedFilePositions.add(ref[0] + ':' + ref[1]);
616
634
  const [virtualFile, sourceScript] = (0, utils_1.getServiceScript)(language, ref[0]);
@@ -1,4 +1,4 @@
1
- import { type Language } from '@volar/language-core';
1
+ import type { Language } from '@volar/language-core';
2
2
  import type * as ts from 'typescript';
3
- export declare function decorateLanguageServiceHost(language: Language, languageServiceHost: ts.LanguageServiceHost, ts: typeof import('typescript')): void;
3
+ export declare function decorateLanguageServiceHost(ts: typeof import('typescript'), language: Language, languageServiceHost: ts.LanguageServiceHost): void;
4
4
  export declare function searchExternalFiles(ts: typeof import('typescript'), project: ts.server.Project, exts: string[]): string[];
@@ -1,25 +1,23 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.searchExternalFiles = exports.decorateLanguageServiceHost = void 0;
4
- const language_core_1 = require("@volar/language-core");
5
4
  const resolveModuleName_1 = require("../resolveModuleName");
6
- function decorateLanguageServiceHost(language, languageServiceHost, ts) {
7
- let extraProjectVersion = 0;
8
- const exts = language.plugins
5
+ function decorateLanguageServiceHost(ts, language, languageServiceHost) {
6
+ const extensions = language.plugins
9
7
  .map(plugin => plugin.typescript?.extraFileExtensions.map(ext => '.' + ext.extension) ?? [])
10
8
  .flat();
11
9
  const scripts = new Map();
10
+ const crashFileNames = new Set();
12
11
  const readDirectory = languageServiceHost.readDirectory?.bind(languageServiceHost);
13
12
  const resolveModuleNameLiterals = languageServiceHost.resolveModuleNameLiterals?.bind(languageServiceHost);
14
13
  const resolveModuleNames = languageServiceHost.resolveModuleNames?.bind(languageServiceHost);
15
- const getProjectVersion = languageServiceHost.getProjectVersion?.bind(languageServiceHost);
16
14
  const getScriptSnapshot = languageServiceHost.getScriptSnapshot.bind(languageServiceHost);
17
15
  const getScriptKind = languageServiceHost.getScriptKind?.bind(languageServiceHost);
18
16
  // path completion
19
17
  if (readDirectory) {
20
18
  languageServiceHost.readDirectory = (path, extensions, exclude, include, depth) => {
21
19
  if (extensions) {
22
- for (const ext of exts) {
20
+ for (const ext of extensions) {
23
21
  if (!extensions.includes(ext)) {
24
22
  extensions = [...extensions, ...ext];
25
23
  }
@@ -28,34 +26,33 @@ function decorateLanguageServiceHost(language, languageServiceHost, ts) {
28
26
  return readDirectory(path, extensions, exclude, include, depth);
29
27
  };
30
28
  }
31
- if (language.plugins.some(language => language.typescript?.extraFileExtensions.length)) {
29
+ if (extensions.length) {
32
30
  const resolveModuleName = (0, resolveModuleName_1.createResolveModuleName)(ts, languageServiceHost, language.plugins, fileName => language.scripts.get(fileName));
31
+ const getCanonicalFileName = languageServiceHost.useCaseSensitiveFileNames?.()
32
+ ? (fileName) => fileName
33
+ : (fileName) => fileName.toLowerCase();
34
+ const moduleResolutionCache = ts.createModuleResolutionCache(languageServiceHost.getCurrentDirectory(), getCanonicalFileName, languageServiceHost.getCompilationSettings());
33
35
  if (resolveModuleNameLiterals) {
34
36
  languageServiceHost.resolveModuleNameLiterals = (moduleLiterals, containingFile, redirectedReference, options, ...rest) => {
35
- if (moduleLiterals.every(name => !exts.some(ext => name.text.endsWith(ext)))) {
37
+ if (moduleLiterals.every(name => !extensions.some(ext => name.text.endsWith(ext)))) {
36
38
  return resolveModuleNameLiterals(moduleLiterals, containingFile, redirectedReference, options, ...rest);
37
39
  }
38
40
  return moduleLiterals.map(moduleLiteral => {
39
- return resolveModuleName(moduleLiteral.text, containingFile, options, undefined, redirectedReference);
41
+ return resolveModuleName(moduleLiteral.text, containingFile, options, moduleResolutionCache, redirectedReference);
40
42
  });
41
43
  };
42
44
  }
43
45
  if (resolveModuleNames) {
44
46
  languageServiceHost.resolveModuleNames = (moduleNames, containingFile, reusedNames, redirectedReference, options, containingSourceFile) => {
45
- if (moduleNames.every(name => !exts.some(ext => name.endsWith(ext)))) {
47
+ if (moduleNames.every(name => !extensions.some(ext => name.endsWith(ext)))) {
46
48
  return resolveModuleNames(moduleNames, containingFile, reusedNames, redirectedReference, options, containingSourceFile);
47
49
  }
48
50
  return moduleNames.map(moduleName => {
49
- return resolveModuleName(moduleName, containingFile, options, undefined, redirectedReference).resolvedModule;
51
+ return resolveModuleName(moduleName, containingFile, options, moduleResolutionCache, redirectedReference).resolvedModule;
50
52
  });
51
53
  };
52
54
  }
53
55
  }
54
- if (getProjectVersion) {
55
- languageServiceHost.getProjectVersion = () => {
56
- return getProjectVersion() + ':' + extraProjectVersion;
57
- };
58
- }
59
56
  languageServiceHost.getScriptSnapshot = fileName => {
60
57
  const virtualScript = updateVirtualScript(fileName);
61
58
  if (virtualScript) {
@@ -73,46 +70,44 @@ function decorateLanguageServiceHost(language, languageServiceHost, ts) {
73
70
  };
74
71
  }
75
72
  function updateVirtualScript(fileName) {
76
- const version = languageServiceHost.getScriptVersion(fileName);
77
- if (version !== scripts.get(fileName)?.[0]) {
78
- let extension = '.ts';
79
- let snapshotSnapshot;
80
- let scriptKind = ts.ScriptKind.TS;
81
- const snapshot = getScriptSnapshot(fileName);
82
- if (snapshot) {
83
- extraProjectVersion++;
84
- const sourceScript = language.scripts.set(fileName, (0, language_core_1.resolveCommonLanguageId)(fileName), snapshot);
85
- if (sourceScript.generated) {
86
- const text = snapshot.getText(0, snapshot.getLength());
87
- let patchedText = text.split('\n').map(line => ' '.repeat(line.length)).join('\n');
88
- const serviceScript = sourceScript.generated.languagePlugin.typescript?.getServiceScript(sourceScript.generated.root);
89
- if (serviceScript) {
90
- extension = serviceScript.extension;
91
- scriptKind = serviceScript.scriptKind;
92
- patchedText += serviceScript.code.snapshot.getText(0, serviceScript.code.snapshot.getLength());
93
- }
94
- snapshotSnapshot = ts.ScriptSnapshot.fromString(patchedText);
95
- if (sourceScript.generated.languagePlugin.typescript?.getExtraServiceScripts) {
96
- console.warn('getExtraScripts() is not available in this use case.');
97
- }
73
+ if (crashFileNames.has(fileName)) {
74
+ return;
75
+ }
76
+ let version;
77
+ try {
78
+ version = languageServiceHost.getScriptVersion(fileName);
79
+ }
80
+ catch {
81
+ // fix https://github.com/vuejs/language-tools/issues/4278
82
+ crashFileNames.add(fileName);
83
+ }
84
+ if (version === undefined) {
85
+ // somehow getScriptVersion returns undefined
86
+ return;
87
+ }
88
+ let script = scripts.get(fileName);
89
+ if (!script || script[0] !== version) {
90
+ script = [version];
91
+ const sourceScript = language.scripts.get(fileName);
92
+ if (sourceScript?.generated) {
93
+ const serviceScript = sourceScript.generated.languagePlugin.typescript?.getServiceScript(sourceScript.generated.root);
94
+ if (serviceScript) {
95
+ const sourceContents = sourceScript.snapshot.getText(0, sourceScript.snapshot.getLength());
96
+ let virtualContents = sourceContents.split('\n').map(line => ' '.repeat(line.length)).join('\n');
97
+ virtualContents += serviceScript.code.snapshot.getText(0, serviceScript.code.snapshot.getLength());
98
+ script[1] = {
99
+ extension: serviceScript.extension,
100
+ kind: serviceScript.scriptKind,
101
+ snapshot: ts.ScriptSnapshot.fromString(virtualContents),
102
+ };
103
+ }
104
+ if (sourceScript.generated.languagePlugin.typescript?.getExtraServiceScripts) {
105
+ console.warn('getExtraServiceScripts() is not available in TS plugin.');
98
106
  }
99
107
  }
100
- else if (language.scripts.get(fileName)) {
101
- extraProjectVersion++;
102
- language.scripts.delete(fileName);
103
- }
104
- if (snapshotSnapshot) {
105
- scripts.set(fileName, [
106
- version,
107
- {
108
- extension,
109
- snapshot: snapshotSnapshot,
110
- kind: scriptKind,
111
- }
112
- ]);
113
- }
108
+ scripts.set(fileName, script);
114
109
  }
115
- return scripts.get(fileName)?.[1];
110
+ return script[1];
116
111
  }
117
112
  }
118
113
  exports.decorateLanguageServiceHost = decorateLanguageServiceHost;
@@ -9,6 +9,7 @@ function decorateProgram(language, program) {
9
9
  const getSyntacticDiagnostics = program.getSyntacticDiagnostics;
10
10
  const getSemanticDiagnostics = program.getSemanticDiagnostics;
11
11
  const getGlobalDiagnostics = program.getGlobalDiagnostics;
12
+ const getSourceFileByPath = program.getSourceFileByPath;
12
13
  // for tsc --noEmit --watch
13
14
  // @ts-ignore
14
15
  const getBindAndCheckDiagnostics = program.getBindAndCheckDiagnostics;
@@ -17,31 +18,39 @@ function decorateProgram(language, program) {
17
18
  return {
18
19
  ...result,
19
20
  diagnostics: result.diagnostics
20
- .map(d => (0, transform_1.transformDiagnostic)(language, d))
21
+ .map(d => (0, transform_1.transformDiagnostic)(language, d, true))
21
22
  .filter(utils_1.notEmpty),
22
23
  };
23
24
  };
24
25
  program.getSyntacticDiagnostics = (sourceFile, cancellationToken) => {
25
26
  return getSyntacticDiagnostics(sourceFile, cancellationToken)
26
- .map(d => (0, transform_1.transformDiagnostic)(language, d))
27
+ .map(d => (0, transform_1.transformDiagnostic)(language, d, true))
27
28
  .filter(utils_1.notEmpty);
28
29
  };
29
30
  program.getSemanticDiagnostics = (sourceFile, cancellationToken) => {
30
31
  return getSemanticDiagnostics(sourceFile, cancellationToken)
31
- .map(d => (0, transform_1.transformDiagnostic)(language, d))
32
+ .map(d => (0, transform_1.transformDiagnostic)(language, d, true))
32
33
  .filter(utils_1.notEmpty);
33
34
  };
34
35
  program.getGlobalDiagnostics = cancellationToken => {
35
36
  return getGlobalDiagnostics(cancellationToken)
36
- .map(d => (0, transform_1.transformDiagnostic)(language, d))
37
+ .map(d => (0, transform_1.transformDiagnostic)(language, d, true))
37
38
  .filter(utils_1.notEmpty);
38
39
  };
39
40
  // @ts-ignore
40
41
  program.getBindAndCheckDiagnostics = (sourceFile, cancellationToken) => {
41
42
  return getBindAndCheckDiagnostics(sourceFile, cancellationToken)
42
- .map(d => (0, transform_1.transformDiagnostic)(language, d))
43
+ .map(d => (0, transform_1.transformDiagnostic)(language, d, true))
43
44
  .filter(utils_1.notEmpty);
44
45
  };
46
+ // fix https://github.com/vuejs/language-tools/issues/4099 with `incremental`
47
+ program.getSourceFileByPath = path => {
48
+ const sourceFile = getSourceFileByPath(path);
49
+ if (sourceFile) {
50
+ (0, transform_1.fillSourceFileText)(language, sourceFile);
51
+ }
52
+ return sourceFile;
53
+ };
45
54
  }
46
55
  exports.decorateProgram = decorateProgram;
47
56
  //# sourceMappingURL=decorateProgram.js.map
@@ -1,3 +1,2 @@
1
1
  import type * as ts from 'typescript';
2
- export declare function dedupeReferencedSymbols<T extends ts.ReferencedSymbol>(items: T[]): T[];
3
2
  export declare function dedupeDocumentSpans<T extends ts.DocumentSpan>(items: T[]): T[];
@@ -1,14 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.dedupeDocumentSpans = exports.dedupeReferencedSymbols = void 0;
4
- function dedupeReferencedSymbols(items) {
5
- return dedupe(items, item => [
6
- item.definition.fileName,
7
- item.definition.textSpan.start,
8
- item.definition.textSpan.length,
9
- ].join(':'));
10
- }
11
- exports.dedupeReferencedSymbols = dedupeReferencedSymbols;
3
+ exports.dedupeDocumentSpans = void 0;
12
4
  function dedupeDocumentSpans(items) {
13
5
  return dedupe(items, item => [
14
6
  item.fileName,
@@ -1,3 +1,3 @@
1
- import type * as ts from 'typescript';
2
1
  import { LanguagePlugin } from '@volar/language-core';
3
- export declare function proxyCreateProgram(ts: typeof import('typescript'), original: typeof ts['createProgram'], extensions: string[], getLanguagePlugins: (ts: typeof import('typescript'), options: ts.CreateProgramOptions) => LanguagePlugin[]): typeof import("typescript").createProgram;
2
+ import type * as ts from 'typescript';
3
+ export declare function proxyCreateProgram(ts: typeof import('typescript'), original: typeof ts['createProgram'], getLanguagePlugins: (ts: typeof import('typescript'), options: ts.CreateProgramOptions) => LanguagePlugin[], getLanguageId: (fileName: string) => string): typeof import("typescript").createProgram;
@@ -1,117 +1,161 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.proxyCreateProgram = void 0;
4
- const decorateProgram_1 = require("./decorateProgram");
5
4
  const language_core_1 = require("@volar/language-core");
6
- function proxyCreateProgram(ts, original, extensions, getLanguagePlugins) {
5
+ const resolveModuleName_1 = require("../resolveModuleName");
6
+ const decorateProgram_1 = require("./decorateProgram");
7
+ const arrayEqual = (a, b) => {
8
+ if (a.length !== b.length) {
9
+ return false;
10
+ }
11
+ for (let i = 0; i < a.length; i++) {
12
+ if (a[i] !== b[i]) {
13
+ return false;
14
+ }
15
+ }
16
+ return true;
17
+ };
18
+ const objectEqual = (a, b) => {
19
+ const keysA = Object.keys(a);
20
+ const keysB = Object.keys(b);
21
+ if (keysA.length !== keysB.length) {
22
+ return false;
23
+ }
24
+ for (const key of keysA) {
25
+ if (a[key] !== b[key]) {
26
+ return false;
27
+ }
28
+ }
29
+ return true;
30
+ };
31
+ function proxyCreateProgram(ts, original, getLanguagePlugins, getLanguageId) {
32
+ const sourceFileSnapshots = new Map();
33
+ const parsedSourceFiles = new WeakMap();
34
+ let lastOptions;
35
+ let languagePlugins;
36
+ let language;
37
+ let moduleResolutionCache;
7
38
  return new Proxy(original, {
8
39
  apply: (target, thisArg, args) => {
9
40
  const options = args[0];
10
41
  assert(!!options.host, '!!options.host');
11
- const sourceFileToSnapshotMap = new WeakMap();
12
- const language = (0, language_core_1.createLanguage)(getLanguagePlugins(ts, options), ts.sys.useCaseSensitiveFileNames, fileName => {
13
- let snapshot;
14
- assert(originalSourceFiles.has(fileName), `originalSourceFiles.has(${fileName})`);
15
- const sourceFile = originalSourceFiles.get(fileName);
16
- if (sourceFile) {
17
- snapshot = sourceFileToSnapshotMap.get(sourceFile);
18
- if (!snapshot) {
19
- snapshot = {
20
- getChangeRange() {
21
- return undefined;
22
- },
23
- getLength() {
24
- return sourceFile.text.length;
25
- },
26
- getText(start, end) {
27
- return sourceFile.text.substring(start, end);
28
- },
29
- };
30
- sourceFileToSnapshotMap.set(sourceFile, snapshot);
31
- }
32
- }
33
- if (snapshot) {
34
- language.scripts.set(fileName, (0, language_core_1.resolveCommonLanguageId)(fileName), snapshot);
35
- }
36
- else {
37
- language.scripts.delete(fileName);
38
- }
39
- });
40
- const originalSourceFiles = new Map();
41
- const parsedSourceFiles = new WeakMap();
42
- const arbitraryExtensions = extensions.map(ext => `.d${ext}.ts`);
43
- const originalHost = options.host;
44
- const moduleResolutionHost = {
45
- ...originalHost,
46
- fileExists(fileName) {
47
- for (let i = 0; i < arbitraryExtensions.length; i++) {
48
- if (fileName.endsWith(arbitraryExtensions[i])) {
49
- return originalHost.fileExists(fileName.slice(0, -arbitraryExtensions[i].length) + extensions[i]);
42
+ if (!lastOptions
43
+ || !languagePlugins
44
+ || !language
45
+ || !arrayEqual(options.rootNames, lastOptions.rootNames)
46
+ || !objectEqual(options.options, lastOptions.options)) {
47
+ moduleResolutionCache = ts.createModuleResolutionCache(options.host.getCurrentDirectory(), options.host.getCanonicalFileName, options.options);
48
+ lastOptions = options;
49
+ languagePlugins = getLanguagePlugins(ts, options);
50
+ language = (0, language_core_1.createLanguage)(languagePlugins, ts.sys.useCaseSensitiveFileNames, fileName => {
51
+ if (!sourceFileSnapshots.has(fileName)) {
52
+ const sourceFileText = originalHost.readFile(fileName);
53
+ if (sourceFileText !== undefined) {
54
+ sourceFileSnapshots.set(fileName, [undefined, {
55
+ getChangeRange() {
56
+ return undefined;
57
+ },
58
+ getLength() {
59
+ return sourceFileText.length;
60
+ },
61
+ getText(start, end) {
62
+ return sourceFileText.substring(start, end);
63
+ },
64
+ }]);
65
+ }
66
+ else {
67
+ sourceFileSnapshots.set(fileName, [undefined, undefined]);
50
68
  }
51
69
  }
52
- return originalHost.fileExists(fileName);
53
- },
54
- };
70
+ const snapshot = sourceFileSnapshots.get(fileName)?.[1];
71
+ if (snapshot) {
72
+ language.scripts.set(fileName, getLanguageId(fileName), snapshot);
73
+ }
74
+ else {
75
+ language.scripts.delete(fileName);
76
+ }
77
+ });
78
+ }
79
+ const originalHost = options.host;
80
+ const extensions = languagePlugins
81
+ .map(plugin => plugin.typescript?.extraFileExtensions.map(({ extension }) => `.${extension}`) ?? [])
82
+ .flat();
55
83
  options.host = { ...originalHost };
56
- options.options.allowArbitraryExtensions = true;
57
84
  options.host.getSourceFile = (fileName, languageVersionOrOptions, onError, shouldCreateNewSourceFile) => {
58
85
  const originalSourceFile = originalHost.getSourceFile(fileName, languageVersionOrOptions, onError, shouldCreateNewSourceFile);
59
- originalSourceFiles.set(fileName, originalSourceFile);
60
- if (originalSourceFile && extensions.some(ext => fileName.endsWith(ext))) {
61
- let sourceFile2 = parsedSourceFiles.get(originalSourceFile);
62
- if (!sourceFile2) {
63
- const sourceScript = language.scripts.get(fileName);
64
- assert(!!sourceScript, '!!sourceScript');
65
- let patchedText = originalSourceFile.text.split('\n').map(line => ' '.repeat(line.length)).join('\n');
66
- let scriptKind = ts.ScriptKind.TS;
67
- if (sourceScript.generated?.languagePlugin.typescript) {
68
- const { getServiceScript: getScript, getExtraServiceScripts: getExtraScripts } = sourceScript.generated.languagePlugin.typescript;
69
- const serviceScript = getScript(sourceScript.generated.root);
70
- if (serviceScript) {
71
- scriptKind = serviceScript.scriptKind;
72
- patchedText += serviceScript.code.snapshot.getText(0, serviceScript.code.snapshot.getLength());
73
- }
74
- if (getExtraScripts) {
75
- console.warn('getExtraScripts() is not available in this use case.');
76
- }
86
+ if (!sourceFileSnapshots.has(fileName)
87
+ || sourceFileSnapshots.get(fileName)?.[0] !== originalSourceFile) {
88
+ if (originalSourceFile) {
89
+ sourceFileSnapshots.set(fileName, [originalSourceFile, {
90
+ getChangeRange() {
91
+ return undefined;
92
+ },
93
+ getLength() {
94
+ return originalSourceFile.text.length;
95
+ },
96
+ getText(start, end) {
97
+ return originalSourceFile.text.substring(start, end);
98
+ },
99
+ }]);
100
+ }
101
+ else {
102
+ sourceFileSnapshots.set(fileName, [undefined, undefined]);
103
+ }
104
+ }
105
+ if (!originalSourceFile) {
106
+ return;
107
+ }
108
+ if (!parsedSourceFiles.has(originalSourceFile)) {
109
+ const sourceScript = language.scripts.get(fileName);
110
+ assert(!!sourceScript, '!!sourceScript');
111
+ parsedSourceFiles.set(originalSourceFile, originalSourceFile);
112
+ if (sourceScript.generated?.languagePlugin.typescript) {
113
+ const { getServiceScript, getExtraServiceScripts } = sourceScript.generated.languagePlugin.typescript;
114
+ const serviceScript = getServiceScript(sourceScript.generated.root);
115
+ if (serviceScript) {
116
+ let patchedText = originalSourceFile.text.split('\n').map(line => ' '.repeat(line.length)).join('\n');
117
+ let scriptKind = ts.ScriptKind.TS;
118
+ scriptKind = serviceScript.scriptKind;
119
+ patchedText += serviceScript.code.snapshot.getText(0, serviceScript.code.snapshot.getLength());
120
+ const parsedSourceFile = ts.createSourceFile(fileName, patchedText, languageVersionOrOptions, undefined, scriptKind);
121
+ // @ts-expect-error
122
+ parsedSourceFile.version = originalSourceFile.version;
123
+ parsedSourceFiles.set(originalSourceFile, parsedSourceFile);
124
+ }
125
+ if (getExtraServiceScripts) {
126
+ console.warn('getExtraServiceScripts() is not available in this use case.');
77
127
  }
78
- sourceFile2 = ts.createSourceFile(fileName, patchedText, 99, true, scriptKind);
79
- // @ts-expect-error
80
- sourceFile2.version = originalSourceFile.version;
81
- parsedSourceFiles.set(originalSourceFile, sourceFile2);
82
128
  }
83
- return sourceFile2;
84
129
  }
85
- return originalSourceFile;
86
- };
87
- options.host.resolveModuleNameLiterals = (moduleNames, containingFile, redirectedReference, options) => {
88
- return moduleNames.map(name => {
89
- return resolveModuleName(name.text, containingFile, options, redirectedReference);
90
- });
130
+ return parsedSourceFiles.get(originalSourceFile);
91
131
  };
92
- options.host.resolveModuleNames = (moduleNames, containingFile, _reusedNames, redirectedReference, options) => {
93
- return moduleNames.map(name => {
94
- return resolveModuleName(name, containingFile, options, redirectedReference).resolvedModule;
95
- });
96
- };
97
- const program = Reflect.apply(target, thisArg, [options]);
132
+ if (extensions.length) {
133
+ options.options.allowArbitraryExtensions = true;
134
+ const resolveModuleName = (0, resolveModuleName_1.createResolveModuleName)(ts, originalHost, language.plugins, fileName => language.scripts.get(fileName));
135
+ const resolveModuleNameLiterals = originalHost.resolveModuleNameLiterals;
136
+ const resolveModuleNames = originalHost.resolveModuleNames;
137
+ options.host.resolveModuleNameLiterals = (moduleLiterals, containingFile, redirectedReference, compilerOptions, ...rest) => {
138
+ if (resolveModuleNameLiterals && moduleLiterals.every(name => !extensions.some(ext => name.text.endsWith(ext)))) {
139
+ return resolveModuleNameLiterals(moduleLiterals, containingFile, redirectedReference, compilerOptions, ...rest);
140
+ }
141
+ return moduleLiterals.map(moduleLiteral => {
142
+ return resolveModuleName(moduleLiteral.text, containingFile, compilerOptions, moduleResolutionCache, redirectedReference);
143
+ });
144
+ };
145
+ options.host.resolveModuleNames = (moduleNames, containingFile, reusedNames, redirectedReference, compilerOptions, containingSourceFile) => {
146
+ if (resolveModuleNames && moduleNames.every(name => !extensions.some(ext => name.endsWith(ext)))) {
147
+ return resolveModuleNames(moduleNames, containingFile, reusedNames, redirectedReference, compilerOptions, containingSourceFile);
148
+ }
149
+ return moduleNames.map(moduleName => {
150
+ return resolveModuleName(moduleName, containingFile, compilerOptions, moduleResolutionCache, redirectedReference).resolvedModule;
151
+ });
152
+ };
153
+ }
154
+ const program = Reflect.apply(target, thisArg, args);
98
155
  (0, decorateProgram_1.decorateProgram)(language, program);
99
156
  // TODO: #128
100
- program.__volar__ = { files: language };
157
+ program.__volar__ = { language };
101
158
  return program;
102
- function resolveModuleName(name, containingFile, options, redirectedReference) {
103
- const resolved = ts.resolveModuleName(name, containingFile, options, moduleResolutionHost, originalHost.getModuleResolutionCache?.(), redirectedReference);
104
- if (resolved.resolvedModule) {
105
- for (let i = 0; i < arbitraryExtensions.length; i++) {
106
- if (resolved.resolvedModule.resolvedFileName.endsWith(arbitraryExtensions[i])) {
107
- const sourceFileName = resolved.resolvedModule.resolvedFileName.slice(0, -arbitraryExtensions[i].length) + extensions[i];
108
- resolved.resolvedModule.resolvedFileName = sourceFileName;
109
- resolved.resolvedModule.extension = extensions[i];
110
- }
111
- }
112
- }
113
- return resolved;
114
- }
115
159
  },
116
160
  });
117
161
  }
@@ -1,7 +1,8 @@
1
1
  import { Language, CodeInformation, SourceMap, SourceScript } from '@volar/language-core';
2
2
  import type * as ts from 'typescript';
3
3
  export declare function transformCallHierarchyItem(language: Language, item: ts.CallHierarchyItem, filter: (data: CodeInformation) => boolean): ts.CallHierarchyItem;
4
- export declare function transformDiagnostic<T extends ts.Diagnostic>(language: Language, diagnostic: T): T | undefined;
4
+ export declare function transformDiagnostic<T extends ts.Diagnostic>(language: Language, diagnostic: T, isTsc: boolean): T | undefined;
5
+ export declare function fillSourceFileText(language: Language, sourceFile: ts.SourceFile): void;
5
6
  export declare function transformFileTextChanges(language: Language, changes: ts.FileTextChanges, filter: (data: CodeInformation) => boolean): ts.FileTextChanges | undefined;
6
7
  export declare function transformDocumentSpan<T extends ts.DocumentSpan>(language: Language, documentSpan: T, filter: (data: CodeInformation) => boolean, shouldFallback?: boolean): T | undefined;
7
8
  export declare function transformSpan(language: Language, fileName: string | undefined, textSpan: ts.TextSpan | undefined, filter: (data: CodeInformation) => boolean): {
@@ -1,9 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.toGeneratedOffset = exports.toSourceOffset = exports.transformTextSpan = exports.transformTextChange = exports.transformSpan = exports.transformDocumentSpan = exports.transformFileTextChanges = exports.transformDiagnostic = exports.transformCallHierarchyItem = void 0;
3
+ exports.toGeneratedOffset = exports.toSourceOffset = exports.transformTextSpan = exports.transformTextChange = exports.transformSpan = exports.transformDocumentSpan = exports.transformFileTextChanges = exports.fillSourceFileText = exports.transformDiagnostic = exports.transformCallHierarchyItem = void 0;
4
4
  const language_core_1 = require("@volar/language-core");
5
5
  const utils_1 = require("./utils");
6
6
  const transformedDiagnostics = new WeakMap();
7
+ const transformedSourceFile = new WeakSet();
7
8
  function transformCallHierarchyItem(language, item, filter) {
8
9
  const span = transformSpan(language, item.file, item.span, filter);
9
10
  const selectionSpan = transformSpan(language, item.file, item.selectionSpan, filter);
@@ -14,13 +15,13 @@ function transformCallHierarchyItem(language, item, filter) {
14
15
  };
15
16
  }
16
17
  exports.transformCallHierarchyItem = transformCallHierarchyItem;
17
- function transformDiagnostic(language, diagnostic) {
18
+ function transformDiagnostic(language, diagnostic, isTsc) {
18
19
  if (!transformedDiagnostics.has(diagnostic)) {
19
20
  transformedDiagnostics.set(diagnostic, undefined);
20
21
  const { relatedInformation } = diagnostic;
21
22
  if (relatedInformation) {
22
23
  diagnostic.relatedInformation = relatedInformation
23
- .map(d => transformDiagnostic(language, d))
24
+ .map(d => transformDiagnostic(language, d, isTsc))
24
25
  .filter(utils_1.notEmpty);
25
26
  }
26
27
  if (diagnostic.file !== undefined
@@ -30,6 +31,9 @@ function transformDiagnostic(language, diagnostic) {
30
31
  if (serviceScript) {
31
32
  const sourceSpan = transformTextSpan(sourceScript, map, { start: diagnostic.start, length: diagnostic.length }, language_core_1.shouldReportDiagnostics);
32
33
  if (sourceSpan) {
34
+ if (isTsc) {
35
+ fillSourceFileText(language, diagnostic.file);
36
+ }
33
37
  transformedDiagnostics.set(diagnostic, {
34
38
  ...diagnostic,
35
39
  start: sourceSpan.start,
@@ -48,6 +52,19 @@ function transformDiagnostic(language, diagnostic) {
48
52
  return transformedDiagnostics.get(diagnostic);
49
53
  }
50
54
  exports.transformDiagnostic = transformDiagnostic;
55
+ // fix https://github.com/vuejs/language-tools/issues/4099 without `incremental`
56
+ function fillSourceFileText(language, sourceFile) {
57
+ if (transformedSourceFile.has(sourceFile)) {
58
+ return;
59
+ }
60
+ transformedSourceFile.add(sourceFile);
61
+ const [serviceScript, sourceScript] = (0, utils_1.getServiceScript)(language, sourceFile.fileName);
62
+ if (serviceScript) {
63
+ sourceFile.text = sourceScript.snapshot.getText(0, sourceScript.snapshot.getLength())
64
+ + sourceFile.text.substring(sourceScript.snapshot.getLength());
65
+ }
66
+ }
67
+ exports.fillSourceFileText = fillSourceFileText;
51
68
  function transformFileTextChanges(language, changes, filter) {
52
69
  const [_, source] = (0, utils_1.getServiceScript)(language, changes.fileName);
53
70
  if (source) {
@@ -72,13 +89,10 @@ exports.transformFileTextChanges = transformFileTextChanges;
72
89
  function transformDocumentSpan(language, documentSpan, filter, shouldFallback) {
73
90
  let textSpan = transformSpan(language, documentSpan.fileName, documentSpan.textSpan, filter);
74
91
  if (!textSpan && shouldFallback) {
75
- const [serviceScript] = (0, utils_1.getServiceScript)(language, documentSpan.fileName);
76
- if (serviceScript) {
77
- textSpan = {
78
- fileName: documentSpan.fileName,
79
- textSpan: { start: 0, length: 0 },
80
- };
81
- }
92
+ textSpan = {
93
+ fileName: documentSpan.fileName,
94
+ textSpan: { start: 0, length: 0 },
95
+ };
82
96
  }
83
97
  if (!textSpan) {
84
98
  return;
@@ -43,7 +43,7 @@ function createTypeScriptLanguage(ts, languagePlugins, projectHost) {
43
43
  }
44
44
  if (languagePlugins.some(language => language.typescript?.extraFileExtensions.length)) {
45
45
  // TODO: can this share between monorepo packages?
46
- const moduleCache = ts.createModuleResolutionCache(languageServiceHost.getCurrentDirectory(), languageServiceHost.useCaseSensitiveFileNames ? s => s : s => s.toLowerCase(), languageServiceHost.getCompilationSettings());
46
+ const moduleCache = ts.createModuleResolutionCache(languageServiceHost.getCurrentDirectory(), languageServiceHost.useCaseSensitiveFileNames?.() ? s => s : s => s.toLowerCase(), languageServiceHost.getCompilationSettings());
47
47
  const resolveModuleName = (0, resolveModuleName_1.createResolveModuleName)(ts, languageServiceHost, languagePlugins, fileName => language.scripts.get(projectHost.fileNameToScriptId(fileName)));
48
48
  let lastSysVersion = projectHost.getSystemVersion?.();
49
49
  languageServiceHost.resolveModuleNameLiterals = (moduleLiterals, containingFile, redirectedReference, options, sourceFile) => {
@@ -1,3 +1,3 @@
1
1
  import type * as ts from 'typescript';
2
2
  import { LanguagePlugin } from '@volar/language-core';
3
- export declare function createAsyncLanguageServicePlugin(extensions: string[], scriptKind: ts.ScriptKind, loadLanguagePlugins: (ts: typeof import('typescript'), info: ts.server.PluginCreateInfo) => Promise<LanguagePlugin[]>): ts.server.PluginModuleFactory;
3
+ export declare function createAsyncLanguageServicePlugin(extensions: string[], scriptKind: ts.ScriptKind, loadLanguagePlugins: (ts: typeof import('typescript'), info: ts.server.PluginCreateInfo) => Promise<LanguagePlugin[]>, getLanguageId: (fileName: string) => string): ts.server.PluginModuleFactory;
@@ -8,7 +8,7 @@ const createLanguageServicePlugin_1 = require("./createLanguageServicePlugin");
8
8
  const externalFiles = new WeakMap();
9
9
  const decoratedLanguageServices = new WeakSet();
10
10
  const decoratedLanguageServiceHosts = new WeakSet();
11
- function createAsyncLanguageServicePlugin(extensions, scriptKind, loadLanguagePlugins) {
11
+ function createAsyncLanguageServicePlugin(extensions, scriptKind, loadLanguagePlugins, getLanguageId) {
12
12
  return modules => {
13
13
  const { typescript: ts } = modules;
14
14
  const pluginModule = {
@@ -55,14 +55,14 @@ function createAsyncLanguageServicePlugin(extensions, scriptKind, loadLanguagePl
55
55
  const language = (0, language_core_1.createLanguage)(languagePlugins, ts.sys.useCaseSensitiveFileNames, fileName => {
56
56
  const snapshot = getScriptSnapshot(fileName);
57
57
  if (snapshot) {
58
- language.scripts.set(fileName, (0, language_core_1.resolveCommonLanguageId)(fileName), snapshot);
58
+ language.scripts.set(fileName, getLanguageId(fileName), snapshot);
59
59
  }
60
60
  else {
61
61
  language.scripts.delete(fileName);
62
62
  }
63
63
  });
64
64
  (0, decorateLanguageService_1.decorateLanguageService)(language, info.languageService);
65
- (0, decorateLanguageServiceHost_1.decorateLanguageServiceHost)(language, info.languageServiceHost, ts);
65
+ (0, decorateLanguageServiceHost_1.decorateLanguageServiceHost)(ts, language, info.languageServiceHost);
66
66
  info.project.markAsDirty();
67
67
  initialized = true;
68
68
  });
@@ -1,4 +1,4 @@
1
1
  import type * as ts from 'typescript';
2
2
  import { LanguagePlugin } from '@volar/language-core';
3
- export declare function createLanguageServicePlugin(loadLanguagePlugins: (ts: typeof import('typescript'), info: ts.server.PluginCreateInfo) => LanguagePlugin[]): ts.server.PluginModuleFactory;
3
+ export declare function createLanguageServicePlugin(loadLanguagePlugins: (ts: typeof import('typescript'), info: ts.server.PluginCreateInfo) => LanguagePlugin[], getLanguageId: (fileName: string) => string): ts.server.PluginModuleFactory;
4
4
  export declare function arrayItemsEqual(a: string[], b: string[]): boolean;
@@ -8,7 +8,7 @@ const externalFiles = new WeakMap();
8
8
  const projectExternalFileExtensions = new WeakMap();
9
9
  const decoratedLanguageServices = new WeakSet();
10
10
  const decoratedLanguageServiceHosts = new WeakSet();
11
- function createLanguageServicePlugin(loadLanguagePlugins) {
11
+ function createLanguageServicePlugin(loadLanguagePlugins, getLanguageId) {
12
12
  return modules => {
13
13
  const { typescript: ts } = modules;
14
14
  const pluginModule = {
@@ -26,14 +26,14 @@ function createLanguageServicePlugin(loadLanguagePlugins) {
26
26
  const language = (0, language_core_1.createLanguage)(languagePlugins, ts.sys.useCaseSensitiveFileNames, fileName => {
27
27
  const snapshot = getScriptSnapshot(fileName);
28
28
  if (snapshot) {
29
- language.scripts.set(fileName, (0, language_core_1.resolveCommonLanguageId)(fileName), snapshot);
29
+ language.scripts.set(fileName, getLanguageId(fileName), snapshot);
30
30
  }
31
31
  else {
32
32
  language.scripts.delete(fileName);
33
33
  }
34
34
  });
35
35
  (0, decorateLanguageService_1.decorateLanguageService)(language, info.languageService);
36
- (0, decorateLanguageServiceHost_1.decorateLanguageServiceHost)(language, info.languageServiceHost, ts);
36
+ (0, decorateLanguageServiceHost_1.decorateLanguageServiceHost)(ts, language, info.languageServiceHost);
37
37
  }
38
38
  return info.languageService;
39
39
  },
@@ -1,4 +1,5 @@
1
1
  import type * as ts from 'typescript';
2
2
  import type { LanguagePlugin } from '@volar/language-core';
3
3
  export declare let getLanguagePlugins: (ts: typeof import('typescript'), options: ts.CreateProgramOptions) => LanguagePlugin[];
4
- export declare function runTsc(tscPath: string, extensions: string[], _getLanguagePlugins: typeof getLanguagePlugins): void;
4
+ export declare let getLanguageId: (fileName: string) => string;
5
+ export declare function runTsc(tscPath: string, extensions: string[], _getLanguagePlugins: typeof getLanguagePlugins, _getLanguageId: typeof getLanguageId): void;
@@ -1,11 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.runTsc = exports.getLanguagePlugins = void 0;
3
+ exports.runTsc = exports.getLanguageId = exports.getLanguagePlugins = void 0;
4
4
  const fs = require("fs");
5
5
  let getLanguagePlugins = () => [];
6
6
  exports.getLanguagePlugins = getLanguagePlugins;
7
- function runTsc(tscPath, extensions, _getLanguagePlugins) {
7
+ let getLanguageId = () => 'ts';
8
+ exports.getLanguageId = getLanguageId;
9
+ function runTsc(tscPath, extensions, _getLanguagePlugins, _getLanguageId) {
8
10
  exports.getLanguagePlugins = _getLanguagePlugins;
11
+ exports.getLanguageId = _getLanguageId;
9
12
  const proxyApiPath = require.resolve('../node/proxyCreateProgram');
10
13
  const readFileSync = fs.readFileSync;
11
14
  fs.readFileSync = (...args) => {
@@ -18,10 +21,12 @@ function runTsc(tscPath, extensions, _getLanguagePlugins) {
18
21
  tsc = replace(tsc, /allSupportedExtensions = .*(?=;)/, s => s + `.concat([[${extsText}]])`);
19
22
  // proxy createProgram
20
23
  tsc = replace(tsc, /function createProgram\(.+\) {/, s => `var createProgram = require(${JSON.stringify(proxyApiPath)}).proxyCreateProgram(`
21
- + `new Proxy({}, { get(_target, p, _receiver) { return eval(p); } } ), `
22
- + `_createProgram, `
23
- + `[${extsText}], `
24
- + `require(${JSON.stringify(__filename)}).getLanguagePlugins`
24
+ + [
25
+ `new Proxy({}, { get(_target, p, _receiver) { return eval(p); } } )`,
26
+ `_createProgram`,
27
+ `require(${JSON.stringify(__filename)}).getLanguagePlugins`,
28
+ `require(${JSON.stringify(__filename)}).getLanguageId`,
29
+ ].join(', ')
25
30
  + `);\n`
26
31
  + s.replace('createProgram', '_createProgram'));
27
32
  return tsc;
@@ -1,3 +1,3 @@
1
1
  import type { LanguagePlugin, SourceScript } from '@volar/language-core';
2
2
  import type * as ts from 'typescript';
3
- export declare function createResolveModuleName(ts: typeof import('typescript'), languageServiceHost: ts.LanguageServiceHost, languagePlugins: LanguagePlugin<any>[], getSourceScript: (fileName: string) => SourceScript | undefined): (moduleName: string, containingFile: string, compilerOptions: ts.CompilerOptions, cache?: ts.ModuleResolutionCache, redirectedReference?: ts.ResolvedProjectReference, resolutionMode?: ts.ResolutionMode) => ts.ResolvedModuleWithFailedLookupLocations;
3
+ export declare function createResolveModuleName(ts: typeof import('typescript'), host: ts.ModuleResolutionHost, languagePlugins: LanguagePlugin<any>[], getSourceScript: (fileName: string) => SourceScript | undefined): (moduleName: string, containingFile: string, compilerOptions: ts.CompilerOptions, cache?: ts.ModuleResolutionCache, redirectedReference?: ts.ResolvedProjectReference, resolutionMode?: ts.ResolutionMode) => ts.ResolvedModuleWithFailedLookupLocations;
@@ -1,15 +1,17 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createResolveModuleName = void 0;
4
- function createResolveModuleName(ts, languageServiceHost, languagePlugins, getSourceScript) {
5
- const toPatchResults = new Map();
4
+ function createResolveModuleName(ts, host, languagePlugins, getSourceScript) {
5
+ const toSourceFileInfo = new Map();
6
6
  const moduleResolutionHost = {
7
- readFile: languageServiceHost.readFile.bind(languageServiceHost),
8
- directoryExists: languageServiceHost.directoryExists?.bind(languageServiceHost),
9
- realpath: languageServiceHost.realpath?.bind(languageServiceHost),
10
- getCurrentDirectory: languageServiceHost.getCurrentDirectory.bind(languageServiceHost),
11
- getDirectories: languageServiceHost.getDirectories?.bind(languageServiceHost),
12
- useCaseSensitiveFileNames: languageServiceHost.useCaseSensitiveFileNames?.bind(languageServiceHost),
7
+ readFile: host.readFile.bind(host),
8
+ directoryExists: host.directoryExists?.bind(host),
9
+ realpath: host.realpath?.bind(host),
10
+ getCurrentDirectory: host.getCurrentDirectory?.bind(host),
11
+ getDirectories: host.getDirectories?.bind(host),
12
+ useCaseSensitiveFileNames: typeof host.useCaseSensitiveFileNames === 'function'
13
+ ? host.useCaseSensitiveFileNames.bind(host)
14
+ : host.useCaseSensitiveFileNames,
13
15
  fileExists(fileName) {
14
16
  for (const { typescript } of languagePlugins) {
15
17
  if (!typescript) {
@@ -17,36 +19,51 @@ function createResolveModuleName(ts, languageServiceHost, languagePlugins, getSo
17
19
  }
18
20
  for (const { extension } of typescript.extraFileExtensions) {
19
21
  if (fileName.endsWith(`.d.${extension}.ts`)) {
20
- const patchFileName = fileName.slice(0, -`.d.${extension}.ts`.length) + `.${extension}`;
21
- if (fileExists(patchFileName)) {
22
- toPatchResults.set(fileName, patchFileName);
23
- return true;
22
+ const sourceFileName = fileName.slice(0, -`.d.${extension}.ts`.length) + `.${extension}`;
23
+ if (fileExists(sourceFileName)) {
24
+ const sourceScript = getSourceScript(sourceFileName);
25
+ if (sourceScript?.generated) {
26
+ const serviceScript = sourceScript.generated.languagePlugin.typescript?.getServiceScript(sourceScript.generated.root);
27
+ if (serviceScript) {
28
+ const dtsPath = sourceFileName + '.d.ts';
29
+ if ((serviceScript.extension === '.js' || serviceScript.extension === '.jsx') && fileExists(dtsPath)) {
30
+ toSourceFileInfo.set(fileName, {
31
+ sourceFileName: dtsPath,
32
+ extension: '.ts',
33
+ });
34
+ }
35
+ else {
36
+ toSourceFileInfo.set(fileName, {
37
+ sourceFileName,
38
+ extension: serviceScript.extension,
39
+ });
40
+ }
41
+ return true;
42
+ }
43
+ }
24
44
  }
25
45
  }
26
46
  }
27
47
  }
28
- return languageServiceHost.fileExists(fileName);
48
+ return host.fileExists(fileName);
29
49
  },
30
50
  };
31
51
  return (moduleName, containingFile, compilerOptions, cache, redirectedReference, resolutionMode) => {
32
52
  const result = ts.resolveModuleName(moduleName, containingFile, compilerOptions, moduleResolutionHost, cache, redirectedReference, resolutionMode);
33
- if (result.resolvedModule && toPatchResults.has(result.resolvedModule.resolvedFileName)) {
34
- result.resolvedModule.resolvedFileName = toPatchResults.get(result.resolvedModule.resolvedFileName);
35
- const sourceScript = getSourceScript(result.resolvedModule.resolvedFileName);
36
- if (sourceScript?.generated) {
37
- const serviceScript = sourceScript.generated.languagePlugin.typescript?.getServiceScript(sourceScript.generated.root);
38
- if (serviceScript) {
39
- result.resolvedModule.extension = serviceScript.extension;
40
- }
53
+ if (result.resolvedModule) {
54
+ const sourceFileInfo = toSourceFileInfo.get(result.resolvedModule.resolvedFileName);
55
+ if (sourceFileInfo) {
56
+ result.resolvedModule.resolvedFileName = sourceFileInfo.sourceFileName;
57
+ result.resolvedModule.extension = sourceFileInfo.extension;
41
58
  }
42
59
  }
43
- toPatchResults.clear();
60
+ toSourceFileInfo.clear();
44
61
  return result;
45
62
  };
46
63
  // fix https://github.com/vuejs/language-tools/issues/3332
47
64
  function fileExists(fileName) {
48
- if (languageServiceHost.fileExists(fileName)) {
49
- const fileSize = ts.sys.getFileSize?.(fileName) ?? languageServiceHost.readFile(fileName)?.length ?? 0;
65
+ if (host.fileExists(fileName)) {
66
+ const fileSize = ts.sys.getFileSize?.(fileName) ?? host.readFile(fileName)?.length ?? 0;
50
67
  return fileSize < 4 * 1024 * 1024;
51
68
  }
52
69
  return false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@volar/typescript",
3
- "version": "2.2.0-alpha.1",
3
+ "version": "2.2.0-alpha.10",
4
4
  "license": "MIT",
5
5
  "files": [
6
6
  "**/*.js",
@@ -12,13 +12,13 @@
12
12
  "directory": "packages/typescript"
13
13
  },
14
14
  "dependencies": {
15
- "@volar/language-core": "2.2.0-alpha.1",
15
+ "@volar/language-core": "2.2.0-alpha.10",
16
16
  "path-browserify": "^1.0.1"
17
17
  },
18
18
  "devDependencies": {
19
19
  "@types/node": "latest",
20
20
  "@types/path-browserify": "latest",
21
- "@volar/language-service": "2.2.0-alpha.1"
21
+ "@volar/language-service": "2.2.0-alpha.10"
22
22
  },
23
- "gitHead": "e6dcb83ecadcfcc9e22083eea61e1ee817a9d483"
23
+ "gitHead": "aedd2230883c457f703be93ed150917a3efde75c"
24
24
  }