@eventra_dev/eventra-cli 0.2.3 → 0.3.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.
Files changed (89) hide show
  1. package/README.md +154 -32
  2. package/dist/analysis/cache/evaluationCache.js +21 -0
  3. package/dist/analysis/cache/resolvedCallCache.js +21 -0
  4. package/dist/analysis/cache/resolvedExportCache.js +21 -0
  5. package/dist/analysis/cache/semanticDependencyGraph.js +25 -0
  6. package/dist/analysis/cache/symbolInvalidation.js +20 -0
  7. package/dist/analysis/extractor/extractor.js +47 -0
  8. package/dist/analysis/extractor/propagationExtractor.js +52 -0
  9. package/dist/analysis/pipeline/semanticPass.js +2 -0
  10. package/dist/analysis/resolver/callResolver.js +125 -0
  11. package/dist/analysis/resolver/exportResolver.js +75 -0
  12. package/dist/analysis/resolver/resolver.js +133 -0
  13. package/dist/analysis/scanner/analyzer/propagationAnalyzer.js +193 -0
  14. package/dist/analysis/scanner/analyzer/returnPropagationAnalyzer.js +105 -0
  15. package/dist/analysis/scanner/scanner.js +117 -0
  16. package/dist/analysis/scanner/sinkDetector.js +91 -0
  17. package/dist/analysis/shared/evaluationContext.js +9 -0
  18. package/dist/analysis/shared/propagation.js +3 -0
  19. package/dist/analysis/shared/returnPropagation.js +2 -0
  20. package/dist/analysis/shared/types.js +2 -0
  21. package/dist/analysis/shared/utils.js +62 -0
  22. package/dist/analysis/symbols/symbolUtils.js +68 -0
  23. package/dist/analysis/symbols/wrapperRegistry.js +55 -0
  24. package/dist/cli/check.js +73 -0
  25. package/dist/{commands → cli}/init.js +1 -1
  26. package/dist/{commands → cli}/send.js +1 -1
  27. package/dist/cli/sync.js +56 -0
  28. package/dist/{commands → cli}/watch.js +41 -25
  29. package/dist/compiler/compilerContext.js +204 -0
  30. package/dist/compiler/documentRegistry.js +78 -0
  31. package/dist/compiler/importGraph.js +83 -0
  32. package/dist/compiler/scheduler.js +29 -0
  33. package/dist/core/EventraEngine.js +234 -0
  34. package/dist/core/projectScanner.js +73 -0
  35. package/dist/{utils → filesystem}/getVirtualFile.js +1 -3
  36. package/dist/filesystem/processFile.js +38 -0
  37. package/dist/index.js +5 -5
  38. package/dist/shared/buildSyntheticTsx.js +20 -0
  39. package/dist/shared/templateExpressionExtractor.js +22 -0
  40. package/package.json +32 -9
  41. package/.github/workflows/release.yml +0 -43
  42. package/ARCHITECTURE.md +0 -88
  43. package/assets/eventra-icon-animated.svg +0 -19
  44. package/dist/commands/check.js +0 -78
  45. package/dist/commands/sync.js +0 -79
  46. package/dist/engine/boundary.js +0 -14
  47. package/dist/engine/callResolver.js +0 -58
  48. package/dist/engine/engine.js +0 -154
  49. package/dist/engine/exportResolver.js +0 -46
  50. package/dist/engine/functionAnalyzer.js +0 -71
  51. package/dist/engine/graph.js +0 -168
  52. package/dist/engine/languageService.js +0 -162
  53. package/dist/engine/resolver.js +0 -149
  54. package/dist/engine/scanner.js +0 -230
  55. package/dist/utils/processFile.js +0 -28
  56. package/dist/utils/universal.js +0 -190
  57. package/src/commands/check.ts +0 -91
  58. package/src/commands/init.ts +0 -174
  59. package/src/commands/send.ts +0 -213
  60. package/src/commands/sync.ts +0 -106
  61. package/src/commands/watch.ts +0 -144
  62. package/src/engine/boundary.ts +0 -12
  63. package/src/engine/callResolver.ts +0 -65
  64. package/src/engine/engine.ts +0 -227
  65. package/src/engine/exportResolver.ts +0 -56
  66. package/src/engine/functionAnalyzer.ts +0 -81
  67. package/src/engine/graph.ts +0 -193
  68. package/src/engine/hash.ts +0 -5
  69. package/src/engine/languageService.ts +0 -209
  70. package/src/engine/resolver.ts +0 -177
  71. package/src/engine/scanner.ts +0 -298
  72. package/src/index.ts +0 -49
  73. package/src/types.ts +0 -35
  74. package/src/utils/config.ts +0 -53
  75. package/src/utils/getVirtualFile.ts +0 -5
  76. package/src/utils/processFile.ts +0 -29
  77. package/src/utils/universal.ts +0 -249
  78. package/tests/fixtures/backend/express/app.ts +0 -233
  79. package/tests/fixtures/backend/nest/service.ts +0 -70
  80. package/tests/fixtures/backend/node/index.ts +0 -63
  81. package/tests/fixtures/frontend/next/page.tsx +0 -101
  82. package/tests/fixtures/frontend/react/App.tsx +0 -104
  83. package/tests/fixtures/frontend/vue/App.vue +0 -83
  84. package/tests/fixtures/wrappers/component/test.tsx +0 -62
  85. package/tests/fixtures/wrappers/function/test.ts +0 -60
  86. package/tests/run.ts +0 -106
  87. package/tsconfig.json +0 -14
  88. /package/dist/{utils → config}/config.js +0 -0
  89. /package/dist/{engine → shared}/hash.js +0 -0
