@volar/language-core 1.6.8 → 1.7.0

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,21 +1,7 @@
1
- import type * as ts from 'typescript/lib/tsserverlibrary';
2
- import { Language, LanguageServiceHost } from './types';
3
- export type LanguageContext = ReturnType<typeof createLanguageContext>;
4
- export declare function createLanguageContext(modules: {
5
- typescript?: typeof import('typescript/lib/tsserverlibrary');
6
- }, host: LanguageServiceHost, languages: Language[]): {
7
- typescript: {
8
- languageServiceHost: ts.LanguageServiceHost;
9
- };
10
- virtualFiles: {
11
- allSources(): import("./virtualFiles").Source[];
12
- updateSource(fileName: string, snapshot: ts.IScriptSnapshot, languageId: string | undefined): import("./types").VirtualFile | undefined;
13
- deleteSource(fileName: string): void;
14
- getSource(fileName: string): import("./virtualFiles").Source | undefined;
15
- hasSource: (fileName: string) => boolean;
16
- getMirrorMap: (file: import("./types").VirtualFile) => import("./sourceMaps").MirrorMap | undefined;
17
- getMaps: (virtualFile: import("./types").VirtualFile) => [string, import("@volar/source-map").SourceMap<import("./types").FileRangeCapabilities>][];
18
- hasVirtualFile(fileName: string): boolean;
19
- getVirtualFile(fileName: string): readonly [import("./types").VirtualFile, import("./virtualFiles").Source] | readonly [undefined, undefined];
20
- };
21
- };
1
+ import { createVirtualFiles } from './virtualFiles';
2
+ import { Language, TypeScriptLanguageHost } from './types';
3
+ export interface LanguageContext {
4
+ host: TypeScriptLanguageHost;
5
+ virtualFiles: ReturnType<typeof createVirtualFiles>;
6
+ }
7
+ export declare function createLanguageContext(host: TypeScriptLanguageHost, languages: Language<any>[]): LanguageContext;
@@ -1,10 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createLanguageContext = void 0;
4
- const path_1 = require("path");
5
4
  const virtualFiles_1 = require("./virtualFiles");
