@volar/language-core 1.6.9 → 1.7.1

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,257 +23,41 @@ 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 host.getTypeRootsVersion?.() + ':' + tsProjectVersion.toString();
65
- },
66
- getTypeRootsVersion: host.getTypeRootsVersion,
67
- getScriptFileNames,
68
- getScriptVersion,
69
- getScriptSnapshot,
70
- readDirectory: (_path, extensions, exclude, include, depth) => {
71
- const result = host.readDirectory?.(_path, extensions, exclude, include, depth) ?? [];
72
- for (const { fileName } of virtualFiles.allSources()) {
73
- const vuePath2 = path_1.posix.join(_path, path_1.posix.basename(fileName));
74
- if (path_1.posix.relative(_path.toLowerCase(), fileName.toLowerCase()).startsWith('..')) {
75
- continue;
76
- }
77
- if (!depth && fileName.toLowerCase() === vuePath2.toLowerCase()) {
78
- result.push(vuePath2);
79
- }
80
- else if (depth) {
81
- result.push(vuePath2); // TODO: depth num
82
- }
83
- }
84
- return result;
85
- },
86
- getScriptKind(fileName) {
87
- if (ts) {
88
- if (virtualFiles.hasSource(fileName))
89
- return ts.ScriptKind.Deferred;
90
- switch (path_1.posix.extname(fileName)) {
91
- case '.js': return ts.ScriptKind.JS;
92
- case '.jsx': return ts.ScriptKind.JSX;
93
- case '.ts': return ts.ScriptKind.TS;
94
- case '.tsx': return ts.ScriptKind.TSX;
95
- case '.json': return ts.ScriptKind.JSON;
96
- default: return ts.ScriptKind.Unknown;
97
- }
98
- }
99
- return 0;
100
- },
101
- };
102
27
  return {
103
- typescript: {
104
- languageServiceHost: new Proxy(_tsHost, {
105
- get: (target, property) => {
106
- update();
107
- return target[property] || host[property];
108
- },
109
- }),
110
- },
28
+ host,
111
29
  virtualFiles: new Proxy(virtualFiles, {
112
30
  get: (target, property) => {
113
- update();
31
+ syncVirtualFiles();
114
32
  return target[property];
115
33
  },
116
34
  }),
117
35
  };
