@esportsplus/typescript 0.28.5 → 0.29.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.
- package/build/cli/tsc.js +1 -1
- package/build/compiler/coordinator.d.ts +1 -2
- package/build/compiler/coordinator.js +6 -19
- package/build/compiler/language-service.d.ts +12 -0
- package/build/compiler/language-service.js +83 -0
- package/build/compiler/plugins/vite.js +6 -11
- package/package.json +1 -1
- package/src/cli/tsc.ts +1 -0
- package/src/compiler/coordinator.ts +8 -27
- package/src/compiler/language-service.ts +135 -0
- package/src/compiler/plugins/vite.ts +7 -14
- package/build/compiler/program.d.ts +0 -6
- package/build/compiler/program.js +0 -34
- package/src/compiler/program.ts +0 -55
package/build/cli/tsc.js
CHANGED
|
@@ -22,7 +22,7 @@ async function build(config, tsconfig, pluginConfigs) {
|
|
|
22
22
|
if (!sourceFile) {
|
|
23
23
|
continue;
|
|
24
24
|
}
|
|
25
|
-
let result = coordinator.transform(plugins, sourceFile.getFullText(), sourceFile, program, shared);
|
|
25
|
+
let result = coordinator.transform(plugins, sourceFile.getFullText(), sourceFile, program, root, shared);
|
|
26
26
|
if (result.changed) {
|
|
27
27
|
transformedFiles.set(normalizePath(fileName), result.code);
|
|
28
28
|
}
|
|
@@ -6,8 +6,7 @@ type CoordinatorResult = {
|
|
|
6
6
|
sourceFile: ts.SourceFile;
|
|
7
7
|
};
|
|
8
8
|
declare const _default: {
|
|
9
|
-
|
|
10
|
-
transform: (plugins: Plugin[], code: string, file: ts.SourceFile, program: ts.Program, shared: SharedContext) => {
|
|
9
|
+
transform: (plugins: Plugin[], code: string, file: ts.SourceFile, program: ts.Program, root: string, shared: SharedContext) => {
|
|
11
10
|
changed: boolean;
|
|
12
11
|
code: string;
|
|
13
12
|
sourceFile: ts.SourceFile;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ts } from '../index.js';
|
|
2
2
|
import imports from './imports.js';
|
|
3
|
+
import languageService from './language-service.js';
|
|
3
4
|
function applyImports(code, file, intents) {
|
|
4
5
|
for (let i = 0, n = intents.length; i < n; i++) {
|
|
5
6
|
let intent = intents[i];
|
|
@@ -111,25 +112,11 @@ function replaceReverse(code, replacements) {
|
|
|
111
112
|
}
|
|
112
113
|
return result;
|
|
113
114
|
}
|
|
114
|
-
const
|
|
115
|
-
let baseHost = ts.createCompilerHost(baseProgram.getCompilerOptions()), options = baseProgram.getCompilerOptions();
|
|
116
|
-
return ts.createProgram(baseProgram.getRootFileNames(), options, {
|
|
117
|
-
...baseHost,
|
|
118
|
-
getSourceFile: (name, languageVersion) => {
|
|
119
|
-
if (name === fileName || name === fileName.replace(/\\/g, '/')) {
|
|
120
|
-
return ts.createSourceFile(name, newContent, languageVersion, true);
|
|
121
|
-
}
|
|
122
|
-
return baseProgram.getSourceFile(name) ?? baseHost.getSourceFile(name, languageVersion);
|
|
123
|
-
},
|
|
124
|
-
fileExists: (name) => baseHost.fileExists(name),
|
|
125
|
-
readFile: (name) => name === fileName ? newContent : baseHost.readFile(name)
|
|
126
|
-
}, baseProgram);
|
|
127
|
-
};
|
|
128
|
-
const transform = (plugins, code, file, program, shared) => {
|
|
115
|
+
const transform = (plugins, code, file, program, root, shared) => {
|
|
129
116
|
if (plugins.length === 0) {
|
|
130
117
|
return { changed: false, code, sourceFile: file };
|
|
131
118
|
}
|
|
132
|
-
let changed = false, currentCode = code, currentFile = file, currentProgram = program, fileName = file.fileName;
|
|
119
|
+
let changed = false, currentCode = code, currentFile = file, currentProgram = program, fileName = file.fileName, last = plugins.length - 1;
|
|
133
120
|
for (let i = 0, n = plugins.length; i < n; i++) {
|
|
134
121
|
let plugin = plugins[i];
|
|
135
122
|
if (plugin.patterns && !hasPattern(currentCode, plugin.patterns)) {
|
|
@@ -156,8 +143,8 @@ const transform = (plugins, code, file, program, shared) => {
|
|
|
156
143
|
}
|
|
157
144
|
if (pluginChanged) {
|
|
158
145
|
changed = true;
|
|
159
|
-
if (i <
|
|
160
|
-
currentProgram =
|
|
146
|
+
if (i < last) {
|
|
147
|
+
currentProgram = languageService.update(root, fileName, currentCode);
|
|
161
148
|
currentFile = currentProgram.getSourceFile(fileName) ||
|
|
162
149
|
ts.createSourceFile(fileName, currentCode, file.languageVersion, true);
|
|
163
150
|
}
|
|
@@ -168,4 +155,4 @@ const transform = (plugins, code, file, program, shared) => {
|
|
|
168
155
|
}
|
|
169
156
|
return { changed, code: currentCode, sourceFile: currentFile };
|
|
170
157
|
};
|
|
171
|
-
export default {
|
|
158
|
+
export default { transform };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import ts from 'typescript';
|
|
2
|
+
declare const get: (root: string) => ts.Program;
|
|
3
|
+
declare const invalidate: (root: string, fileName: string) => void;
|
|
4
|
+
declare const update: (root: string, fileName: string, content: string) => ts.Program;
|
|
5
|
+
declare const _default: {
|
|
6
|
+
delete: (root: string) => void;
|
|
7
|
+
get: (root: string) => ts.Program;
|
|
8
|
+
invalidate: (root: string, fileName: string) => void;
|
|
9
|
+
update: (root: string, fileName: string, content: string) => ts.Program;
|
|
10
|
+
};
|
|
11
|
+
export default _default;
|
|
12
|
+
export { get, invalidate, update };
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import ts from 'typescript';
|
|
3
|
+
import { PACKAGE_NAME } from '../constants.js';
|
|
4
|
+
let cache = new Map();
|
|
5
|
+
function create(root) {
|
|
6
|
+
let tsconfig = ts.findConfigFile(root, ts.sys.fileExists, 'tsconfig.json');
|
|
7
|
+
if (!tsconfig) {
|
|
8
|
+
throw new Error(`${PACKAGE_NAME}: tsconfig.json not found`);
|
|
9
|
+
}
|
|
10
|
+
let file = ts.readConfigFile(tsconfig, ts.sys.readFile);
|
|
11
|
+
if (file.error) {
|
|
12
|
+
throw new Error(`${PACKAGE_NAME}: error reading tsconfig.json ${file.error.messageText}`);
|
|
13
|
+
}
|
|
14
|
+
let parsed = ts.parseJsonConfigFileContent(file.config, ts.sys, path.dirname(tsconfig));
|
|
15
|
+
if (parsed.errors.length > 0) {
|
|
16
|
+
throw new Error(`${PACKAGE_NAME}: error parsing tsconfig.json ${parsed.errors[0].messageText}`);
|
|
17
|
+
}
|
|
18
|
+
let contents = new Map(), rootFiles = new Set(parsed.fileNames.map(f => f.replace(/\\/g, '/'))), versions = new Map();
|
|
19
|
+
for (let fileName of rootFiles) {
|
|
20
|
+
versions.set(fileName, 0);
|
|
21
|
+
}
|
|
22
|
+
let host = {
|
|
23
|
+
fileExists: ts.sys.fileExists,
|
|
24
|
+
getCompilationSettings: () => parsed.options,
|
|
25
|
+
getCurrentDirectory: () => root,
|
|
26
|
+
getDefaultLibFileName: ts.getDefaultLibFilePath,
|
|
27
|
+
getScriptFileNames: () => [...rootFiles],
|
|
28
|
+
getScriptSnapshot: (fileName) => {
|
|
29
|
+
let content = contents.get(fileName);
|
|
30
|
+
if (content !== undefined) {
|
|
31
|
+
return ts.ScriptSnapshot.fromString(content);
|
|
32
|
+
}
|
|
33
|
+
if (!ts.sys.fileExists(fileName)) {
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
return ts.ScriptSnapshot.fromString(ts.sys.readFile(fileName) || '');
|
|
37
|
+
},
|
|
38
|
+
getScriptVersion: (fileName) => String(versions.get(fileName) || 0),
|
|
39
|
+
readFile: ts.sys.readFile
|
|
40
|
+
};
|
|
41
|
+
return { contents, host, rootFiles, service: ts.createLanguageService(host), versions };
|
|
42
|
+
}
|
|
43
|
+
function getEntry(root) {
|
|
44
|
+
let entry = cache.get(root);
|
|
45
|
+
if (!entry) {
|
|
46
|
+
entry = create(root);
|
|
47
|
+
cache.set(root, entry);
|
|
48
|
+
}
|
|
49
|
+
return entry;
|
|
50
|
+
}
|
|
51
|
+
const del = (root) => {
|
|
52
|
+
cache.delete(root);
|
|
53
|
+
};
|
|
54
|
+
const get = (root) => {
|
|
55
|
+
let entry = getEntry(root), program = entry.service.getProgram();
|
|
56
|
+
if (!program) {
|
|
57
|
+
throw new Error(`${PACKAGE_NAME}: failed to get program from language service`);
|
|
58
|
+
}
|
|
59
|
+
return program;
|
|
60
|
+
};
|
|
61
|
+
const invalidate = (root, fileName) => {
|
|
62
|
+
let entry = cache.get(root);
|
|
63
|
+
if (entry) {
|
|
64
|
+
let normalized = fileName.replace(/\\/g, '/');
|
|
65
|
+
entry.contents.delete(normalized);
|
|
66
|
+
entry.versions.set(normalized, (entry.versions.get(normalized) || 0) + 1);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
const update = (root, fileName, content) => {
|
|
70
|
+
let entry = getEntry(root), normalized = fileName.replace(/\\/g, '/');
|
|
71
|
+
if (!entry.rootFiles.has(normalized)) {
|
|
72
|
+
entry.rootFiles.add(normalized);
|
|
73
|
+
}
|
|
74
|
+
entry.contents.set(normalized, content);
|
|
75
|
+
entry.versions.set(normalized, (entry.versions.get(normalized) || 0) + 1);
|
|
76
|
+
let program = entry.service.getProgram();
|
|
77
|
+
if (!program) {
|
|
78
|
+
throw new Error(`${PACKAGE_NAME}: failed to get program from language service`);
|
|
79
|
+
}
|
|
80
|
+
return program;
|
|
81
|
+
};
|
|
82
|
+
export default { delete: del, get, invalidate, update };
|
|
83
|
+
export { get, invalidate, update };
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { ts } from '../../index.js';
|
|
2
2
|
import coordinator from '../coordinator.js';
|
|
3
|
-
import
|
|
4
|
-
const FILE_REGEX = /\.[tj]sx?$/;
|
|
3
|
+
import languageService from '../language-service.js';
|
|
5
4
|
const DIRECTORY_SEPARATOR_REGEX = /\\/g;
|
|
6
|
-
const
|
|
5
|
+
const FILE_REGEX = /\.[tj]sx?$/;
|
|
7
6
|
let contexts = new Map();
|
|
8
7
|
export default ({ name, onWatchChange, plugins }) => {
|
|
9
8
|
return ({ root } = {}) => {
|
|
@@ -18,15 +17,11 @@ export default ({ name, onWatchChange, plugins }) => {
|
|
|
18
17
|
return null;
|
|
19
18
|
}
|
|
20
19
|
try {
|
|
21
|
-
let normalizedId = id.replace(DIRECTORY_SEPARATOR_REGEX, '/'), prog =
|
|
22
|
-
if (sourceFile && sourceFile.getText().replace(LINE_ENDINGS_REGEX, '\n') !== code.replace(LINE_ENDINGS_REGEX, '\n')) {
|
|
23
|
-
sourceFile = undefined;
|
|
24
|
-
}
|
|
20
|
+
let normalizedId = id.replace(DIRECTORY_SEPARATOR_REGEX, '/'), prog = languageService.update(root || '', normalizedId, code), sourceFile = prog.getSourceFile(normalizedId);
|
|
25
21
|
if (!sourceFile) {
|
|
26
|
-
|
|
27
|
-
sourceFile = prog.getSourceFile(normalizedId) || ts.createSourceFile(id, code, ts.ScriptTarget.Latest, true);
|
|
22
|
+
sourceFile = ts.createSourceFile(id, code, ts.ScriptTarget.Latest, true);
|
|
28
23
|
}
|
|
29
|
-
let result = coordinator.transform(plugins, code, sourceFile, prog, contexts.get(root || '') ?? contexts.set(root || '', new Map()).get(root || ''));
|
|
24
|
+
let result = coordinator.transform(plugins, code, sourceFile, prog, root || '', contexts.get(root || '') ?? contexts.set(root || '', new Map()).get(root || ''));
|
|
30
25
|
if (!result.changed) {
|
|
31
26
|
return null;
|
|
32
27
|
}
|
|
@@ -41,7 +36,7 @@ export default ({ name, onWatchChange, plugins }) => {
|
|
|
41
36
|
if (FILE_REGEX.test(id)) {
|
|
42
37
|
onWatchChange?.();
|
|
43
38
|
contexts.delete(root || '');
|
|
44
|
-
|
|
39
|
+
languageService.invalidate(root || '', id);
|
|
45
40
|
}
|
|
46
41
|
}
|
|
47
42
|
};
|
package/package.json
CHANGED
package/src/cli/tsc.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ImportIntent, Plugin, Replacement, ReplacementIntent, SharedContext } from './types';
|
|
2
2
|
import { ts } from '~/index';
|
|
3
3
|
import imports, { ModifyOptions } from './imports';
|
|
4
|
+
import languageService from './language-service';
|
|
4
5
|
|
|
5
6
|
|
|
6
7
|
type CoordinatorResult = {
|
|
@@ -169,33 +170,12 @@ function replaceReverse(code: string, replacements: Replacement[]): string {
|
|
|
169
170
|
}
|
|
170
171
|
|
|
171
172
|
|
|
172
|
-
const createPatchedProgram = (baseProgram: ts.Program, fileName: string, newContent: string) => {
|
|
173
|
-
let baseHost = ts.createCompilerHost(baseProgram.getCompilerOptions()),
|
|
174
|
-
options = baseProgram.getCompilerOptions();
|
|
175
|
-
|
|
176
|
-
return ts.createProgram(
|
|
177
|
-
baseProgram.getRootFileNames(),
|
|
178
|
-
options,
|
|
179
|
-
{
|
|
180
|
-
...baseHost,
|
|
181
|
-
getSourceFile: (name, languageVersion) => {
|
|
182
|
-
if (name === fileName || name === fileName.replace(/\\/g, '/')) {
|
|
183
|
-
return ts.createSourceFile(name, newContent, languageVersion, true);
|
|
184
|
-
}
|
|
185
|
-
return baseProgram.getSourceFile(name) ?? baseHost.getSourceFile(name, languageVersion);
|
|
186
|
-
},
|
|
187
|
-
fileExists: (name) => baseHost.fileExists(name),
|
|
188
|
-
readFile: (name) => name === fileName ? newContent : baseHost.readFile(name)
|
|
189
|
-
},
|
|
190
|
-
baseProgram
|
|
191
|
-
);
|
|
192
|
-
};
|
|
193
|
-
|
|
194
173
|
const transform = (
|
|
195
174
|
plugins: Plugin[],
|
|
196
175
|
code: string,
|
|
197
176
|
file: ts.SourceFile,
|
|
198
177
|
program: ts.Program,
|
|
178
|
+
root: string,
|
|
199
179
|
shared: SharedContext
|
|
200
180
|
) => {
|
|
201
181
|
if (plugins.length === 0) {
|
|
@@ -206,7 +186,8 @@ const transform = (
|
|
|
206
186
|
currentCode = code,
|
|
207
187
|
currentFile = file,
|
|
208
188
|
currentProgram = program,
|
|
209
|
-
fileName = file.fileName
|
|
189
|
+
fileName = file.fileName,
|
|
190
|
+
last = plugins.length - 1;
|
|
210
191
|
|
|
211
192
|
for (let i = 0, n = plugins.length; i < n; i++) {
|
|
212
193
|
let plugin = plugins[i];
|
|
@@ -241,9 +222,9 @@ const transform = (
|
|
|
241
222
|
|
|
242
223
|
if (pluginChanged) {
|
|
243
224
|
changed = true;
|
|
244
|
-
|
|
245
|
-
if (i <
|
|
246
|
-
currentProgram =
|
|
225
|
+
|
|
226
|
+
if (i < last) {
|
|
227
|
+
currentProgram = languageService.update(root, fileName, currentCode);
|
|
247
228
|
currentFile = currentProgram.getSourceFile(fileName) ||
|
|
248
229
|
ts.createSourceFile(fileName, currentCode, file.languageVersion, true);
|
|
249
230
|
}
|
|
@@ -257,5 +238,5 @@ const transform = (
|
|
|
257
238
|
};
|
|
258
239
|
|
|
259
240
|
|
|
260
|
-
export default {
|
|
241
|
+
export default { transform };
|
|
261
242
|
export type { CoordinatorResult };
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import ts from 'typescript';
|
|
3
|
+
import { PACKAGE_NAME } from '~/constants';
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
type LanguageServiceEntry = {
|
|
7
|
+
contents: Map<string, string>;
|
|
8
|
+
host: ts.LanguageServiceHost;
|
|
9
|
+
rootFiles: Set<string>;
|
|
10
|
+
service: ts.LanguageService;
|
|
11
|
+
versions: Map<string, number>;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
let cache = new Map<string, LanguageServiceEntry>();
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
function create(root: string): LanguageServiceEntry {
|
|
19
|
+
let tsconfig = ts.findConfigFile(root, ts.sys.fileExists, 'tsconfig.json');
|
|
20
|
+
|
|
21
|
+
if (!tsconfig) {
|
|
22
|
+
throw new Error(`${PACKAGE_NAME}: tsconfig.json not found`);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
let file = ts.readConfigFile(tsconfig, ts.sys.readFile);
|
|
26
|
+
|
|
27
|
+
if (file.error) {
|
|
28
|
+
throw new Error(`${PACKAGE_NAME}: error reading tsconfig.json ${file.error.messageText}`);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
let parsed = ts.parseJsonConfigFileContent(
|
|
32
|
+
file.config,
|
|
33
|
+
ts.sys,
|
|
34
|
+
path.dirname(tsconfig)
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
if (parsed.errors.length > 0) {
|
|
38
|
+
throw new Error(`${PACKAGE_NAME}: error parsing tsconfig.json ${parsed.errors[0].messageText}`);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
let contents = new Map<string, string>(),
|
|
42
|
+
rootFiles = new Set(parsed.fileNames.map(f => f.replace(/\\/g, '/'))),
|
|
43
|
+
versions = new Map<string, number>();
|
|
44
|
+
|
|
45
|
+
for (let fileName of rootFiles) {
|
|
46
|
+
versions.set(fileName, 0);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
let host: ts.LanguageServiceHost = {
|
|
50
|
+
fileExists: ts.sys.fileExists,
|
|
51
|
+
getCompilationSettings: () => parsed.options,
|
|
52
|
+
getCurrentDirectory: () => root,
|
|
53
|
+
getDefaultLibFileName: ts.getDefaultLibFilePath,
|
|
54
|
+
getScriptFileNames: () => [...rootFiles],
|
|
55
|
+
getScriptSnapshot: (fileName: string) => {
|
|
56
|
+
let content = contents.get(fileName);
|
|
57
|
+
|
|
58
|
+
if (content !== undefined) {
|
|
59
|
+
return ts.ScriptSnapshot.fromString(content);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (!ts.sys.fileExists(fileName)) {
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return ts.ScriptSnapshot.fromString(ts.sys.readFile(fileName) || '');
|
|
67
|
+
},
|
|
68
|
+
getScriptVersion: (fileName: string) => String(versions.get(fileName) || 0),
|
|
69
|
+
readFile: ts.sys.readFile
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
return { contents, host, rootFiles, service: ts.createLanguageService(host), versions };
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function getEntry(root: string): LanguageServiceEntry {
|
|
76
|
+
let entry = cache.get(root);
|
|
77
|
+
|
|
78
|
+
if (!entry) {
|
|
79
|
+
entry = create(root);
|
|
80
|
+
cache.set(root, entry);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return entry;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
const del = (root: string): void => {
|
|
88
|
+
cache.delete(root);
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const get = (root: string): ts.Program => {
|
|
92
|
+
let entry = getEntry(root),
|
|
93
|
+
program = entry.service.getProgram();
|
|
94
|
+
|
|
95
|
+
if (!program) {
|
|
96
|
+
throw new Error(`${PACKAGE_NAME}: failed to get program from language service`);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return program;
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const invalidate = (root: string, fileName: string): void => {
|
|
103
|
+
let entry = cache.get(root);
|
|
104
|
+
|
|
105
|
+
if (entry) {
|
|
106
|
+
let normalized = fileName.replace(/\\/g, '/');
|
|
107
|
+
|
|
108
|
+
entry.contents.delete(normalized);
|
|
109
|
+
entry.versions.set(normalized, (entry.versions.get(normalized) || 0) + 1);
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const update = (root: string, fileName: string, content: string): ts.Program => {
|
|
114
|
+
let entry = getEntry(root),
|
|
115
|
+
normalized = fileName.replace(/\\/g, '/');
|
|
116
|
+
|
|
117
|
+
if (!entry.rootFiles.has(normalized)) {
|
|
118
|
+
entry.rootFiles.add(normalized);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
entry.contents.set(normalized, content);
|
|
122
|
+
entry.versions.set(normalized, (entry.versions.get(normalized) || 0) + 1);
|
|
123
|
+
|
|
124
|
+
let program = entry.service.getProgram();
|
|
125
|
+
|
|
126
|
+
if (!program) {
|
|
127
|
+
throw new Error(`${PACKAGE_NAME}: failed to get program from language service`);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return program;
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
export default { delete: del, get, invalidate, update };
|
|
135
|
+
export { get, invalidate, update };
|
|
@@ -2,7 +2,7 @@ import type { ResolvedConfig } from 'vite';
|
|
|
2
2
|
import type { Plugin, SharedContext } from '../types';
|
|
3
3
|
import { ts } from '~/index';
|
|
4
4
|
import coordinator from '../coordinator';
|
|
5
|
-
import
|
|
5
|
+
import languageService from '../language-service';
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
type VitePlugin = {
|
|
@@ -20,11 +20,9 @@ type VitePluginOptions = {
|
|
|
20
20
|
};
|
|
21
21
|
|
|
22
22
|
|
|
23
|
-
const FILE_REGEX = /\.[tj]sx?$/;
|
|
24
|
-
|
|
25
23
|
const DIRECTORY_SEPARATOR_REGEX = /\\/g;
|
|
26
24
|
|
|
27
|
-
const
|
|
25
|
+
const FILE_REGEX = /\.[tj]sx?$/;
|
|
28
26
|
|
|
29
27
|
|
|
30
28
|
let contexts = new Map<string, SharedContext>();
|
|
@@ -45,17 +43,11 @@ export default ({ name, onWatchChange, plugins }: VitePluginOptions) => {
|
|
|
45
43
|
|
|
46
44
|
try {
|
|
47
45
|
let normalizedId = id.replace(DIRECTORY_SEPARATOR_REGEX, '/'),
|
|
48
|
-
prog =
|
|
49
|
-
sourceFile = prog.getSourceFile(normalizedId)
|
|
50
|
-
|
|
51
|
-
// Check if file content matches (existing file may have changed)
|
|
52
|
-
if (sourceFile && sourceFile.getText().replace(LINE_ENDINGS_REGEX, '\n') !== code.replace(LINE_ENDINGS_REGEX, '\n')) {
|
|
53
|
-
sourceFile = undefined;
|
|
54
|
-
}
|
|
46
|
+
prog = languageService.update(root || '', normalizedId, code),
|
|
47
|
+
sourceFile = prog.getSourceFile(normalizedId);
|
|
55
48
|
|
|
56
49
|
if (!sourceFile) {
|
|
57
|
-
|
|
58
|
-
sourceFile = prog.getSourceFile(normalizedId) || ts.createSourceFile(id, code, ts.ScriptTarget.Latest, true);
|
|
50
|
+
sourceFile = ts.createSourceFile(id, code, ts.ScriptTarget.Latest, true);
|
|
59
51
|
}
|
|
60
52
|
|
|
61
53
|
let result = coordinator.transform(
|
|
@@ -63,6 +55,7 @@ export default ({ name, onWatchChange, plugins }: VitePluginOptions) => {
|
|
|
63
55
|
code,
|
|
64
56
|
sourceFile,
|
|
65
57
|
prog,
|
|
58
|
+
root || '',
|
|
66
59
|
contexts.get(root || '') ?? contexts.set(root || '', new Map()).get(root || '')!
|
|
67
60
|
);
|
|
68
61
|
|
|
@@ -81,7 +74,7 @@ export default ({ name, onWatchChange, plugins }: VitePluginOptions) => {
|
|
|
81
74
|
if (FILE_REGEX.test(id)) {
|
|
82
75
|
onWatchChange?.();
|
|
83
76
|
contexts.delete(root || '');
|
|
84
|
-
|
|
77
|
+
languageService.invalidate(root || '', id);
|
|
85
78
|
}
|
|
86
79
|
}
|
|
87
80
|
};
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import path from 'path';
|
|
2
|
-
import ts from 'typescript';
|
|
3
|
-
import { PACKAGE_NAME } from '../constants.js';
|
|
4
|
-
let cache = new Map();
|
|
5
|
-
function create(root) {
|
|
6
|
-
let tsconfig = ts.findConfigFile(root, ts.sys.fileExists, 'tsconfig.json');
|
|
7
|
-
if (!tsconfig) {
|
|
8
|
-
throw new Error('tsconfig.json not found');
|
|
9
|
-
}
|
|
10
|
-
let file = ts.readConfigFile(tsconfig, ts.sys.readFile);
|
|
11
|
-
if (file.error) {
|
|
12
|
-
throw new Error(`${PACKAGE_NAME}: error reading tsconfig.json ${file.error.messageText}`);
|
|
13
|
-
}
|
|
14
|
-
let parsed = ts.parseJsonConfigFileContent(file.config, ts.sys, path.dirname(tsconfig));
|
|
15
|
-
if (parsed.errors.length > 0) {
|
|
16
|
-
throw new Error(`${PACKAGE_NAME}: error parsing tsconfig.json ${parsed.errors[0].messageText}`);
|
|
17
|
-
}
|
|
18
|
-
return ts.createProgram({
|
|
19
|
-
options: parsed.options,
|
|
20
|
-
rootNames: parsed.fileNames
|
|
21
|
-
});
|
|
22
|
-
}
|
|
23
|
-
const get = (root) => {
|
|
24
|
-
let program = cache.get(root);
|
|
25
|
-
if (!program) {
|
|
26
|
-
program = create(root);
|
|
27
|
-
cache.set(root, program);
|
|
28
|
-
}
|
|
29
|
-
return program;
|
|
30
|
-
};
|
|
31
|
-
const del = (root) => {
|
|
32
|
-
cache.delete(root);
|
|
33
|
-
};
|
|
34
|
-
export default { get, delete: del };
|
package/src/compiler/program.ts
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import path from 'path';
|
|
2
|
-
import ts from 'typescript';
|
|
3
|
-
import { PACKAGE_NAME } from '~/constants';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
let cache = new Map<string, ts.Program>();
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
function create(root: string): ts.Program {
|
|
10
|
-
let tsconfig = ts.findConfigFile(root, ts.sys.fileExists, 'tsconfig.json');
|
|
11
|
-
|
|
12
|
-
if (!tsconfig) {
|
|
13
|
-
throw new Error('tsconfig.json not found');
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
let file = ts.readConfigFile(tsconfig, ts.sys.readFile);
|
|
17
|
-
|
|
18
|
-
if (file.error) {
|
|
19
|
-
throw new Error(`${PACKAGE_NAME}: error reading tsconfig.json ${file.error.messageText}`);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
let parsed = ts.parseJsonConfigFileContent(
|
|
23
|
-
file.config,
|
|
24
|
-
ts.sys,
|
|
25
|
-
path.dirname(tsconfig)
|
|
26
|
-
);
|
|
27
|
-
|
|
28
|
-
if (parsed.errors.length > 0) {
|
|
29
|
-
throw new Error(`${PACKAGE_NAME}: error parsing tsconfig.json ${parsed.errors[0].messageText}`);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
return ts.createProgram({
|
|
33
|
-
options: parsed.options,
|
|
34
|
-
rootNames: parsed.fileNames
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const get = (root: string): ts.Program => {
|
|
40
|
-
let program = cache.get(root);
|
|
41
|
-
|
|
42
|
-
if (!program) {
|
|
43
|
-
program = create(root);
|
|
44
|
-
cache.set(root, program);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
return program;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const del = (root: string): void => {
|
|
51
|
-
cache.delete(root);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
export default { get, delete: del };
|