6
- const types_1 = require("./types");
7
- function createLanguageContext(modules, host, languages) {
5
+ ;
6
+ function createLanguageContext(host, languages) {
8
7
  for (const language of languages.reverse()) {
9
8
  if (language.resolveHost) {
10
9
  const pastHost = host;
@@ -24,232 +23,42 @@ function createLanguageContext(modules, host, languages) {
24
23
  }
25
24
  }
26
25
  let lastProjectVersion;
27
- let tsProjectVersion = 0;
28
26
  const virtualFiles = (0, virtualFiles_1.createVirtualFiles)(languages);
29
- const ts = modules.typescript;
30
- const scriptSnapshots = new Map();
31
- const sourceTsFileVersions = new Map();
32
- const sourceFileVersions = new Map();
33
- const virtualFileVersions = new Map();
34
- const _tsHost = {
35
- fileExists: host.fileExists
36
- ? fileName => {
37
- const ext = fileName.substring(fileName.lastIndexOf('.'));
38
- if (ext === '.js'
39
- || ext === '.ts'
40
- || ext === '.jsx'
41
- || ext === '.tsx') {
42
- /**
43
- * If try to access a external .vue file that outside of the project,
44
- * the file will not process by language service host,
45
- * so virtual file will not be created.
46
- *
47
- * We try to create virtual file here.
48
- */
49
- const sourceFileName = fileName.substring(0, fileName.lastIndexOf('.'));
50
- if (!virtualFiles.hasSource(sourceFileName)) {
51
- const scriptSnapshot = host.getScriptSnapshot(sourceFileName);
52
- if (scriptSnapshot) {
53
- virtualFiles.updateSource(sourceFileName, scriptSnapshot, host.getScriptLanguageId?.(sourceFileName));
54
- }
55
- }
56
- }
57
- if (virtualFiles.hasVirtualFile(fileName)) {
58
- return true;
59
- }
60
- return !!host.fileExists?.(fileName);
61
- }
62
- : undefined,
63
- getProjectVersion: () => {
64
- return tsProjectVersion.toString();
65
- },
66
- getScriptFileNames,
67
- getScriptVersion,
68
- getScriptSnapshot,
69
- readDirectory: (_path, extensions, exclude, include, depth) => {
70
- const result = host.readDirectory?.(_path, extensions, exclude, include, depth) ?? [];
71
- for (const { fileName } of virtualFiles.allSources()) {
72
- const vuePath2 = path_1.posix.join(_path, path_1.posix.basename(fileName));
73
- if (path_1.posix.relative(_path.toLowerCase(), fileName.toLowerCase()).startsWith('..')) {
74
- continue;
75
- }
76
- if (!depth && fileName.toLowerCase() === vuePath2.toLowerCase()) {
77
- result.push(vuePath2);
78
- }
79
- else if (depth) {
80
- result.push(vuePath2); // TODO: depth num
81
- }
82
- }
83
- return result;
84
- },
85
- getScriptKind(fileName) {
86
- if (ts) {
87
- if (virtualFiles.hasSource(fileName))
88
- return ts.ScriptKind.Deferred;
89
- switch (path_1.posix.extname(fileName)) {
90
- case '.js': return ts.ScriptKind.JS;
91
- case '.jsx': return ts.ScriptKind.JSX;
92
- case '.ts': return ts.ScriptKind.TS;
93
- case '.tsx': return ts.ScriptKind.TSX;
94
- case '.json': return ts.ScriptKind.JSON;
95
- default: return ts.ScriptKind.Unknown;
96
- }
97
- }
98
- return 0;
99
- },
100
- };
101
27
  return {
102
- typescript: {
103
- languageServiceHost: new Proxy(_tsHost, {
104
- get: (target, property) => {
105
- update();
106
- return target[property] || host[property];
107
- },
108
- }),
109
- },
28
+ host,
110
29
  virtualFiles: new Proxy(virtualFiles, {
111
30
  get: (target, property) => {
112
- update();
31
+ syncVirtualFiles();
113
32
  return target[property];
114
33
  },
115
34
  }),
116
35
  };
117
- function update() {
118
- const newProjectVersion = host.getProjectVersion?.();
119
- const shouldUpdate = newProjectVersion === undefined || newProjectVersion !== lastProjectVersion;
120
- lastProjectVersion = newProjectVersion;
36
+ function syncVirtualFiles() {
37
+ const newProjectVersion = host.getProjectVersion();
38
+ const shouldUpdate = newProjectVersion !== lastProjectVersion;
121
39
  if (!shouldUpdate)
122
40
  return;
123
- let shouldUpdateTsProject = false;
124
- let virtualFilesUpdatedNum = 0;
41
+ lastProjectVersion = newProjectVersion;
125
42
  const remainRootFiles = new Set(host.getScriptFileNames());
126
- // .vue
127
- for (const { fileName } of virtualFiles.allSources()) {
43
+ for (const { fileName, snapshot } of virtualFiles.allSources()) {
128
44
  remainRootFiles.delete(fileName);
129
- const snapshot = host.getScriptSnapshot(fileName);
130
- if (!snapshot) {
45
+ const newSnapshot = host.getScriptSnapshot(fileName);
46
+ if (!newSnapshot) {
131
47
  // delete
132
48
  virtualFiles.deleteSource(fileName);
133
- shouldUpdateTsProject = true;
134
- virtualFilesUpdatedNum++;
135
- continue;
136
49
  }
137
- const newVersion = host.getScriptVersion(fileName);
138
- if (sourceFileVersions.get(fileName) !== newVersion) {
50
+ else if (newSnapshot !== snapshot) {
139
51
  // update
140
- sourceFileVersions.set(fileName, newVersion);
141
- virtualFiles.updateSource(fileName, snapshot, host.getScriptLanguageId?.(fileName));
142
- virtualFilesUpdatedNum++;
52
+ virtualFiles.updateSource(fileName, newSnapshot, host.getLanguageId?.(fileName));
143
53
  }
144
54
  }
145
- // no any vue file version change, it mean project version was update by ts file change at this time
146
- if (!virtualFilesUpdatedNum) {
147
- shouldUpdateTsProject = true;
148
- }
149
- // add
55
+ // create
150
56
  for (const fileName of [...remainRootFiles]) {
151
57
  const snapshot = host.getScriptSnapshot(fileName);
152
58
  if (snapshot) {
153
- const virtualFile = virtualFiles.updateSource(fileName, snapshot, host.getScriptLanguageId?.(fileName));
154
- if (virtualFile) {
155
- remainRootFiles.delete(fileName);
156
- }
157
- }
158
- }
159
- // .ts / .js / .d.ts / .json ...
160
- for (const [oldTsFileName, oldTsFileVersion] of [...sourceTsFileVersions]) {
161
- const newVersion = host.getScriptVersion(oldTsFileName);
162
- if (oldTsFileVersion !== newVersion) {
163
- if (!remainRootFiles.has(oldTsFileName) && !host.getScriptSnapshot(oldTsFileName)) {
164
- // delete
165
- sourceTsFileVersions.delete(oldTsFileName);
166
- }
167
- else {
168
- // update
169
- sourceTsFileVersions.set(oldTsFileName, newVersion);
170
- }
171
- shouldUpdateTsProject = true;
59
+ virtualFiles.updateSource(fileName, snapshot, host.getLanguageId?.(fileName));
172
60
  }
173
61
  }
174
- for (const nowFileName of remainRootFiles) {
175
- if (!sourceTsFileVersions.has(nowFileName)) {
176
- // add
177
- const newVersion = host.getScriptVersion(nowFileName);
178
- sourceTsFileVersions.set(nowFileName, newVersion);
179
- shouldUpdateTsProject = true;
180
- }
181
- }
182
- for (const { root: rootVirtualFile } of virtualFiles.allSources()) {
183
- if (!shouldUpdateTsProject) {
184
- (0, virtualFiles_1.forEachEmbeddedFile)(rootVirtualFile, embedded => {
185
- if (embedded.kind === types_1.FileKind.TypeScriptHostFile) {
186
- if (virtualFileVersions.has(embedded.fileName) && virtualFileVersions.get(embedded.fileName)?.virtualFileSnapshot !== embedded.snapshot) {
187
- shouldUpdateTsProject = true;
188
- }
189
- }
190
- });
191
- }
192
- }
193
- if (shouldUpdateTsProject) {
194
- tsProjectVersion++;
195
- }
196
- }
197
- function getScriptFileNames() {
198
- const tsFileNames = new Set();
199
- for (const { root: rootVirtualFile } of virtualFiles.allSources()) {
200
- (0, virtualFiles_1.forEachEmbeddedFile)(rootVirtualFile, embedded => {
201
- if (embedded.kind === types_1.FileKind.TypeScriptHostFile) {
202
- tsFileNames.add(embedded.fileName); // virtual .ts
203
- }
204
- });
205
- }
206
- for (const fileName of host.getScriptFileNames()) {
207
- if (!virtualFiles.hasSource(fileName)) {
208
- tsFileNames.add(fileName); // .ts
209
- }
210
- }
211
- return [...tsFileNames];
212
- }
213
- function getScriptVersion(fileName) {
214
- let [virtualFile, source] = virtualFiles.getVirtualFile(fileName);
215
- if (virtualFile && source) {
216
- let version = virtualFileVersions.get(virtualFile.fileName);
217
- if (!version) {
218
- version = {
219
- value: 0,
220
- virtualFileSnapshot: virtualFile.snapshot,
221
- sourceFileSnapshot: source.snapshot,
222
- };
223
- virtualFileVersions.set(virtualFile.fileName, version);
224
- }
225
- else if (version.virtualFileSnapshot !== virtualFile.snapshot
226
- || (host.isTsc && version.sourceFileSnapshot !== source.snapshot) // fix https://github.com/johnsoncodehk/volar/issues/1082
227
- ) {
228
- version.value++;
229
- version.virtualFileSnapshot = virtualFile.snapshot;
230
- version.sourceFileSnapshot = source.snapshot;
231
- }
232
- return version.value.toString();
233
- }
234
- return host.getScriptVersion(fileName);
235
- }
236
- function getScriptSnapshot(fileName) {
237
- const version = getScriptVersion(fileName);
238
- const cache = scriptSnapshots.get(fileName.toLowerCase());
239
- if (cache && cache[0] === version) {
240
- return cache[1];
241
- }
242
- const [virtualFile] = virtualFiles.getVirtualFile(fileName);
243
- if (virtualFile) {
244
- const snapshot = virtualFile.snapshot;
245
- scriptSnapshots.set(fileName.toLowerCase(), [version, snapshot]);
246
- return snapshot;
247
- }
248
- let tsScript = host.getScriptSnapshot(fileName);
249
- if (tsScript) {
250
- scriptSnapshots.set(fileName.toLowerCase(), [version, tsScript]);
251
- return tsScript;
252
- }
253
62
  }
254
63
  }
255
64
  exports.createLanguageContext = createLanguageContext;
package/out/types.d.ts CHANGED
@@ -20,7 +20,9 @@ export interface FileRangeCapabilities {
20
20
  additional?: boolean;
21
21
  autoImportOnly?: boolean;
22
22
  };
23
- diagnostic?: boolean;
23
+ diagnostic?: boolean | {
24
+ shouldReport(): boolean;
25
+ };
24
26
  semanticTokens?: boolean;
25
27
  referencesCodeLens?: boolean;
26
28
  displayWithLink?: boolean;
@@ -54,12 +56,23 @@ export interface VirtualFile {
54
56
  embeddedFiles: VirtualFile[];
55
57
  }
56
58
  export interface Language<T extends VirtualFile = VirtualFile> {
57
- resolveHost?(host: LanguageServiceHost): LanguageServiceHost;
59
+ resolveHost?(host: TypeScriptLanguageHost): TypeScriptLanguageHost;
58
60
  createVirtualFile(fileName: string, snapshot: ts.IScriptSnapshot, languageId: string | undefined): T | undefined;
59
61
  updateVirtualFile(virtualFile: T, snapshot: ts.IScriptSnapshot): void;
60
62
  deleteVirtualFile?(virtualFile: T): void;
61
63
  }
62
- export interface LanguageServiceHost extends ts.LanguageServiceHost {
63
- getScriptLanguageId?(fileName: string): string | undefined;
64
- isTsc?: boolean;
64
+ interface LanguageHost {
65
+ getProjectVersion(): number | string;
66
+ getScriptFileNames(): string[];
67
+ getScriptSnapshot(fileName: string): ts.IScriptSnapshot | undefined;
68
+ getLanguageId?(fileName: string): string | undefined;
69
+ }
70
+ export interface TypeScriptLanguageHost extends LanguageHost {
71
+ getScriptVersion(fileName: string): string | undefined;
72
+ getCurrentDirectory(): string;
73
+ getCancellationToken?(): ts.CancellationToken;
74
+ getLocalizedDiagnosticMessages?: () => any;
75
+ getCompilationSettings(): ts.CompilerOptions;
76
+ getProjectReferences?(): readonly ts.ProjectReference[] | undefined;
65
77
  }
78
+ export {};
package/out/types.js CHANGED
@@ -11,7 +11,7 @@ var FileCapabilities;
11
11
  codeAction: true,
12
12
  inlayHint: true,
13
13
  };
14
- })(FileCapabilities = exports.FileCapabilities || (exports.FileCapabilities = {}));
14
+ })(FileCapabilities || (exports.FileCapabilities = FileCapabilities = {}));
15
15
  var FileRangeCapabilities;
16
16
  (function (FileRangeCapabilities) {
17
17
  FileRangeCapabilities.full = {
@@ -23,7 +23,7 @@ var FileRangeCapabilities;
23
23
  diagnostic: true,
24
24
  semanticTokens: true,
25
25
  };
26
- })(FileRangeCapabilities = exports.FileRangeCapabilities || (exports.FileRangeCapabilities = {}));
26
+ })(FileRangeCapabilities || (exports.FileRangeCapabilities = FileRangeCapabilities = {}));
27
27
  var MirrorBehaviorCapabilities;