118
- function update() {
119
- const newProjectVersion = host.getProjectVersion?.();
120
- const shouldUpdate = newProjectVersion === undefined || newProjectVersion !== lastProjectVersion;
121
- lastProjectVersion = newProjectVersion;
36
+ function syncVirtualFiles() {
37
+ const newProjectVersion = host.getProjectVersion();
38
+ const shouldUpdate = newProjectVersion !== lastProjectVersion;
122
39
  if (!shouldUpdate)
123
40
  return;
124
- let shouldUpdateTsProject = false;
125
- let virtualFilesUpdatedNum = 0;
41
+ lastProjectVersion = newProjectVersion;
126
42
  const remainRootFiles = new Set(host.getScriptFileNames());
127
- const oldVirtualTsFileNames = new Set();
128
- const newVirtualTsFileNames = new Set();
129
- for (const { root: rootVirtualFile } of virtualFiles.allSources()) {
130
- (0, virtualFiles_1.forEachEmbeddedFile)(rootVirtualFile, embedded => {
131
- if (embedded.kind === types_1.FileKind.TypeScriptHostFile) {
132
- oldVirtualTsFileNames.add(embedded.fileName);
133
- }
134
- });
135
- }
136
- // .vue
137
- for (const { fileName } of virtualFiles.allSources()) {
43
+ for (const { fileName, snapshot } of virtualFiles.allSources()) {
138
44
  remainRootFiles.delete(fileName);
139
- const snapshot = host.getScriptSnapshot(fileName);
140
- if (!snapshot) {
45
+ const newSnapshot = host.getScriptSnapshot(fileName);
46
+ if (!newSnapshot) {
141
47
  // delete
142
48
  virtualFiles.deleteSource(fileName);
143
- shouldUpdateTsProject = true;
144
- virtualFilesUpdatedNum++;
145
- continue;
146
49
  }
147
- const newVersion = host.getScriptVersion(fileName);
148
- if (sourceFileVersions.get(fileName) !== newVersion) {
50
+ else if (newSnapshot !== snapshot) {
149
51
  // update
150
- sourceFileVersions.set(fileName, newVersion);
151
- virtualFiles.updateSource(fileName, snapshot, host.getScriptLanguageId?.(fileName));
152
- virtualFilesUpdatedNum++;
52
+ virtualFiles.updateSource(fileName, newSnapshot, host.getLanguageId?.(fileName));
153
53
  }
154
54
  }
155
- // no any vue file version change, it mean project version was update by ts file change at this time
156
- if (!virtualFilesUpdatedNum) {
157
- shouldUpdateTsProject = true;
158
- }
159
- // add
55
+ // create
160
56
  for (const fileName of [...remainRootFiles]) {
161
57
  const snapshot = host.getScriptSnapshot(fileName);
162
58
  if (snapshot) {
163
- const virtualFile = virtualFiles.updateSource(fileName, snapshot, host.getScriptLanguageId?.(fileName));
164
- if (virtualFile) {
165
- remainRootFiles.delete(fileName);
166
- }
167
- }
168
- }
169
- // .ts / .js / .d.ts / .json ...
170
- for (const [oldTsFileName, oldTsFileVersion] of [...sourceTsFileVersions]) {
171
- const newVersion = host.getScriptVersion(oldTsFileName);
172
- if (oldTsFileVersion !== newVersion) {
173
- if (!remainRootFiles.has(oldTsFileName) && !host.getScriptSnapshot(oldTsFileName)) {
174
- // delete
175
- sourceTsFileVersions.delete(oldTsFileName);
176
- }
177
- else {
178
- // update
179
- sourceTsFileVersions.set(oldTsFileName, newVersion);
180
- }
181
- shouldUpdateTsProject = true;
182
- }
183
- }
184
- for (const nowFileName of remainRootFiles) {
185
- if (!sourceTsFileVersions.has(nowFileName)) {
186
- // add
187
- const newVersion = host.getScriptVersion(nowFileName);
188
- sourceTsFileVersions.set(nowFileName, newVersion);
189
- shouldUpdateTsProject = true;
190
- }
191
- }
192
- // check virtual file update
193
- if (!shouldUpdateTsProject) {
194
- for (const { root: rootVirtualFile } of virtualFiles.allSources()) {
195
- (0, virtualFiles_1.forEachEmbeddedFile)(rootVirtualFile, embedded => {
196
- if (embedded.kind === types_1.FileKind.TypeScriptHostFile) {
197
- newVirtualTsFileNames.add(embedded.fileName);
198
- if (virtualFileVersions.has(embedded.fileName) && virtualFileVersions.get(embedded.fileName)?.virtualFileSnapshot !== embedded.snapshot) {
199
- shouldUpdateTsProject = true;
200
- }
201
- }
202
- });
203
- }
204
- }
205
- // check virtual file create / delete
206
- if (!shouldUpdateTsProject) {
207
- if (oldVirtualTsFileNames.size !== newVirtualTsFileNames.size) {
208
- shouldUpdateTsProject = true;
209
- }
210
- else {
211
- for (const fileName of oldVirtualTsFileNames) {
212
- if (!newVirtualTsFileNames.has(fileName)) {
213
- shouldUpdateTsProject = true;
214
- break;
215
- }
216
- }
217
- }
218
- }
219
- if (shouldUpdateTsProject) {
220
- tsProjectVersion++;
221
- }
222
- }
223
- function getScriptFileNames() {
224
- const tsFileNames = new Set();
225
- for (const { root: rootVirtualFile } of virtualFiles.allSources()) {
226
- (0, virtualFiles_1.forEachEmbeddedFile)(rootVirtualFile, embedded => {
227
- if (embedded.kind === types_1.FileKind.TypeScriptHostFile) {
228
- tsFileNames.add(embedded.fileName); // virtual .ts
229
- }
230
- });
231
- }
232
- for (const fileName of host.getScriptFileNames()) {
233
- if (!virtualFiles.hasSource(fileName)) {
234
- tsFileNames.add(fileName); // .ts
235
- }
236
- }
237
- return [...tsFileNames];
238
- }
239
- function getScriptVersion(fileName) {
240
- let [virtualFile, source] = virtualFiles.getVirtualFile(fileName);
241
- if (virtualFile && source) {
242
- let version = virtualFileVersions.get(virtualFile.fileName);
243
- if (!version) {
244
- version = {
245
- value: 0,
246
- virtualFileSnapshot: virtualFile.snapshot,
247
- sourceFileSnapshot: source.snapshot,
248
- };
249
- virtualFileVersions.set(virtualFile.fileName, version);
250
- }
251
- else if (version.virtualFileSnapshot !== virtualFile.snapshot
252
- || (host.isTsc && version.sourceFileSnapshot !== source.snapshot) // fix https://github.com/johnsoncodehk/volar/issues/1082
253
- ) {
254
- version.value++;
255
- version.virtualFileSnapshot = virtualFile.snapshot;
256
- version.sourceFileSnapshot = source.snapshot;
59
+ virtualFiles.updateSource(fileName, snapshot, host.getLanguageId?.(fileName));
257
60
  }
258
- return version.value.toString();
259
- }
260
- return host.getScriptVersion(fileName);
261
- }
262
- function getScriptSnapshot(fileName) {
263
- const version = getScriptVersion(fileName);
264
- const cache = scriptSnapshots.get(fileName.toLowerCase());
265
- if (cache && cache[0] === version) {
266
- return cache[1];
267
- }
268
- const [virtualFile] = virtualFiles.getVirtualFile(fileName);
269
- if (virtualFile) {
270
- const snapshot = virtualFile.snapshot;
271
- scriptSnapshots.set(fileName.toLowerCase(), [version, snapshot]);
272
- return snapshot;
273
- }
274
- let tsScript = host.getScriptSnapshot(fileName);
275
- if (tsScript) {
276
- scriptSnapshots.set(fileName.toLowerCase(), [version, tsScript]);
277
- return tsScript;
278
61
  }
279
62
  }
280
63
  }
package/out/types.d.ts CHANGED
@@ -56,12 +56,22 @@ export interface VirtualFile {
56
56
  embeddedFiles: VirtualFile[];
57
57
  }
58
58
  export interface Language<T extends VirtualFile = VirtualFile> {
59
- resolveHost?(host: LanguageServiceHost): LanguageServiceHost;
59
+ resolveHost?(host: TypeScriptLanguageHost): TypeScriptLanguageHost;
60
60
  createVirtualFile(fileName: string, snapshot: ts.IScriptSnapshot, languageId: string | undefined): T | undefined;
61
61
  updateVirtualFile(virtualFile: T, snapshot: ts.IScriptSnapshot): void;
62
62
  deleteVirtualFile?(virtualFile: T): void;
63
63
  }
64
- export interface LanguageServiceHost extends ts.LanguageServiceHost {
65
- getScriptLanguageId?(fileName: string): string | undefined;
66
- 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;
67
69
  }
70
+ export interface TypeScriptLanguageHost extends LanguageHost {
71
+ getCurrentDirectory(): string;
72
+ getCancellationToken?(): ts.CancellationToken;
73
+ getLocalizedDiagnosticMessages?: () => any;
74
+ getCompilationSettings(): ts.CompilerOptions;
75
+ getProjectReferences?(): readonly ts.ProjectReference[] | undefined;
76
+ }
77
+ export {};
@@ -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.9",
3
+ "version": "1.7.1",
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.9"
16
+ "@volar/source-map": "1.7.1"
17
17
  },
18
- "gitHead": "e676fa08e4186bd2f8cc14861ef65f8d8c855ea1"
18
+ "gitHead": "6d092d684c65ce43af8a401bc90d0b2769a2bf49"
19
19
  }