@volar/typescript 2.4.11 → 2.4.12

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.
@@ -1,5 +1,17 @@
1
1
  import { Language } from '@volar/language-core';
2
2
  import type * as ts from 'typescript';
3
+ /**
4
+ * Creates and returns a Proxy around the base TypeScript LanguageService.
5
+ *
6
+ * This is used by the Volar TypeScript Plugin (which can be created by `createLanguageServicePlugin`
7
+ * and `createAsyncLanguageServicePlugin`) as an adapter layer between the TypeScript Language Service
8
+ * plugin API (see https://github.com/microsoft/TypeScript/wiki/Writing-a-Language-Service-Plugin)
9
+ * and a Volar `Language`.
10
+ *
11
+ * Once the `initialize` method is called, the proxy will begin intercepting requests and
12
+ * enhancing the default behavior of the LanguageService with enhancements based on
13
+ * the Volar `Language` that has been passed to `initialize`.
14
+ */
3
15
  export declare function createProxyLanguageService(languageService: ts.LanguageService): {
4
16
  initialize(language: Language<string>): void;
5
17
  proxy: ts.LanguageService;
@@ -6,6 +6,18 @@ const dedupe_1 = require("./dedupe");
6
6
  const transform_1 = require("./transform");
7
7
  const utils_1 = require("./utils");
8
8
  const windowsPathReg = /\\/g;
9
+ /**
10
+ * Creates and returns a Proxy around the base TypeScript LanguageService.
11
+ *
12
+ * This is used by the Volar TypeScript Plugin (which can be created by `createLanguageServicePlugin`
13
+ * and `createAsyncLanguageServicePlugin`) as an adapter layer between the TypeScript Language Service
14
+ * plugin API (see https://github.com/microsoft/TypeScript/wiki/Writing-a-Language-Service-Plugin)
15
+ * and a Volar `Language`.
16
+ *
17
+ * Once the `initialize` method is called, the proxy will begin intercepting requests and
18
+ * enhancing the default behavior of the LanguageService with enhancements based on
19
+ * the Volar `Language` that has been passed to `initialize`.
20
+ */
9
21
  function createProxyLanguageService(languageService) {
10
22
  const proxyCache = new Map();
11
23
  let getProxyMethod;
@@ -2,6 +2,12 @@ import type { CodeInformation, SourceScript } from '@volar/language-core';
2
2
  import { Language } from '@volar/language-core';
3
3
  import type * as ts from 'typescript';
4
4
  import type { TypeScriptServiceScript } from '../..';
5
+ /**
6
+ * This file contains a number of facilities for transforming `ts.Diagnostic`s returned
7
+ * from the base TypeScript LanguageService, which reference locations in generated
8
+ * TS code (e.g. the TypeScript codegen'd from the script portion of a .vue file) into locations
9
+ * in the script portion of the .vue file.
10
+ */
5
11
  export declare function transformCallHierarchyItem(language: Language<string>, item: ts.CallHierarchyItem, fallbackToAnyMatch: boolean, filter: (data: CodeInformation) => boolean): ts.CallHierarchyItem;
6
12
  export declare function transformDiagnostic<T extends ts.Diagnostic>(language: Language<string>, diagnostic: T, program: ts.Program | undefined, isTsc: boolean): T | undefined;
7
13
  export declare function fillSourceFileText(language: Language<string>, sourceFile: ts.SourceFile): void;
@@ -19,6 +19,12 @@ const language_core_1 = require("@volar/language-core");
19
19
  const utils_1 = require("./utils");
20
20
  const transformedDiagnostics = new WeakMap();
21
21
  const transformedSourceFile = new WeakSet();
22
+ /**
23
+ * This file contains a number of facilities for transforming `ts.Diagnostic`s returned
24
+ * from the base TypeScript LanguageService, which reference locations in generated
25
+ * TS code (e.g. the TypeScript codegen'd from the script portion of a .vue file) into locations
26
+ * in the script portion of the .vue file.
27
+ */
22
28
  function transformCallHierarchyItem(language, item, fallbackToAnyMatch, filter) {
23
29
  const span = transformSpan(language, item.file, item.span, fallbackToAnyMatch, filter);
24
30
  const selectionSpan = transformSpan(language, item.file, item.selectionSpan, fallbackToAnyMatch, filter);
@@ -1,6 +1,22 @@
1
- import { Language, LanguagePlugin } from '@volar/language-core';
2
1
  import type * as ts from 'typescript';
3
- export declare function createAsyncLanguageServicePlugin(extensions: string[], getScriptKindForExtraExtensions: ts.ScriptKind | ((fileName: string) => ts.ScriptKind), create: (ts: typeof import('typescript'), info: ts.server.PluginCreateInfo) => Promise<{
4
- languagePlugins: LanguagePlugin<string>[];
5
- setup?: (language: Language<string>) => void;
6
- }>): ts.server.PluginModuleFactory;
2
+ import type { createPluginCallbackAsync } from './languageServicePluginCommon';
3
+ /**
4
+ * Creates and returns a TS Service Plugin that supports async initialization.
5
+ * Essentially, this functions the same as `createLanguageServicePlugin`, but supports
6
+ * use cases in which the plugin callback must be async. For example in mdx-analyzer
7
+ * and Glint, this async variant is required because Glint + mdx-analyzer are written
8
+ * in ESM and get transpiled to CJS, which requires usage of `await import()` to load
9
+ * the necessary dependencies and fully initialize the plugin.
10
+ *
11
+ * To handle the period of time in which the plugin is initializing, this async
12
+ * variant stubs a number of methods on the LanguageServiceHost to handle the uninitialized state.
13
+ *
14
+ * Additionally, this async variant requires a few extra args pertaining to
15
+ * file extensions intended to be handled by the TS Plugin. In the synchronous variant,
16
+ * these can be synchronously inferred from elsewhere but for the async variant, they
17
+ * need to be passed in.
18
+ *
19
+ * See https://github.com/microsoft/TypeScript/wiki/Writing-a-Language-Service-Plugin for
20
+ * more information.
21
+ */
22
+ export declare function createAsyncLanguageServicePlugin(extensions: string[], getScriptKindForExtraExtensions: ts.ScriptKind | ((fileName: string) => ts.ScriptKind), createPluginCallbackAsync: createPluginCallbackAsync): ts.server.PluginModuleFactory;
@@ -1,130 +1,107 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createAsyncLanguageServicePlugin = createAsyncLanguageServicePlugin;
4
- const language_core_1 = require("@volar/language-core");
5
- const common_1 = require("../common");
6
4
  const proxyLanguageService_1 = require("../node/proxyLanguageService");
7
- const decorateLanguageServiceHost_1 = require("../node/decorateLanguageServiceHost");
8
- const createLanguageServicePlugin_1 = require("./createLanguageServicePlugin");
9
- function createAsyncLanguageServicePlugin(extensions, getScriptKindForExtraExtensions, create) {
5
+ const languageServicePluginCommon_1 = require("./languageServicePluginCommon");
6
+ /**
7
+ * Creates and returns a TS Service Plugin that supports async initialization.
8
+ * Essentially, this functions the same as `createLanguageServicePlugin`, but supports
9
+ * use cases in which the plugin callback must be async. For example in mdx-analyzer
10
+ * and Glint, this async variant is required because Glint + mdx-analyzer are written
11
+ * in ESM and get transpiled to CJS, which requires usage of `await import()` to load
12
+ * the necessary dependencies and fully initialize the plugin.
13
+ *
14
+ * To handle the period of time in which the plugin is initializing, this async
15
+ * variant stubs a number of methods on the LanguageServiceHost to handle the uninitialized state.
16
+ *
17
+ * Additionally, this async variant requires a few extra args pertaining to
18
+ * file extensions intended to be handled by the TS Plugin. In the synchronous variant,
19
+ * these can be synchronously inferred from elsewhere but for the async variant, they
20
+ * need to be passed in.
21
+ *
22
+ * See https://github.com/microsoft/TypeScript/wiki/Writing-a-Language-Service-Plugin for
23
+ * more information.
24
+ */
25
+ function createAsyncLanguageServicePlugin(extensions, getScriptKindForExtraExtensions, createPluginCallbackAsync) {
10
26
  return modules => {
11
27
  const { typescript: ts } = modules;
12
28
  const pluginModule = {
13
29
  create(info) {
14
- if (!createLanguageServicePlugin_1.decoratedLanguageServices.has(info.languageService)
15
- && !createLanguageServicePlugin_1.decoratedLanguageServiceHosts.has(info.languageServiceHost)) {
16
- createLanguageServicePlugin_1.decoratedLanguageServices.add(info.languageService);
17
- createLanguageServicePlugin_1.decoratedLanguageServiceHosts.add(info.languageServiceHost);
18
- const emptySnapshot = ts.ScriptSnapshot.fromString('');
19
- const getScriptSnapshot = info.languageServiceHost.getScriptSnapshot.bind(info.languageServiceHost);
20
- const getScriptVersion = info.languageServiceHost.getScriptVersion.bind(info.languageServiceHost);
21
- const getScriptKind = info.languageServiceHost.getScriptKind?.bind(info.languageServiceHost);
22
- const getProjectVersion = info.languageServiceHost.getProjectVersion?.bind(info.languageServiceHost);
23
- let initialized = false;
24
- info.languageServiceHost.getScriptSnapshot = fileName => {
25
- if (!initialized) {
26
- if (extensions.some(ext => fileName.endsWith(ext))) {
27
- return emptySnapshot;
28
- }
29
- if (getScriptInfo(fileName)?.isScriptOpen()) {
30
- return emptySnapshot;
31
- }
32
- }
33
- return getScriptSnapshot(fileName);
34
- };
35
- info.languageServiceHost.getScriptVersion = fileName => {
36
- if (!initialized) {
37
- if (extensions.some(ext => fileName.endsWith(ext))) {
38
- return 'initializing...';
39
- }
40
- if (getScriptInfo(fileName)?.isScriptOpen()) {
41
- return getScriptVersion(fileName) + ',initializing...';
42
- }
43
- }
44
- return getScriptVersion(fileName);
45
- };
46
- if (getScriptKind) {
47
- info.languageServiceHost.getScriptKind = fileName => {
48
- if (!initialized && extensions.some(ext => fileName.endsWith(ext))) {
49
- // bypass upstream bug https://github.com/microsoft/TypeScript/issues/57631
50
- // TODO: check if the bug is fixed in 5.5
51
- if (typeof getScriptKindForExtraExtensions === 'function') {
52
- return getScriptKindForExtraExtensions(fileName);
53
- }
54
- else {
55
- return getScriptKindForExtraExtensions;
56
- }
57
- }
58
- return getScriptKind(fileName);
59
- };
60
- }
61
- if (getProjectVersion) {
62
- info.languageServiceHost.getProjectVersion = () => {
63
- if (!initialized) {
64
- return getProjectVersion() + ',initializing...';
65
- }
66
- return getProjectVersion();
67
- };
68
- }
30
+ if (!(0, languageServicePluginCommon_1.isHasAlreadyDecoratedLanguageService)(info)) {
31
+ const state = decorateWithAsyncInitializationHandling(ts, info, extensions, getScriptKindForExtraExtensions);
69
32
  const { proxy, initialize } = (0, proxyLanguageService_1.createProxyLanguageService)(info.languageService);
70
33
  info.languageService = proxy;
71
- create(ts, info).then(({ languagePlugins, setup }) => {
72
- const language = (0, language_core_1.createLanguage)([
73
- ...languagePlugins,
74
- { getLanguageId: common_1.resolveFileLanguageId },
75
- ], new language_core_1.FileMap(ts.sys.useCaseSensitiveFileNames), (fileName, _, shouldRegister) => {
76
- let snapshot;
77
- if (shouldRegister) {
78
- // We need to trigger registration of the script file with the project, see #250
79
- snapshot = getScriptSnapshot(fileName);
80
- }
81
- else {
82
- snapshot = getScriptInfo(fileName)?.getSnapshot();
83
- if (!snapshot) {
84
- // trigger projectService.getOrCreateScriptInfoNotOpenedByClient
85
- info.project.getScriptVersion(fileName);
86
- snapshot = getScriptInfo(fileName)?.getSnapshot();
87
- }
88
- }
89
- if (snapshot) {
90
- language.scripts.set(fileName, snapshot);
91
- }
92
- else {
93
- language.scripts.delete(fileName);
94
- }
95
- });
96
- initialize(language);
97
- (0, decorateLanguageServiceHost_1.decorateLanguageServiceHost)(ts, language, info.languageServiceHost);
98
- setup?.(language);
99
- initialized = true;
34
+ createPluginCallbackAsync(ts, info).then(createPluginResult => {
35
+ (0, languageServicePluginCommon_1.createLanguageCommon)(createPluginResult, ts, info, initialize);
36
+ state.initialized = true;
100
37
  if ('markAsDirty' in info.project && typeof info.project.markAsDirty === 'function') {
38
+ // This is an attempt to mark the project as dirty so that in case the IDE/tsserver
39
+ // already finished a first pass of generating diagnostics (or other things), another
40
+ // pass will be triggered which should hopefully make use of this now-initialized plugin.
101
41
  info.project.markAsDirty();
102
42
  }
103
43
  });
104
44
  }
105
45
  return info.languageService;
106
- function getScriptInfo(fileName) {
107
- // getSnapshot could be crashed if the file is too large
108
- try {
109
- return info.project.getScriptInfo(fileName);
110
- }
111
- catch { }
112
- }
113
- },
114
- getExternalFiles(project, updateLevel = 0) {
115
- if (updateLevel >= 1
116
- || !createLanguageServicePlugin_1.externalFiles.has(project)) {
117
- const oldFiles = createLanguageServicePlugin_1.externalFiles.get(project);
118
- const newFiles = extensions.length ? (0, decorateLanguageServiceHost_1.searchExternalFiles)(ts, project, extensions) : [];
119
- createLanguageServicePlugin_1.externalFiles.set(project, newFiles);
120
- if (oldFiles && !(0, createLanguageServicePlugin_1.arrayItemsEqual)(oldFiles, newFiles)) {
121
- project.refreshDiagnostics();
122
- }
123
- }
124
- return createLanguageServicePlugin_1.externalFiles.get(project);
125
46
  },
47
+ getExternalFiles: (0, languageServicePluginCommon_1.makeGetExternalFiles)(ts),
126
48
  };
127
49
  return pluginModule;
128
50
  };
129
51
  }
52
+ function decorateWithAsyncInitializationHandling(ts, info, extensions, getScriptKindForExtraExtensions) {
53
+ const emptySnapshot = ts.ScriptSnapshot.fromString('');
54
+ const getScriptSnapshot = info.languageServiceHost.getScriptSnapshot.bind(info.languageServiceHost);
55
+ const getScriptVersion = info.languageServiceHost.getScriptVersion.bind(info.languageServiceHost);
56
+ const getScriptKind = info.languageServiceHost.getScriptKind?.bind(info.languageServiceHost);
57
+ const getProjectVersion = info.languageServiceHost.getProjectVersion?.bind(info.languageServiceHost);
58
+ const getScriptInfo = (0, languageServicePluginCommon_1.makeGetScriptInfoWithLargeFileFailsafe)(info);
59
+ const state = { initialized: false };
60
+ info.languageServiceHost.getScriptSnapshot = fileName => {
61
+ if (!state.initialized) {
62
+ if (extensions.some(ext => fileName.endsWith(ext))) {
63
+ return emptySnapshot;
64
+ }
65
+ if (getScriptInfo(fileName)?.isScriptOpen()) {
66
+ return emptySnapshot;
67
+ }
68
+ }
69
+ return getScriptSnapshot(fileName);
70
+ };
71
+ info.languageServiceHost.getScriptVersion = fileName => {
72
+ if (!state.initialized) {
73
+ if (extensions.some(ext => fileName.endsWith(ext))) {
74
+ return 'initializing...';
75
+ }
76
+ if (getScriptInfo(fileName)?.isScriptOpen()) {
77
+ return getScriptVersion(fileName) + ',initializing...';
78
+ }
79
+ }
80
+ return getScriptVersion(fileName);
81
+ };
82
+ if (getScriptKind) {
83
+ info.languageServiceHost.getScriptKind = fileName => {
84
+ if (!state.initialized && extensions.some(ext => fileName.endsWith(ext))) {
85
+ // bypass upstream bug https://github.com/microsoft/TypeScript/issues/57631
86
+ // TODO: check if the bug is fixed in 5.5
87
+ if (typeof getScriptKindForExtraExtensions === 'function') {
88
+ return getScriptKindForExtraExtensions(fileName);
89
+ }
90
+ else {
91
+ return getScriptKindForExtraExtensions;
92
+ }
93
+ }
94
+ return getScriptKind(fileName);
95
+ };
96
+ }
97
+ if (getProjectVersion) {
98
+ info.languageServiceHost.getProjectVersion = () => {
99
+ if (!state.initialized) {
100
+ return getProjectVersion() + ',initializing...';
101
+ }
102
+ return getProjectVersion();
103
+ };
104
+ }
105
+ return state;
106
+ }
130
107
  //# sourceMappingURL=createAsyncLanguageServicePlugin.js.map
@@ -1,11 +1,9 @@
1
- import { Language, LanguagePlugin } from '@volar/language-core';
2
1
  import type * as ts from 'typescript';
3
- export declare const externalFiles: WeakMap<ts.server.Project, string[]>;
4
- export declare const projectExternalFileExtensions: WeakMap<ts.server.Project, string[]>;
5
- export declare const decoratedLanguageServices: WeakSet<ts.LanguageService>;
6
- export declare const decoratedLanguageServiceHosts: WeakSet<ts.LanguageServiceHost>;
7
- export declare function createLanguageServicePlugin(create: (ts: typeof import('typescript'), info: ts.server.PluginCreateInfo) => {
8
- languagePlugins: LanguagePlugin<string>[];
9
- setup?: (language: Language<string>) => void;
10
- }): ts.server.PluginModuleFactory;
11
- export declare function arrayItemsEqual(a: string[], b: string[]): boolean;
2
+ import type { createPluginCallbackSync } from './languageServicePluginCommon';
3
+ /**
4
+ * Creates and returns a TS Service Plugin using Volar primitives.
5
+ *
6
+ * See https://github.com/microsoft/TypeScript/wiki/Writing-a-Language-Service-Plugin for
7
+ * more information.
8
+ */
9
+ export declare function createLanguageServicePlugin(createPluginCallback: createPluginCallbackSync): ts.server.PluginModuleFactory;
@@ -1,97 +1,36 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.decoratedLanguageServiceHosts = exports.decoratedLanguageServices = exports.projectExternalFileExtensions = exports.externalFiles = void 0;
4
3
  exports.createLanguageServicePlugin = createLanguageServicePlugin;
5
- exports.arrayItemsEqual = arrayItemsEqual;
6
- const language_core_1 = require("@volar/language-core");
7
- const common_1 = require("../common");
8
4
  const proxyLanguageService_1 = require("../node/proxyLanguageService");
9
- const decorateLanguageServiceHost_1 = require("../node/decorateLanguageServiceHost");
10
- exports.externalFiles = new WeakMap();
11
- exports.projectExternalFileExtensions = new WeakMap();
12
- exports.decoratedLanguageServices = new WeakSet();
13
- exports.decoratedLanguageServiceHosts = new WeakSet();
14
- function createLanguageServicePlugin(create) {
5
+ const languageServicePluginCommon_1 = require("./languageServicePluginCommon");
6
+ /**
7
+ * Creates and returns a TS Service Plugin using Volar primitives.
8
+ *
9
+ * See https://github.com/microsoft/TypeScript/wiki/Writing-a-Language-Service-Plugin for
10
+ * more information.
11
+ */
12
+ function createLanguageServicePlugin(createPluginCallback) {
15
13
  return modules => {
16
14
  const { typescript: ts } = modules;
17
15
  const pluginModule = {
18
16
  create(info) {
19
- if (!exports.decoratedLanguageServices.has(info.languageService)
20
- && !exports.decoratedLanguageServiceHosts.has(info.languageServiceHost)) {
21
- exports.decoratedLanguageServices.add(info.languageService);
22
- exports.decoratedLanguageServiceHosts.add(info.languageServiceHost);
23
- const { languagePlugins, setup } = create(ts, info);
24
- const extensions = languagePlugins
17
+ if (!(0, languageServicePluginCommon_1.isHasAlreadyDecoratedLanguageService)(info)) {
18
+ const createPluginResult = createPluginCallback(ts, info);
19
+ const extensions = createPluginResult.languagePlugins
25
20
  .map(plugin => plugin.typescript?.extraFileExtensions.map(ext => '.' + ext.extension) ?? [])
26
21
  .flat();
27
- exports.projectExternalFileExtensions.set(info.project, extensions);
28
- const getScriptSnapshot = info.languageServiceHost.getScriptSnapshot.bind(info.languageServiceHost);
29
- const language = (0, language_core_1.createLanguage)([
30
- ...languagePlugins,
31
- { getLanguageId: common_1.resolveFileLanguageId },
32
- ], new language_core_1.FileMap(ts.sys.useCaseSensitiveFileNames), (fileName, _, shouldRegister) => {
33
- let snapshot;
34
- if (shouldRegister) {
35
- // We need to trigger registration of the script file with the project, see #250
36
- snapshot = getScriptSnapshot(fileName);
37
- }
38
- else {
39
- snapshot = getScriptInfo(fileName)?.getSnapshot();
40
- if (!snapshot) {
41
- // trigger projectService.getOrCreateScriptInfoNotOpenedByClient
42
- info.project.getScriptVersion(fileName);
43
- snapshot = getScriptInfo(fileName)?.getSnapshot();
44
- }
45
- }
46
- if (snapshot) {
47
- language.scripts.set(fileName, snapshot);
48
- }
49
- else {
50
- language.scripts.delete(fileName);
51
- }
52
- });
22
+ // TODO: this logic does not seem to appear in the async variant
23
+ // (createAsyncLanguageServicePlugin)... bug?
24
+ languageServicePluginCommon_1.projectExternalFileExtensions.set(info.project, extensions);
53
25
  const { proxy, initialize } = (0, proxyLanguageService_1.createProxyLanguageService)(info.languageService);
54
26
  info.languageService = proxy;
55
- initialize(language);
56
- (0, decorateLanguageServiceHost_1.decorateLanguageServiceHost)(ts, language, info.languageServiceHost);
57
- setup?.(language);
27
+ (0, languageServicePluginCommon_1.createLanguageCommon)(createPluginResult, ts, info, initialize);
58
28
  }
59
29
  return info.languageService;
60
- function getScriptInfo(fileName) {
61
- // getSnapshot could be crashed if the file is too large
62
- try {
63
- return info.project.getScriptInfo(fileName);
64
- }
65
- catch { }
66
- }
67
- },
68
- getExternalFiles(project, updateLevel = 0) {
69
- if (updateLevel >= 1
70
- || !exports.externalFiles.has(project)) {
71
- const oldFiles = exports.externalFiles.get(project);
72
- const extensions = exports.projectExternalFileExtensions.get(project);
73
- const newFiles = extensions?.length ? (0, decorateLanguageServiceHost_1.searchExternalFiles)(ts, project, extensions) : [];
74
- exports.externalFiles.set(project, newFiles);
75
- if (oldFiles && !arrayItemsEqual(oldFiles, newFiles)) {
76
- project.refreshDiagnostics();
77
- }
78
- }
79
- return exports.externalFiles.get(project);
80
30
  },
31
+ getExternalFiles: (0, languageServicePluginCommon_1.makeGetExternalFiles)(ts),
81
32
  };
82
33
  return pluginModule;
83
34
  };
84
35
  }
85
- function arrayItemsEqual(a, b) {
86
- if (a.length !== b.length) {
87
- return false;
88
- }
89
- const set = new Set(a);
90
- for (const file of b) {
91
- if (!set.has(file)) {
92
- return false;
93
- }
94
- }
95
- return true;
96
- }
97
36
  //# sourceMappingURL=createLanguageServicePlugin.js.map
@@ -0,0 +1,24 @@
1
+ import { Language, LanguagePlugin } from '@volar/language-core/lib/types';
2
+ import type * as ts from 'typescript';
3
+ export declare const externalFiles: WeakMap<ts.server.Project, string[]>;
4
+ export declare const projectExternalFileExtensions: WeakMap<ts.server.Project, string[]>;
5
+ export declare const decoratedLanguageServices: WeakSet<ts.LanguageService>;
6
+ export declare const decoratedLanguageServiceHosts: WeakSet<ts.LanguageServiceHost>;
7
+ /**
8
+ * Wrap `getScriptInfo` to handle large files that may crash the language service.
9
+ *
10
+ * Introduced to fix issues with converting `relatedInformation` (in Diagnostics)
11
+ * when working with large files.
12
+ *
13
+ * https://github.com/volarjs/volar.js/commit/e242709a91e9d2919dc4fa59278dd266fd11e7a3
14
+ */
15
+ export declare function makeGetScriptInfoWithLargeFileFailsafe(info: ts.server.PluginCreateInfo): (fileName: string) => ts.server.ScriptInfo | undefined;
16
+ export declare function createLanguageCommon(createPluginResult: createPluginCallbackReturnValue, ts: typeof import('typescript'), info: ts.server.PluginCreateInfo, initializeProxiedLanguageService: (language: Language<string>) => void): void;
17
+ export declare const makeGetExternalFiles: (ts: typeof import("typescript")) => (project: ts.server.Project, updateLevel?: number) => string[];
18
+ export type createPluginCallbackReturnValue = {
19
+ languagePlugins: LanguagePlugin<string>[];
20
+ setup?: (language: Language<string>) => void;
21
+ };
22
+ export type createPluginCallbackSync = (ts: typeof import('typescript'), info: ts.server.PluginCreateInfo) => createPluginCallbackReturnValue;
23
+ export type createPluginCallbackAsync = (ts: typeof import('typescript'), info: ts.server.PluginCreateInfo) => Promise<createPluginCallbackReturnValue>;
24
+ export declare function isHasAlreadyDecoratedLanguageService(info: ts.server.PluginCreateInfo): boolean;
@@ -0,0 +1,109 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.makeGetExternalFiles = exports.decoratedLanguageServiceHosts = exports.decoratedLanguageServices = exports.projectExternalFileExtensions = exports.externalFiles = void 0;
4
+ exports.makeGetScriptInfoWithLargeFileFailsafe = makeGetScriptInfoWithLargeFileFailsafe;
5
+ exports.createLanguageCommon = createLanguageCommon;
6
+ exports.isHasAlreadyDecoratedLanguageService = isHasAlreadyDecoratedLanguageService;
7
+ const language_core_1 = require("@volar/language-core");
8
+ const common_1 = require("../common");
9
+ const decorateLanguageServiceHost_1 = require("../node/decorateLanguageServiceHost");
10
+ exports.externalFiles = new WeakMap();
11
+ exports.projectExternalFileExtensions = new WeakMap();
12
+ exports.decoratedLanguageServices = new WeakSet();
13
+ exports.decoratedLanguageServiceHosts = new WeakSet();
14
+ /**
15
+ * Wrap `getScriptInfo` to handle large files that may crash the language service.
16
+ *
17
+ * Introduced to fix issues with converting `relatedInformation` (in Diagnostics)
18
+ * when working with large files.
19
+ *
20
+ * https://github.com/volarjs/volar.js/commit/e242709a91e9d2919dc4fa59278dd266fd11e7a3
21
+ */
22
+ function makeGetScriptInfoWithLargeFileFailsafe(info) {
23
+ return (fileName) => {
24
+ // getSnapshot could be crashed if the file is too large
25
+ try {
26
+ return info.project.getScriptInfo(fileName);
27
+ }
28
+ catch { }
29
+ };
30
+ }
31
+ function createLanguageCommon(createPluginResult, ts, info, initializeProxiedLanguageService) {
32
+ const getScriptSnapshot = info.languageServiceHost.getScriptSnapshot.bind(info.languageServiceHost);
33
+ const getScriptInfo = makeGetScriptInfoWithLargeFileFailsafe(info);
34
+ const language = (0, language_core_1.createLanguage)([
35
+ ...createPluginResult.languagePlugins,
36
+ { getLanguageId: common_1.resolveFileLanguageId },
37
+ ], new language_core_1.FileMap(ts.sys.useCaseSensitiveFileNames), (fileName, _, shouldRegister) => {
38
+ let snapshot;
39
+ if (shouldRegister) {
40
+ // We need to trigger registration of the script file with the project, see #250
41
+ snapshot = getScriptSnapshot(fileName);
42
+ }
43
+ else {
44
+ snapshot = getScriptInfo(fileName)?.getSnapshot();
45
+ if (!snapshot) {
46
+ // trigger projectService.getOrCreateScriptInfoNotOpenedByClient
47
+ info.project.getScriptVersion(fileName);
48
+ snapshot = getScriptInfo(fileName)?.getSnapshot();
49
+ }
50
+ }
51
+ if (snapshot) {
52
+ language.scripts.set(fileName, snapshot);
53
+ }
54
+ else {
55
+ language.scripts.delete(fileName);
56
+ }
57
+ }, targetFileName => {
58
+ // https://github.com/JetBrains/intellij-plugins/blob/6435723ad88fa296b41144162ebe3b8513f4949b/Angular/src-js/angular-service/src/ngCommands.ts#L88
59
+ info.session.change({
60
+ file: targetFileName,
61
+ line: 1,
62
+ offset: 1,
63
+ endLine: 1,
64
+ endOffset: 1,
65
+ insertString: '',
66
+ });
67
+ });
68
+ initializeProxiedLanguageService(language);
69
+ (0, decorateLanguageServiceHost_1.decorateLanguageServiceHost)(ts, language, info.languageServiceHost);
70
+ createPluginResult.setup?.(language);
71
+ }
72
+ const makeGetExternalFiles = (ts) => (project, updateLevel = 0) => {
73
+ if (updateLevel >= 1
74
+ || !exports.externalFiles.has(project)) {
75
+ const oldFiles = exports.externalFiles.get(project);
76
+ const extensions = exports.projectExternalFileExtensions.get(project);
77
+ const newFiles = extensions?.length ? (0, decorateLanguageServiceHost_1.searchExternalFiles)(ts, project, extensions) : [];
78
+ exports.externalFiles.set(project, newFiles);
79
+ if (oldFiles && !arrayItemsEqual(oldFiles, newFiles)) {
80
+ project.refreshDiagnostics();
81
+ }
82
+ }
83
+ return exports.externalFiles.get(project);
84
+ };
85
+ exports.makeGetExternalFiles = makeGetExternalFiles;
86
+ function arrayItemsEqual(a, b) {
87
+ if (a.length !== b.length) {
88
+ return false;
89
+ }
90
+ const set = new Set(a);
91
+ for (const file of b) {
92
+ if (!set.has(file)) {
93
+ return false;
94
+ }
95
+ }
96
+ return true;
97
+ }
98
+ function isHasAlreadyDecoratedLanguageService(info) {
99
+ if (exports.decoratedLanguageServices.has(info.languageService)
100
+ || exports.decoratedLanguageServiceHosts.has(info.languageServiceHost)) {
101
+ return true;
102
+ }
103
+ else {
104
+ exports.decoratedLanguageServices.add(info.languageService);
105
+ exports.decoratedLanguageServiceHosts.add(info.languageServiceHost);
106
+ return false;
107
+ }
108
+ }
109
+ //# sourceMappingURL=languageServicePluginCommon.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@volar/typescript",
3
- "version": "2.4.11",
3
+ "version": "2.4.12",
4
4
  "license": "MIT",
5
5
  "files": [
6
6
  "**/*.js",
@@ -12,14 +12,14 @@
12
12
  "directory": "packages/typescript"
13
13
  },
14
14
  "dependencies": {
15
- "@volar/language-core": "2.4.11",
15
+ "@volar/language-core": "2.4.12",
16
16
  "path-browserify": "^1.0.1",
17
17
  "vscode-uri": "^3.0.8"
18
18
  },
19
19
  "devDependencies": {
20
20
  "@types/node": "latest",
21
21
  "@types/path-browserify": "latest",
22
- "@volar/language-service": "2.4.11"
22
+ "@volar/language-service": "2.4.12"
23
23
  },
24
- "gitHead": "42ccae005cc8516e07ad38f4d7730cab9b723340"
24
+ "gitHead": "17b9b8a1f522afd1aad1e598d2fd935680d8a8d7"
25
25
  }