@@ -1,154 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.EventraEngine = void 0;
7
- const path_1 = __importDefault(require("path"));
8
- const fs_1 = __importDefault(require("fs"));
9
- const languageService_1 = require("./languageService");
10
- const scanner_1 = require("./scanner");
11
- const graph_1 = require("./graph");
12
- const hash_1 = require("./hash");
13
- const boundary_1 = require("./boundary");
14
- class EventraEngine {
15
- ts;
16
- graph;
17
- wrapperCache = new Map();
18
- fileResults = new Map();
19
- fileHash = new Map();
20
- constructor(root) {
21
- this.ts = new languageService_1.TSService(root);
22
- const { baseUrl, paths } = this.ts.getModuleResolutionConfig();
23
- this.graph = new graph_1.DependencyGraph(baseUrl, paths);
24
- }
25
- normalize(file) {
26
- return path_1.default.resolve(file).replace(/\\/g, "/");
27
- }
28
- empty() {
29
- return {
30
- events: new Set(),
31
- detectedFunctionWrappers: new Set(),
32
- detectedComponentWrappers: new Map(),
33
- };
34
- }
35
- // PRELOAD
36
- preloadFile(file, content) {
37
- file = this.normalize(file);
38
- this.ts.updateFile(file, content);
39
- const source = this.ts.getSourceFile(file);
40
- if (source) {
41
- this.graph.update(file, source);
42
- }
43
- }
44
- // SCAN FILE (cached)
45
- scanFile(file, content, config) {
46
- file = this.normalize(file);
47
- const h = (0, hash_1.hash)(content);
48
- if (this.fileHash.get(file) === h) {
49
- return this.fileResults.get(file) ?? this.empty();
50
- }
51
- this.fileHash.set(file, h);
52
- this.ts.updateFile(file, content);
53
- const source = this.ts.getSourceFile(file);
54
- const checker = this.ts.getChecker();
55
- if (!source || !checker) {
56
- return this.empty();
57
- }
58
- this.graph.update(file, source);
59
- const res = (0, scanner_1.scanSource)(source, checker, config, new Set(), undefined, this.wrapperCache);
60
- this.fileResults.set(file, res);
61
- return res;
62
- }
63
- // UPDATE FILE (incremental)
64
- updateFile(file, content, config) {
65
- file = this.normalize(file);
66
- // EARLY EXIT
67
- if (this.fileHash.get(file) === (0, hash_1.hash)(content)) {
68
- return this.fileResults.get(file) ?? this.empty();
69
- }
70
- // invalidate wrapper cache
71
- this.wrapperCache.clear();
72
- const res = this.scanFile(file, content, config);
73
- const dependents = this.graph.getAllDependentsDeep(file);
74
- for (const dep of dependents) {
75
- const abs = this.normalize(dep);
76
- if (abs === file)
77
- continue; // self-skip
78
- if ((0, boundary_1.isExternalFile)(abs))
79
- continue;
80
- let depContent = this.ts.getFileContent(abs);
81
- if (!depContent) {
82
- try {
83
- depContent = fs_1.default.readFileSync(abs, "utf-8");
84
- }
85
- catch {
86
- continue;
87
- }
88
- }
89
- const h = (0, hash_1.hash)(depContent);
90
- if (this.fileHash.get(abs) === h) {
91
- continue;
92
- }
93
- this.fileHash.set(abs, h);
94
- this.ts.updateFile(abs, depContent);
95
- const source = this.ts.getSourceFile(abs);
96
- const checker = this.ts.getChecker();
97
- if (!source || !checker)
98
- continue;
99
- this.graph.update(abs, source);
100
- const r = (0, scanner_1.scanSource)(source, checker, config, new Set(), undefined, this.wrapperCache);
101
- this.fileResults.set(abs, r);
102
- }
103
- return res;
104
- }
105
- // GET ALL EVENTS
106
- getAllEvents() {
107
- const all = new Set();
108
- for (const r of this.fileResults.values()) {
109
- r.events.forEach(e => all.add(e));
110
- }
111
- return [...all];
112
- }
113
- // REMOVE FILE
114
- removeFile(file, config) {
115
- file = this.normalize(file);
116
- this.wrapperCache.clear();
117
- const dependents = this.graph.getAllDependentsDeep(file);
118
- this.graph.remove(file);
119
- this.ts.removeFile(file);
120
- this.fileResults.delete(file);
121
- this.fileHash.delete(file);
122
- for (const dep of dependents) {
123
- const abs = this.normalize(dep);
124
- if (abs === file)
125
- continue;
126
- if ((0, boundary_1.isExternalFile)(abs))
127
- continue;
128
- let content = this.ts.getFileContent(abs);
129
- if (!content) {
130
- try {
131
- content = fs_1.default.readFileSync(abs, "utf-8");
132
- }
133
- catch {
134
- continue;
135
- }
136
- }
137
- this.fileHash.delete(abs);
138
- this.ts.updateFile(abs, content);
139
- const source = this.ts.getSourceFile(abs);
140
- const checker = this.ts.getChecker();
141
- if (!source || !checker)
142
- continue;
143
- this.graph.update(abs, source);
144
- const r = (0, scanner_1.scanSource)(source, checker, config ?? {
145
- events: [],
146
- wrappers: [],
147
- functionWrappers: [],
148
- sync: { include: [], exclude: [] },
149
- }, new Set(), undefined, this.wrapperCache);
150
- this.fileResults.set(abs, r);
151
- }
152
- }
153
- }
154
- exports.EventraEngine = EventraEngine;
@@ -1,46 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.resolveExportedSymbol = resolveExportedSymbol;
7
- const typescript_1 = __importDefault(require("typescript"));
8
- function isRealDeclaration(node) {
9
- return (typescript_1.default.isFunctionDeclaration(node) ||
10
- typescript_1.default.isVariableDeclaration(node) ||
11
- typescript_1.default.isClassDeclaration(node));
12
- }
13
- function resolveExportedSymbol(symbol, checker, visited = new Set()) {
14
- if (visited.has(symbol))
15
- return null;
16
- visited.add(symbol);
17
- // unwrap alias
18
- if (symbol.flags & typescript_1.default.SymbolFlags.Alias) {
19
- const aliased = checker.getAliasedSymbol(symbol);
20
- return resolveExportedSymbol(aliased, checker, visited);
21
- }
22
- // export symbol
23
- const exportSymbol = checker.getExportSymbolOfSymbol(symbol);
24
- if (exportSymbol && exportSymbol !== symbol) {
25
- return resolveExportedSymbol(exportSymbol, checker, visited);
26
- }
27
- const decls = symbol.getDeclarations() ?? [];
28
- if (decls.some(isRealDeclaration)) {
29
- return symbol;
30
- }
31
- // exports (re-export)
32
- for (const decl of decls) {
33
- const source = decl.getSourceFile();
34
- const moduleSymbol = source.symbol;
35
- if (!moduleSymbol)
36
- continue;
37
- const exports = checker.getExportsOfModule(moduleSymbol);
38
- for (const exp of exports) {
39
- const resolved = resolveExportedSymbol(exp, checker, visited);
40
- if (resolved?.getDeclarations()?.length) {
41
- return resolved;
42
- }
43
- }
44
- }
45
- return symbol;
46
- }
@@ -1,71 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.findTrackParamIndex = findTrackParamIndex;
7
- const typescript_1 = __importDefault(require("typescript"));
8
- function findTrackParamIndex(fn) {
9
- const paramIndex = new Map();
10
- fn.parameters.forEach((p, i) => {
11
- if (typescript_1.default.isIdentifier(p.name)) {
12
- paramIndex.set(p.name.text, i);
13
- }
14
- });
15
- let result = null;
16
- function check(arg) {
17
- // identifier
18
- if (typescript_1.default.isIdentifier(arg)) {
19
- const idx = paramIndex.get(arg.text);
20
- if (idx !== undefined) {
21
- result = idx;
22
- return true;
23
- }
24
- }
25
- // template
26
- if (typescript_1.default.isTemplateExpression(arg)) {
27
- for (const span of arg.templateSpans) {
28
- if (typescript_1.default.isIdentifier(span.expression)) {
29
- const idx = paramIndex.get(span.expression.text);
30
- if (idx !== undefined) {
31
- result = idx;
32
- return true;
33
- }
34
- }
35
- }
36
- }
37
- // object { event: name }
38
- if (typescript_1.default.isObjectLiteralExpression(arg)) {
39
- for (const prop of arg.properties) {
40
- if (!typescript_1.default.isPropertyAssignment(prop))
41
- continue;
42
- const key = prop.name.getText();
43
- if (["event", "name", "type"].includes(key)) {
44
- return check(prop.initializer);
45
- }
46
- }
47
- }
48
- return false;
49
- }
50
- function visit(node) {
51
- if (result !== null)
52
- return;
53
- if (typescript_1.default.isCallExpression(node)) {
54
- const expr = node.expression;
55
- const isTrack = (typescript_1.default.isIdentifier(expr) && expr.text === "track") ||
56
- (typescript_1.default.isPropertyAccessExpression(expr) &&
57
- expr.name.text === "track");
58
- if (!isTrack)
59
- return;
60
- for (const arg of node.arguments) {
61
- if (check(arg))
62
- return;
63
- }
64
- }
65
- typescript_1.default.forEachChild(node, visit);
66
- }
67
- if (fn.body) {
68
- visit(fn.body);
69
- }
70
- return result;
71
- }
@@ -1,168 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.DependencyGraph = void 0;
7
- const typescript_1 = __importDefault(require("typescript"));
8
- const path_1 = __importDefault(require("path"));
9
- const fs_1 = __importDefault(require("fs"));
10
- class DependencyGraph {
11
- baseUrl;
12
- paths;
13
- reverse = new Map();
14
- exports = new Map();
15
- fileCache = new Map();
16
- constructor(baseUrl, paths) {
17
- this.baseUrl = baseUrl;
18
- this.paths = paths;
19
- }
20
- normalize(file) {
21
- return path_1.default.resolve(file).replace(/\\/g, "/");
22
- }
23
- // MODULE RESOLVE
24
- resolveModule(module, from) {
25
- // relative import
26
- if (module.startsWith(".")) {
27
- const abs = path_1.default.resolve(path_1.default.dirname(from), module);
28
- return this.resolveFile(abs);
29
- }
30
- // tsconfig paths
31
- for (const key in this.paths) {
32
- const pattern = key.replace(/\*/g, "(.*)");
33
- const regex = new RegExp("^" + pattern + "$");
34
- const match = module.match(regex);
35
- if (!match)
36
- continue;
37
- const wildcard = match.slice(1);
38
- for (const target of this.paths[key]) {
39
- let replaced = target;
40
- wildcard.forEach(w => {
41
- replaced = replaced.replace("*", w);
42
- });
43
- const abs = path_1.default.resolve(this.baseUrl, replaced);
44
- const resolved = this.resolveFile(abs);
45
- if (resolved)
46
- return resolved;
47
- }
48
- }
49
- // node resolution (safe)
50
- try {
51
- const resolved = require.resolve(module, {
52
- paths: [path_1.default.dirname(from)],
53
- });
54
- return this.normalize(resolved);
55
- }
56
- catch { }
57
- // fallback
58
- const abs = path_1.default.resolve(this.baseUrl, module);
59
- return this.resolveFile(abs);
60
- }
61
- // FILE RESOLVE
62
- resolveFile(base) {
63
- if (this.fileCache.has(base)) {
64
- return this.fileCache.get(base);
65
- }
66
- const tryFiles = [
67
- base,
68
- base + ".ts",
69
- base + ".tsx",
70
- base + ".js",
71
- base + ".jsx",
72
- base + ".mjs",
73
- base + ".cjs",
74
- base + ".d.ts",
75
- base + ".vue",
76
- base + ".svelte",
77
- base + ".astro",
78
- path_1.default.join(base, "index.ts"),
79
- path_1.default.join(base, "index.tsx"),
80
- path_1.default.join(base, "index.js"),
81
- ];
82
- for (const f of tryFiles) {
83
- if (fs_1.default.existsSync(f)) {
84
- const normalized = this.normalize(f);
85
- this.fileCache.set(base, normalized);
86
- return normalized;
87
- }
88
- }
89
- this.fileCache.set(base, null);
90
- return null;
91
- }
92
- // UPDATE GRAPH
93
- update(file, source) {
94
- const normalizedFile = this.normalize(file);
95
- for (const deps of this.reverse.values()) {
96
- deps.delete(normalizedFile);
97
- }
98
- this.exports.set(normalizedFile, new Set());
99
- for (const stmt of source.statements) {
100
- // IMPORT
101
- if (typescript_1.default.isImportDeclaration(stmt)) {
102
- // ignore import type
103
- if (stmt.importClause?.importKind === "type")
104
- continue;
105
- const module = stmt.moduleSpecifier
106
- .getText()
107
- .replace(/['"]/g, "");
108
- const resolved = this.resolveModule(module, normalizedFile);
109
- if (!resolved)
110
- continue;
111
- if (!this.reverse.has(resolved)) {
112
- this.reverse.set(resolved, new Set());
113
- }
114
- this.reverse.get(resolved).add(normalizedFile);
115
- }
116
- // EXPORT (re-export)
117
- if (typescript_1.default.isExportDeclaration(stmt)) {
118
- if (!stmt.moduleSpecifier)
119
- continue;
120
- const module = stmt.moduleSpecifier
121
- .getText()
122
- .replace(/['"]/g, "");
123
- const resolved = this.resolveModule(module, normalizedFile);
124
- if (!resolved)
125
- continue;
126
- this.exports.get(normalizedFile)?.add(resolved);
127
- if (!this.reverse.has(resolved)) {
128
- this.reverse.set(resolved, new Set());
129
- }
130
- this.reverse.get(resolved).add(normalizedFile);
131
- }
132
- }
133
- }
134
- // DEPENDENTS
135
- getAllDependentsDeep(file) {
136
- const start = this.normalize(file);
137
- const visited = new Set();
138
- const result = new Set();
139
- const walk = (f) => {
140
- if (visited.has(f))
141
- return;
142
- visited.add(f);
143
- const deps = this.reverse.get(f);
144
- deps?.forEach(d => {
145
- result.add(d);
146
- walk(d);
147
- });
148
- const ex = this.exports.get(f);
149
- ex?.forEach(e => walk(e));
150
- };
151
- walk(start);
152
- return [...result];
153
- }
154
- // REMOVE
155
- remove(file) {
156
- const normalized = this.normalize(file);
157
- this.reverse.delete(normalized);
158
- this.exports.delete(normalized);
159
- this.fileCache.delete(normalized);
160
- for (const set of this.reverse.values()) {
161
- set.delete(normalized);
162
- }
163
- for (const set of this.exports.values()) {
164
- set.delete(normalized);
165
- }
166
- }
167
- }
168
- exports.DependencyGraph = DependencyGraph;
@@ -1,162 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.TSService = void 0;
7
- const typescript_1 = __importDefault(require("typescript"));
8
- const fs_1 = __importDefault(require("fs"));
9
- const path_1 = __importDefault(require("path"));
10
- class TSService {
11
- root;
12
- files = new Map();
13
- fileNames = new Set();
14
- service;
15
- compilerOptions;
16
- baseUrl;
17
- paths;
18
- constructor(root) {
19
- this.root = root;
20
- const configPath = typescript_1.default.findConfigFile(root, typescript_1.default.sys.fileExists, "tsconfig.json");
21
- let compilerOptions = {
22
- allowJs: true,
23
- allowNonTsExtensions: true,
24
- jsx: typescript_1.default.JsxEmit.Preserve,
25
- jsxImportSource: "react",
26
- moduleResolution: typescript_1.default.ModuleResolutionKind.Node16,
27
- target: typescript_1.default.ScriptTarget.ESNext,
28
- esModuleInterop: true,
29
- allowSyntheticDefaultImports: true,
30
- skipLibCheck: true,
31
- };
32
- let baseUrl = root;
33
- let paths = {};
34
- if (configPath) {
35
- const configFile = typescript_1.default.readConfigFile(configPath, typescript_1.default.sys.readFile);
36
- const parsed = typescript_1.default.parseJsonConfigFileContent(configFile.config, typescript_1.default.sys, root);
37
- compilerOptions = {
38
- ...compilerOptions,
39
- ...parsed.options,
40
- };
41
- paths = parsed.options.paths || {};
42
- baseUrl = parsed.options.baseUrl
43
- ? path_1.default.resolve(root, parsed.options.baseUrl)
44
- : root;
45
- }
46
- this.compilerOptions = compilerOptions;
47
- this.baseUrl = baseUrl;
48
- this.paths = paths;
49
- const allFiles = typescript_1.default.sys.readDirectory(root, [
50
- ".ts",
51
- ".tsx",
52
- ".js",
53
- ".jsx",
54
- ".vue",
55
- ".svelte",
56
- ".astro"
57
- ], undefined, undefined);
58
- for (const f of allFiles) {
59
- this.fileNames.add(this.normalize(f));
60
- }
61
- const host = {
62
- getScriptFileNames: () => {
63
- return Array.from(this.fileNames);
64
- },
65
- getScriptVersion: (file) => {
66
- file = this.normalize(file);
67
- return this.files.get(file)?.version.toString() ?? "0";
68
- },
69
- getScriptKind: (fileName) => {
70
- fileName = this.normalize(fileName);
71
- if (fileName.endsWith(".tsx") ||
72
- fileName.endsWith(".vue") ||
73
- fileName.endsWith(".svelte") ||
74
- fileName.endsWith(".astro")) {
75
- return typescript_1.default.ScriptKind.TSX;
76
- }
77
- if (fileName.endsWith(".ts")) {
78
- return typescript_1.default.ScriptKind.TS;
79
- }
80
- if (fileName.endsWith(".jsx")) {
81
- return typescript_1.default.ScriptKind.JSX;
82
- }
83
- if (fileName.endsWith(".js")) {
84
- return typescript_1.default.ScriptKind.JS;
85
- }
86
- return typescript_1.default.ScriptKind.Unknown;
87
- },
88
- getScriptSnapshot: (file) => {
89
- file = this.normalize(file);
90
- const f = this.files.get(file);
91
- if (f) {
92
- return typescript_1.default.ScriptSnapshot.fromString(f.content);
93
- }
94
- try {
95
- if (fs_1.default.existsSync(file)) {
96
- const content = fs_1.default.readFileSync(file, "utf-8");
97
- this.files.set(file, {
98
- content,
99
- version: 1,
100
- });
101
- this.fileNames.add(file);
102
- return typescript_1.default.ScriptSnapshot.fromString(content);
103
- }
104
- }
105
- catch { }
106
- return typescript_1.default.ScriptSnapshot.fromString("");
107
- },
108
- getCurrentDirectory: () => this.root,
109
- getCompilationSettings: () => this.compilerOptions,
110
- getDefaultLibFileName: (opts) => typescript_1.default.getDefaultLibFilePath(opts),
111
- fileExists: (file) => {
112
- file = this.normalize(file);
113
- return this.files.has(file) || typescript_1.default.sys.fileExists(file);
114
- },
115
- readFile: (file) => {
116
- file = this.normalize(file);
117
- return this.files.get(file)?.content ?? typescript_1.default.sys.readFile(file);
118
- },
119
- readDirectory: typescript_1.default.sys.readDirectory,
120
- };
121
- this.service = typescript_1.default.createLanguageService(host);
122
- }
123
- normalize(file) {
124
- return path_1.default.resolve(file).replace(/\\/g, "/");
125
- }
126
- // PUBLIC API
127
- updateFile(file, content) {
128
- file = this.normalize(file);
129
- const prev = this.files.get(file);
130
- this.files.set(file, {
131
- content,
132
- version: prev ? prev.version + 1 : 1,
133
- });
134
- this.fileNames.add(file);
135
- }
136
- removeFile(file) {
137
- file = this.normalize(file);
138
- this.files.delete(file);
139
- this.fileNames.delete(file);
140
- }
141
- getProgram() {
142
- return this.service.getProgram();
143
- }
144
- getChecker() {
145
- return this.getProgram()?.getTypeChecker();
146
- }
147
- getSourceFile(file) {
148
- file = this.normalize(file);
149
- return this.getProgram()?.getSourceFile(file);
150
- }
151
- getFileContent(file) {
152
- file = this.normalize(file);
153
- return this.files.get(file)?.content;
154
- }
155
- getModuleResolutionConfig() {
156
- return {
157
- baseUrl: this.baseUrl,
158
- paths: this.paths,
159
- };
160
- }
161
- }
162
- exports.TSService = TSService;