28
28
  (function (MirrorBehaviorCapabilities) {
29
29
  MirrorBehaviorCapabilities.full = {
@@ -31,10 +31,10 @@ var MirrorBehaviorCapabilities;
31
31
  definition: true,
32
32
  rename: true,
33
33
  };
34
- })(MirrorBehaviorCapabilities = exports.MirrorBehaviorCapabilities || (exports.MirrorBehaviorCapabilities = {}));
34
+ })(MirrorBehaviorCapabilities || (exports.MirrorBehaviorCapabilities = MirrorBehaviorCapabilities = {}));
35
35
  var FileKind;
36
36
  (function (FileKind) {
37
37
  FileKind[FileKind["TextFile"] = 0] = "TextFile";
38
38
  FileKind[FileKind["TypeScriptHostFile"] = 1] = "TypeScriptHostFile";
39
- })(FileKind = exports.FileKind || (exports.FileKind = {}));
39
+ })(FileKind || (exports.FileKind = FileKind = {}));
40
40
  //# sourceMappingURL=types.js.map
@@ -17,8 +17,9 @@ export declare function createVirtualFiles(languages: Language[]): {
17
17
  getSource(fileName: string): Source | undefined;
18
18
  hasSource: (fileName: string) => boolean;
19
19
  getMirrorMap: (file: VirtualFile) => MirrorMap | undefined;
20
- getMaps: (virtualFile: VirtualFile) => [string, SourceMap<FileRangeCapabilities>][];
20
+ getMaps: (virtualFile: VirtualFile) => Map<string, [ts.IScriptSnapshot, SourceMap<FileRangeCapabilities>]>;
21
21
  hasVirtualFile(fileName: string): boolean;
22
22
  getVirtualFile(fileName: string): readonly [VirtualFile, Source] | readonly [undefined, undefined];
23
23
  };
