@esportsplus/typescript 0.28.4 → 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 -1
- package/build/compiler/coordinator.js +5 -18
- package/build/compiler/language-service.d.ts +12 -0
- package/build/compiler/language-service.js +83 -0
- package/build/compiler/plugins/vite.js +6 -8
- package/package.json +1 -1
- package/src/cli/tsc.ts +1 -0
- package/src/compiler/coordinator.ts +8 -26
- package/src/compiler/language-service.ts +135 -0
- package/src/compiler/plugins/vite.ts +8 -11
- 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,7 +6,7 @@ type CoordinatorResult = {
|
|
|
6
6
|
sourceFile: ts.SourceFile;
|
|
7
7
|
};
|
|
8
8
|
declare const _default: {
|
|
9
|
-
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) => {
|
|
10
10
|
changed: boolean;
|
|
11
11
|
code: string;
|
|
12
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];
|
|
@@ -43,20 +44,6 @@ function applyPrepend(code, file, prepend) {
|
|
|
43
44
|
}
|
|
44
45
|
return code.slice(0, position) + prepend.join('\n') + code.slice(position);
|
|
45
46
|
}
|
|
46
|
-
function createPatchedProgram(baseProgram, fileName, newContent) {
|
|
47
|
-
let baseHost = ts.createCompilerHost(baseProgram.getCompilerOptions()), options = baseProgram.getCompilerOptions();
|
|
48
|
-
return ts.createProgram(baseProgram.getRootFileNames(), options, {
|
|
49
|
-
...baseHost,
|
|
50
|
-
getSourceFile: (name, languageVersion) => {
|
|
51
|
-
if (name === fileName || name === fileName.replace(/\\/g, '/')) {
|
|
52
|
-
return ts.createSourceFile(name, newContent, languageVersion, true);
|
|
53
|
-
}
|
|
54
|
-
return baseProgram.getSourceFile(name) ?? baseHost.getSourceFile(name, languageVersion);
|
|
55
|
-
},
|
|
56
|
-
fileExists: (name) => baseHost.fileExists(name),
|
|
57
|
-
readFile: (name) => name === fileName ? newContent : baseHost.readFile(name)
|
|
58
|
-
}, baseProgram);
|
|
59
|
-
}
|
|
60
47
|
function hasPattern(code, patterns) {
|
|
61
48
|
for (let i = 0, n = patterns.length; i < n; i++) {
|
|
62
49
|
if (code.indexOf(patterns[i]) !== -1) {
|
|
@@ -125,11 +112,11 @@ function replaceReverse(code, replacements) {
|
|
|
125
112
|
}
|
|
126
113
|
return result;
|
|
127
114
|
}
|
|
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
|
}
|
|
@@ -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,12 +17,11 @@ export default ({ name, onWatchChange, plugins }) => {
|
|
|
18
17
|
return null;
|
|
19
18
|
}
|
|
20
19
|
try {
|
|
21
|
-
let
|
|
22
|
-
if (!sourceFile
|
|
23
|
-
sourceFile.getText().replace(LINE_ENDINGS_REGEX, '\n') !== code.replace(LINE_ENDINGS_REGEX, '\n')) {
|
|
20
|
+
let normalizedId = id.replace(DIRECTORY_SEPARATOR_REGEX, '/'), prog = languageService.update(root || '', normalizedId, code), sourceFile = prog.getSourceFile(normalizedId);
|
|
21
|
+
if (!sourceFile) {
|
|
24
22
|
sourceFile = ts.createSourceFile(id, code, ts.ScriptTarget.Latest, true);
|
|
25
23
|
}
|
|
26
|
-
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 || ''));
|
|
27
25
|
if (!result.changed) {
|
|
28
26
|
return null;
|
|
29
27
|
}
|
|
@@ -38,7 +36,7 @@ export default ({ name, onWatchChange, plugins }) => {
|
|
|
38
36
|
if (FILE_REGEX.test(id)) {
|
|
39
37
|
onWatchChange?.();
|
|
40
38
|
contexts.delete(root || '');
|
|
41
|
-
|
|
39
|
+
languageService.invalidate(root || '', id);
|
|
42
40
|
}
|
|
43
41
|
}
|
|
44
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 = {
|
|
@@ -73,28 +74,6 @@ function applyPrepend(code: string, file: ts.SourceFile, prepend: string[]): str
|
|
|
73
74
|
return code.slice(0, position) + prepend.join('\n') + code.slice(position);
|
|
74
75
|
}
|
|
75
76
|
|
|
76
|
-
function createPatchedProgram(baseProgram: ts.Program, fileName: string, newContent: string) {
|
|
77
|
-
let baseHost = ts.createCompilerHost(baseProgram.getCompilerOptions()),
|
|
78
|
-
options = baseProgram.getCompilerOptions();
|
|
79
|
-
|
|
80
|
-
return ts.createProgram(
|
|
81
|
-
baseProgram.getRootFileNames(),
|
|
82
|
-
options,
|
|
83
|
-
{
|
|
84
|
-
...baseHost,
|
|
85
|
-
getSourceFile: (name, languageVersion) => {
|
|
86
|
-
if (name === fileName || name === fileName.replace(/\\/g, '/')) {
|
|
87
|
-
return ts.createSourceFile(name, newContent, languageVersion, true);
|
|
88
|
-
}
|
|
89
|
-
return baseProgram.getSourceFile(name) ?? baseHost.getSourceFile(name, languageVersion);
|
|
90
|
-
},
|
|
91
|
-
fileExists: (name) => baseHost.fileExists(name),
|
|
92
|
-
readFile: (name) => name === fileName ? newContent : baseHost.readFile(name)
|
|
93
|
-
},
|
|
94
|
-
baseProgram
|
|
95
|
-
);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
77
|
function hasPattern(code: string, patterns: string[]): boolean {
|
|
99
78
|
for (let i = 0, n = patterns.length; i < n; i++) {
|
|
100
79
|
if (code.indexOf(patterns[i]) !== -1) {
|
|
@@ -190,11 +169,13 @@ function replaceReverse(code: string, replacements: Replacement[]): string {
|
|
|
190
169
|
return result;
|
|
191
170
|
}
|
|
192
171
|
|
|
172
|
+
|
|
193
173
|
const transform = (
|
|
194
174
|
plugins: Plugin[],
|
|
195
175
|
code: string,
|
|
196
176
|
file: ts.SourceFile,
|
|
197
177
|
program: ts.Program,
|
|
178
|
+
root: string,
|
|
198
179
|
shared: SharedContext
|
|
199
180
|
) => {
|
|
200
181
|
if (plugins.length === 0) {
|
|
@@ -205,7 +186,8 @@ const transform = (
|
|
|
205
186
|
currentCode = code,
|
|
206
187
|
currentFile = file,
|
|
207
188
|
currentProgram = program,
|
|
208
|
-
fileName = file.fileName
|
|
189
|
+
fileName = file.fileName,
|
|
190
|
+
last = plugins.length - 1;
|
|
209
191
|
|
|
210
192
|
for (let i = 0, n = plugins.length; i < n; i++) {
|
|
211
193
|
let plugin = plugins[i];
|
|
@@ -240,9 +222,9 @@ const transform = (
|
|
|
240
222
|
|
|
241
223
|
if (pluginChanged) {
|
|
242
224
|
changed = true;
|
|
243
|
-
|
|
244
|
-
if (i <
|
|
245
|
-
currentProgram =
|
|
225
|
+
|
|
226
|
+
if (i < last) {
|
|
227
|
+
currentProgram = languageService.update(root, fileName, currentCode);
|
|
246
228
|
currentFile = currentProgram.getSourceFile(fileName) ||
|
|
247
229
|
ts.createSourceFile(fileName, currentCode, file.languageVersion, true);
|
|
248
230
|
}
|
|
@@ -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>();
|
|
@@ -44,13 +42,11 @@ export default ({ name, onWatchChange, plugins }: VitePluginOptions) => {
|
|
|
44
42
|
}
|
|
45
43
|
|
|
46
44
|
try {
|
|
47
|
-
let
|
|
48
|
-
|
|
45
|
+
let normalizedId = id.replace(DIRECTORY_SEPARATOR_REGEX, '/'),
|
|
46
|
+
prog = languageService.update(root || '', normalizedId, code),
|
|
47
|
+
sourceFile = prog.getSourceFile(normalizedId);
|
|
49
48
|
|
|
50
|
-
if (
|
|
51
|
-
!sourceFile ||
|
|
52
|
-
sourceFile.getText().replace(LINE_ENDINGS_REGEX, '\n') !== code.replace(LINE_ENDINGS_REGEX, '\n')
|
|
53
|
-
) {
|
|
49
|
+
if (!sourceFile) {
|
|
54
50
|
sourceFile = ts.createSourceFile(id, code, ts.ScriptTarget.Latest, true);
|
|
55
51
|
}
|
|
56
52
|
|
|
@@ -59,6 +55,7 @@ export default ({ name, onWatchChange, plugins }: VitePluginOptions) => {
|
|
|
59
55
|
code,
|
|
60
56
|
sourceFile,
|
|
61
57
|
prog,
|
|
58
|
+
root || '',
|
|
62
59
|
contexts.get(root || '') ?? contexts.set(root || '', new Map()).get(root || '')!
|
|
63
60
|
);
|
|
64
61
|
|
|
@@ -77,7 +74,7 @@ export default ({ name, onWatchChange, plugins }: VitePluginOptions) => {
|
|
|
77
74
|
if (FILE_REGEX.test(id)) {
|
|
78
75
|
onWatchChange?.();
|
|
79
76
|
contexts.delete(root || '');
|
|
80
|
-
|
|
77
|
+
languageService.invalidate(root || '', id);
|
|
81
78
|
}
|
|
82
79
|
}
|
|
83
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 };
|