UNPKG

9.79 kBJavaScriptView Raw
1"use strict";
2var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3 if (k2 === undefined) k2 = k;
4 var desc = Object.getOwnPropertyDescriptor(m, k);
5 if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6 desc = { enumerable: true, get: function() { return m[k]; } };
7 }
8 Object.defineProperty(o, k2, desc);
9}) : (function(o, m, k, k2) {
10 if (k2 === undefined) k2 = k;
11 o[k2] = m[k];
12}));
13var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14 Object.defineProperty(o, "default", { enumerable: true, value: v });
15}) : function(o, v) {
16 o["default"] = v;
17});
18var __importStar = (this && this.__importStar) || function (mod) {
19 if (mod && mod.__esModule) return mod;
20 var result = {};
21 if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22 __setModuleDefault(result, mod);
23 return result;
24};
25var __importDefault = (this && this.__importDefault) || function (mod) {
26 return (mod && mod.__esModule) ? mod : { "default": mod };
27};
28Object.defineProperty(exports, "__esModule", { value: true });
29/* eslint-disable no-use-before-define */
30const fs_1 = __importDefault(require("fs"));
31const path_1 = __importDefault(require("path"));
32const typescript_1 = __importDefault(require("typescript"));
33const compilerOutRootFiles_1 = __importDefault(require("./compilerOutRootFiles"));
34const log_1 = __importDefault(require("./log"));
35const versionContainer_1 = __importStar(require("./versionContainer"));
36const formatHost = {
37 getCanonicalFileName: (path) => path,
38 getCurrentDirectory: typescript_1.default.sys.getCurrentDirectory,
39 getNewLine: () => typescript_1.default.sys.newLine,
40};
41function reportDiagnostic(diagnostic) {
42 var _a;
43 let linePointer = "";
44 if (diagnostic.file) {
45 const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start || 0);
46 linePointer = `in ${(_a = diagnostic.file) === null || _a === void 0 ? void 0 : _a.fileName} (${line + 1},${character + 1})`;
47 }
48 log_1.default.error(`TS${diagnostic.code}: ${linePointer}\n${typescript_1.default.flattenDiagnosticMessageText(diagnostic.messageText, formatHost.getNewLine())}`);
49}
50/** Clear Node cache for files in tmpFolder */
51function clearNodeCache(rootPath) {
52 Object.keys(require.cache).forEach((key) => {
53 var _a;
54 if ((_a = require.cache[key]) === null || _a === void 0 ? void 0 : _a.filename.startsWith(rootPath)) {
55 log_1.default.debug("delete node-cache for", key);
56 delete require.cache[key];
57 }
58 });
59}
60// https://github.com/microsoft/TypeScript/wiki/Using-the-Compiler-API#writing-an-incremental-program-watcher
61function compiler(entry, tsConfigFileName, extendCompilerOptions, onChanged) {
62 const tsVer = Number.parseFloat(typescript_1.default.versionMajorMinor);
63 if (tsVer < 2.7) {
64 throw new Error(`WebpackMockServer. Typescript version >=2.7 is expected. Current is ${typescript_1.default.versionMajorMinor}`);
65 }
66 log_1.default.debug(`typescript version: ${typescript_1.default.version}`);
67 const entries = entry && (Array.isArray(entry) ? entry : [entry]);
68 entries &&
69 entries.forEach((v) => {
70 if (typeof v !== "string") {
71 throw new Error(`WebpackMockServer. Option [entry]. Only 'string' is expected: ${v}`);
72 }
73 if (v.includes("*")) {
74 throw new Error(`WebpackMockServer. Option [entry]. Wildcard is not supported. Set 'Null' to [entry] and use tsConfig.json with 'files' and 'include' options instead.
75 More details here: https://github.com/Yegorich555/webpack-mock-server#options`);
76 }
77 });
78 // creating hooks
79 let isOutputChanged = true;
80 const outMockFiles = new compilerOutRootFiles_1.default();
81 const emptyWatcher = {
82 // eslint-disable-next-line @typescript-eslint/no-empty-function
83 close: () => { },
84 };
85 const sysConfig = Object.assign({}, typescript_1.default.sys);
86 sysConfig.watchFile = function watchFile(path) {
87 if (path.includes("node_modules")) {
88 return emptyWatcher;
89 }
90 // @ts-ignore
91 return typescript_1.default.sys.watchFile(...arguments);
92 };
93 sysConfig.watchDirectory = function watchDir(path) {
94 if (path.includes("node_modules")) {
95 return emptyWatcher;
96 }
97 // @ts-ignore
98 return typescript_1.default.sys.watchDirectory(...arguments);
99 };
100 // todo import alias doesn't work https://github.com/microsoft/TypeScript/issues/26722
101 function resolvePathAlias(filePath, path) {
102 var _a;
103 /* eslint-disable @typescript-eslint/no-use-before-define */
104 const isMatchAlias = definedTSOptions.pathsArr.some((v) => v[0] === filePath[0]);
105 if (isMatchAlias) {
106 const m = (_a = typescript_1.default.resolveModuleName(filePath, path, definedTSOptions, host)
107 .resolvedModule) === null || _a === void 0 ? void 0 : _a.resolvedFileName;
108 /* eslint-enable @typescript-eslint/no-use-before-define */
109 return m || filePath;
110 }
111 return filePath;
112 }
113 sysConfig.writeFile = function writeFile(path, data) {
114 log_1.default.debug("write", path);
115 isOutputChanged = true;
116 if (data) {
117 arguments[1] = data.replace(/require\(["']([^./\\][^\n\r]+)["']\)/g, (_str, mPath) =>
118 // prettier-ignore
119 `require(require.resolve("${resolvePathAlias(mPath, path)}", {paths:[process.cwd(), "${process.env.NODE_PATH || ''}"]} ))`);
120 }
121 // @ts-ignore
122 return typescript_1.default.sys.writeFile(...arguments);
123 };
124 sysConfig.readFile = function readFile(path) {
125 log_1.default.debug("read", path);
126 // @ts-ignore
127 const data = typescript_1.default.sys.readFile(...arguments);
128 if (!data && path === tsConfigFileName) {
129 log_1.default.debug(`file ${tsConfigFileName} is not found. Compilation with default settings...`);
130 return JSON.stringify({});
131 }
132 if (!data || path.includes("node_modules")) {
133 return data;
134 }
135 // this is required because under webpack 'path' is not absolute
136 const absolutePath = path_1.default.resolve(path);
137 return data
138 .replace(/(?<![/).])__dirname/g, `String.raw\`${path_1.default.dirname(absolutePath)}\``)
139 .replace(/(?<![/).])__filename/g, `String.raw\`${absolutePath}\``);
140 };
141 // eslint-disable-next-line no-param-reassign
142 // extendCompilerOptions.traceResolution = true;
143 const host = typescript_1.default.createWatchCompilerHost(tsConfigFileName, extendCompilerOptions, sysConfig, typescript_1.default.createEmitAndSemanticDiagnosticsBuilderProgram, reportDiagnostic, (diagnostic) => {
144 if (isOutputChanged && onChanged && diagnostic.code === 6194) {
145 clearNodeCache(extendCompilerOptions.outDir);
146 onChanged(outMockFiles.files);
147 isOutputChanged = false;
148 }
149 else {
150 log_1.default.debug(typescript_1.default.formatDiagnostic(diagnostic, formatHost));
151 }
152 });
153 let definedTSOptions;
154 const origCreateProgram = host.createProgram;
155 host.createProgram = function hookCreateProgram(tsRootNames, allOptions) {
156 const definedRootNames = entries && entries.length ? entries : tsRootNames;
157 arguments[0] = definedRootNames;
158 const tsOptions = allOptions;
159 // rewrite to resolve alias-paths relative to outDir
160 definedTSOptions = JSON.parse(JSON.stringify(tsOptions));
161 definedTSOptions.baseUrl = definedTSOptions.outDir;
162 definedTSOptions.pathsArr =
163 (definedTSOptions.paths && Object.keys(definedTSOptions.paths)) || [];
164 isOutputChanged = outMockFiles.update(definedRootNames, tsOptions.rootDir, tsOptions.outDir);
165 log_1.default.debug("defined root names", "", definedRootNames);
166 log_1.default.debug("TS options", "", tsOptions);
167 // @ts-ignore
168 return origCreateProgram(...arguments);
169 };
170 const program = typescript_1.default.createWatchProgram(host);
171 /*
172 * self-destroying
173 */
174 // clearing previous tmp-folder before exit
175 function clearTmpOutput() {
176 log_1.default.debug("clearing tmp folder ", extendCompilerOptions.outDir);
177 // recursive option is expiremental and supported in node >= v12.10.0: https://nodejs.org/api/fs.html#fs_fs_rmdir_path_options_callback
178 try {
179 fs_1.default.rmdirSync(extendCompilerOptions.outDir, {
180 recursive: true,
181 });
182 // eslint-disable-next-line no-empty
183 }
184 catch (ex) {
185 const nodeJsRequired = new versionContainer_1.default("12.10.0");
186 if (versionContainer_1.nodeJsVer > nodeJsRequired)
187 log_1.default.error("error in clearing tmp folder", ex);
188 }
189 }
190 // prevent double firing event
191 let closed = false;
192 function close() {
193 if (closed) {
194 return;
195 }
196 program && program.close();
197 clearTmpOutput();
198 closed = true;
199 }
200 const signals = ["SIGINT", "SIGTERM"];
201 signals.forEach((s) => {
202 process.on(s, () => {
203 close();
204 process.exit();
205 });
206 });
207}
208exports.default = compiler;