24
+ export declare function updateVirtualFileMaps(virtualFile: VirtualFile, getSourceSnapshot: (source: string | undefined) => [string, ts.IScriptSnapshot] | undefined, map?: Map<string, [ts.IScriptSnapshot, SourceMap<FileRangeCapabilities>]>): Map<string, [ts.IScriptSnapshot, SourceMap<FileRangeCapabilities>]>;
24
25
  export declare function forEachEmbeddedFile(file: VirtualFile, cb: (embedded: VirtualFile) => void): void;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.forEachEmbeddedFile = exports.createVirtualFiles = void 0;
3
+ exports.forEachEmbeddedFile = exports.updateVirtualFileMaps = exports.createVirtualFiles = void 0;
4
4
  const source_map_1 = require("@volar/source-map");
5
5
  const sourceMaps_1 = require("./sourceMaps");
6
6
  function createVirtualFiles(languages) {
@@ -81,21 +81,17 @@ function createVirtualFiles(languages) {
81
81
  if (!virtualFileMaps.has(virtualFile.snapshot)) {
82
82
  virtualFileMaps.set(virtualFile.snapshot, new Map());
83
83
  }
84
- const map = virtualFileMaps.get(virtualFile.snapshot);
85
- const sources = new Set();
86
- const result = [];
87
- for (const mapping of virtualFile.mappings) {
88
- if (sources.has(mapping.source))
89
- continue;
90
- sources.add(mapping.source);
91
- const sourceFileName = mapping.source ?? getVirtualFileToSourceFileMap().get(normalizePath(virtualFile.fileName)).source.fileName;
92
- const sourceSnapshot = mapping.source ? sourceFiles.get(normalizePath(mapping.source)).snapshot : getVirtualFileToSourceFileMap().get(normalizePath(virtualFile.fileName)).source.snapshot;
93
- if (!map.has(sourceSnapshot)) {
94
- map.set(sourceSnapshot, [sourceFileName, new source_map_1.SourceMap(virtualFile.mappings.filter(mapping2 => mapping2.source === mapping.source))]);
84
+ updateVirtualFileMaps(virtualFile, sourceFileName => {
85
+ if (sourceFileName) {
86
+ const source = sourceFiles.get(normalizePath(sourceFileName));
87
+ return [sourceFileName, source.snapshot];
95
88
  }
96
- result.push(map.get(sourceSnapshot));
97
- }
98
- return result;
89
+ else {
90
+ const source = getVirtualFileToSourceFileMap().get(normalizePath(virtualFile.fileName)).source;
91
+ return [source.fileName, source.snapshot];
92
+ }
93
+ }, virtualFileMaps.get(virtualFile.snapshot));
94
+ return virtualFileMaps.get(virtualFile.snapshot);
99
95
  }
100
96
  function getMirrorMap(file) {
101
97
  if (!virtualFileToMirrorMap.has(file.snapshot)) {
@@ -105,6 +101,22 @@ function createVirtualFiles(languages) {
105
101
  }
106
102
  }
107
103
  exports.createVirtualFiles = createVirtualFiles;
104
+ function updateVirtualFileMaps(virtualFile, getSourceSnapshot, map = new Map()) {
105
+ const sources = new Set();
106
+ for (const mapping of virtualFile.mappings) {
107
+ if (sources.has(mapping.source))
108
+ continue;
109
+ sources.add(mapping.source);
110
+ const source = getSourceSnapshot(mapping.source);
111
+ if (!source)
112
+ continue;
113
+ if (!map.has(source[0]) || map.get(source[0])[0] !== source[1]) {
114
+ map.set(source[0], [source[1], new source_map_1.SourceMap(virtualFile.mappings.filter(mapping2 => mapping2.source === mapping.source))]);
115
+ }
116
+ }
117
+ return map;
118
+ }
119
+ exports.updateVirtualFileMaps = updateVirtualFileMaps;
108
120
  function forEachEmbeddedFile(file, cb) {
109
121
  cb(file);
110
122
  for (const embeddedFile of file.embeddedFiles) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@volar/language-core",
3
- "version": "1.6.8",
3
+ "version": "1.7.0",
4
4
  "main": "out/index.js",
5
5
  "license": "MIT",
6
6
  "files": [
@@ -13,7 +13,7 @@
13
13
  "directory": "packages/language-core"
14
14
  },
15
15
  "dependencies": {
16
- "@volar/source-map": "1.6.8"
16
+ "@volar/source-map": "1.7.0"
17
17
  },
18
- "gitHead": "3d269c7e69850ac5497469bede13f057db8a4980"
18
+ "gitHead": "38ec4f727b32dbf2cf3284ab02695e3a8effacc5"
19
19
  }