mirror of https://github.com/ghostfolio/ghostfolio
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
972 lines
43 KiB
972 lines
43 KiB
"use strict";
|
|
var __webpack_require__ = {};
|
|
(()=>{
|
|
__webpack_require__.n = (module)=>{
|
|
var getter = module && module.__esModule ? ()=>module['default'] : ()=>module;
|
|
__webpack_require__.d(getter, {
|
|
a: getter
|
|
});
|
|
return getter;
|
|
};
|
|
})();
|
|
(()=>{
|
|
__webpack_require__.d = (exports1, definition)=>{
|
|
for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
|
|
enumerable: true,
|
|
get: definition[key]
|
|
});
|
|
};
|
|
})();
|
|
(()=>{
|
|
__webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
|
|
})();
|
|
(()=>{
|
|
__webpack_require__.r = (exports1)=>{
|
|
if ('undefined' != typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
|
|
value: 'Module'
|
|
});
|
|
Object.defineProperty(exports1, '__esModule', {
|
|
value: true
|
|
});
|
|
};
|
|
})();
|
|
var __webpack_exports__ = {};
|
|
__webpack_require__.r(__webpack_exports__);
|
|
__webpack_require__.d(__webpack_exports__, {
|
|
TsCheckerRspackPlugin: ()=>TsCheckerRspackPlugin
|
|
});
|
|
const external_node_path_namespaceObject = require("node:path");
|
|
var external_node_path_default = /*#__PURE__*/ __webpack_require__.n(external_node_path_namespaceObject);
|
|
function getInfrastructureLogger(compiler) {
|
|
const logger = compiler.getInfrastructureLogger('TsCheckerRspackPlugin');
|
|
return {
|
|
log: logger.log.bind(logger),
|
|
debug: logger.debug.bind(logger),
|
|
error: logger.error.bind(logger),
|
|
warn: logger.warn.bind(logger),
|
|
info: logger.info.bind(logger)
|
|
};
|
|
}
|
|
const addTrailingSep = (dir)=>dir.endsWith(external_node_path_namespaceObject.sep) ? dir : dir + external_node_path_namespaceObject.sep;
|
|
const isStrictSubdir = (parent, child)=>{
|
|
const parentDir = addTrailingSep(parent);
|
|
const childDir = addTrailingSep(child);
|
|
return parentDir !== childDir && childDir.startsWith(parentDir);
|
|
};
|
|
function excludeOutputPath(dependencies, compiler) {
|
|
const isContextIncluded = dependencies.dirs.includes(compiler.context);
|
|
if (!isContextIncluded) return dependencies;
|
|
const outputPath = 'string' == typeof compiler.options.output?.path ? compiler.options.output.path : compiler.outputPath;
|
|
if (!outputPath || !isStrictSubdir(compiler.context, outputPath) || dependencies.dirs.includes(outputPath)) return dependencies;
|
|
const excluded = new Set(dependencies.excluded);
|
|
excluded.add(outputPath);
|
|
return {
|
|
...dependencies,
|
|
excluded: Array.from(excluded)
|
|
};
|
|
}
|
|
function tapAfterCompileToAddDependencies(compiler, config, state) {
|
|
const { debug } = getInfrastructureLogger(compiler);
|
|
compiler.hooks.afterCompile.tapPromise('TsCheckerRspackPlugin', async (compilation)=>{
|
|
if (compilation.compiler !== compiler) return;
|
|
const dependencies = await state.dependenciesPromise;
|
|
debug("Got dependencies from the getDependenciesWorker.", dependencies);
|
|
if (dependencies) {
|
|
const sanitizedDependencies = excludeOutputPath(dependencies, compiler);
|
|
state.lastDependencies = sanitizedDependencies;
|
|
sanitizedDependencies.files.forEach((file)=>{
|
|
compilation.fileDependencies.add(file);
|
|
});
|
|
}
|
|
});
|
|
}
|
|
const external_chokidar_namespaceObject = require("chokidar");
|
|
var external_chokidar_default = /*#__PURE__*/ __webpack_require__.n(external_chokidar_namespaceObject);
|
|
const external_minimatch_namespaceObject = require("minimatch");
|
|
const external_is_glob_namespaceObject = require("is-glob");
|
|
var external_is_glob_default = /*#__PURE__*/ __webpack_require__.n(external_is_glob_namespaceObject);
|
|
const IGNORED_FILES = [
|
|
'package.json'
|
|
];
|
|
const isIgnoredFile = (file)=>IGNORED_FILES.some((ignoredFile)=>file.endsWith(`/${ignoredFile}`) || file.endsWith(`\\${ignoredFile}`));
|
|
const compilerFilesChangeMap = new WeakMap();
|
|
function getFilesChange(compiler) {
|
|
const { changedFiles = [], deletedFiles = [] } = compilerFilesChangeMap.get(compiler) || {
|
|
changedFiles: [],
|
|
deletedFiles: []
|
|
};
|
|
return {
|
|
changedFiles: changedFiles.filter((changedFile)=>!isIgnoredFile(changedFile)),
|
|
deletedFiles: deletedFiles.filter((deletedFile)=>!isIgnoredFile(deletedFile))
|
|
};
|
|
}
|
|
function consumeFilesChange(compiler) {
|
|
const change = getFilesChange(compiler);
|
|
clearFilesChange(compiler);
|
|
return change;
|
|
}
|
|
function updateFilesChange(compiler, change) {
|
|
compilerFilesChangeMap.set(compiler, aggregateFilesChanges([
|
|
getFilesChange(compiler),
|
|
change
|
|
]));
|
|
}
|
|
function clearFilesChange(compiler) {
|
|
compilerFilesChangeMap.delete(compiler);
|
|
}
|
|
function aggregateFilesChanges(changes) {
|
|
const changedFilesSet = new Set();
|
|
const deletedFilesSet = new Set();
|
|
for (const { changedFiles = [], deletedFiles = [] } of changes){
|
|
for (const changedFile of changedFiles){
|
|
changedFilesSet.add(changedFile);
|
|
deletedFilesSet.delete(changedFile);
|
|
}
|
|
for (const deletedFile of deletedFiles){
|
|
changedFilesSet.delete(deletedFile);
|
|
deletedFilesSet.add(deletedFile);
|
|
}
|
|
}
|
|
return {
|
|
changedFiles: Array.from(changedFilesSet),
|
|
deletedFiles: Array.from(deletedFilesSet)
|
|
};
|
|
}
|
|
function isInsideAnotherPath(parent, directory) {
|
|
const relativePart = (0, external_node_path_namespaceObject.relative)(parent, directory);
|
|
if (relativePart.startsWith('..')) return false;
|
|
if (0 === relativePart.length) return false;
|
|
if ((0, external_node_path_namespaceObject.isAbsolute)(relativePart)) return false;
|
|
return true;
|
|
}
|
|
function _define_property(obj, key, value) {
|
|
if (key in obj) Object.defineProperty(obj, key, {
|
|
value: value,
|
|
enumerable: true,
|
|
configurable: true,
|
|
writable: true
|
|
});
|
|
else obj[key] = value;
|
|
return obj;
|
|
}
|
|
const BUILTIN_IGNORED_DIRS = [
|
|
'.git'
|
|
];
|
|
function createIsIgnored(ignored, excluded) {
|
|
const ignoredPatterns = ignored ? Array.isArray(ignored) ? [
|
|
...ignored
|
|
] : [
|
|
ignored
|
|
] : [];
|
|
const filteredExcluded = excluded.filter((pattern)=>{
|
|
if (external_is_glob_default()(pattern)) {
|
|
const shouldAppendStar = pattern.includes('**') && !pattern.endsWith('*');
|
|
if (shouldAppendStar) ignoredPatterns.push(pattern.endsWith('/') ? `${pattern}**` : `${pattern}/**`);
|
|
else ignoredPatterns.push(pattern);
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
const ignoredFunctions = ignoredPatterns.map((pattern)=>{
|
|
if ('string' == typeof pattern) return (path)=>(0, external_minimatch_namespaceObject.minimatch)(path, pattern);
|
|
if (pattern instanceof RegExp) return (path)=>pattern.test(path);
|
|
return ()=>false;
|
|
});
|
|
ignoredFunctions.push((path)=>filteredExcluded.some((excludedPath)=>isInsideAnotherPath(excludedPath, path)));
|
|
ignoredFunctions.push((path)=>BUILTIN_IGNORED_DIRS.some((ignoredDir)=>path.includes(`/${ignoredDir}/`) || path.includes(`\\${ignoredDir}\\`)));
|
|
return function(path) {
|
|
return ignoredFunctions.some((ignoredFunction)=>ignoredFunction(path));
|
|
};
|
|
}
|
|
class InclusiveNodeWatchFileSystem {
|
|
get watcher() {
|
|
return this.watchFileSystem.watcher || this.watchFileSystem.wfs?.watcher;
|
|
}
|
|
constructor(watchFileSystem, compiler, pluginState){
|
|
_define_property(this, "watchFileSystem", void 0);
|
|
_define_property(this, "compiler", void 0);
|
|
_define_property(this, "pluginState", void 0);
|
|
_define_property(this, "dirsWatchers", void 0);
|
|
_define_property(this, "paused", void 0);
|
|
_define_property(this, "deletedFiles", void 0);
|
|
_define_property(this, "watch", void 0);
|
|
this.watchFileSystem = watchFileSystem;
|
|
this.compiler = compiler;
|
|
this.pluginState = pluginState;
|
|
this.paused = true;
|
|
this.watch = (files, dirs, missing, startTime, options, callback, callbackUndelayed)=>{
|
|
const { debug } = getInfrastructureLogger(this.compiler);
|
|
clearFilesChange(this.compiler);
|
|
const isIgnored = createIsIgnored(options?.ignored, this.pluginState.lastDependencies?.excluded || []);
|
|
const standardWatcher = this.watchFileSystem.watch(files, dirs, missing, startTime, options, callback, callbackUndelayed);
|
|
this.watcher?.on('change', (file)=>{
|
|
if ('string' != typeof file) return;
|
|
if (isIgnored(file)) debug("Detected file change but it's ignored", file);
|
|
else {
|
|
debug('Detected file change', file);
|
|
this.deletedFiles.delete(file);
|
|
updateFilesChange(this.compiler, {
|
|
changedFiles: [
|
|
file
|
|
]
|
|
});
|
|
}
|
|
});
|
|
this.watcher?.on('remove', (file)=>{
|
|
if ('string' != typeof file) return;
|
|
if (this.deletedFiles.has(file)) return void debug('Skipping duplicated remove event.');
|
|
if (isIgnored(file)) debug("Detected file remove but it's ignored", file);
|
|
else {
|
|
debug('Detected file remove', file);
|
|
this.deletedFiles.add(file);
|
|
updateFilesChange(this.compiler, {
|
|
deletedFiles: [
|
|
file
|
|
]
|
|
});
|
|
}
|
|
});
|
|
const prevDirs = Array.from(this.dirsWatchers.keys());
|
|
const nextDirs = Array.from(this.pluginState.lastDependencies?.dirs || []);
|
|
const dirsToUnwatch = prevDirs.filter((prevDir)=>!nextDirs.includes(prevDir));
|
|
const dirsToWatch = nextDirs.filter((nextDir)=>!prevDirs.includes(nextDir) && !isIgnored(nextDir));
|
|
dirsToUnwatch.forEach((dirToUnwatch)=>{
|
|
this.dirsWatchers.get(dirToUnwatch)?.close();
|
|
this.dirsWatchers.delete(dirToUnwatch);
|
|
});
|
|
dirsToWatch.forEach((dirToWatch)=>{
|
|
const interval = 'number' == typeof options?.poll ? options.poll : void 0;
|
|
const dirWatcher = external_chokidar_default().watch(dirToWatch, {
|
|
ignoreInitial: true,
|
|
ignorePermissionErrors: true,
|
|
ignored: (path)=>isIgnored(path),
|
|
usePolling: options?.poll ? true : void 0,
|
|
interval: interval,
|
|
binaryInterval: interval,
|
|
alwaysStat: true,
|
|
atomic: true,
|
|
awaitWriteFinish: true
|
|
});
|
|
dirWatcher.on('add', (file, stats)=>{
|
|
if (this.paused) return;
|
|
const extension = (0, external_node_path_namespaceObject.extname)(file);
|
|
const supportedExtensions = this.pluginState.lastDependencies?.extensions || [];
|
|
if (!supportedExtensions.includes(extension)) return void debug('Detected new file add but extension is not supported', file);
|
|
debug('Detected new file add', file);
|
|
this.deletedFiles.delete(file);
|
|
updateFilesChange(this.compiler, {
|
|
changedFiles: [
|
|
file
|
|
]
|
|
});
|
|
this.watcher?._onChange(file, stats?.mtimeMs || stats?.ctimeMs || 1, file, 'rename');
|
|
});
|
|
dirWatcher.on('unlink', (file)=>{
|
|
if (this.paused) return;
|
|
const extension = (0, external_node_path_namespaceObject.extname)(file);
|
|
const supportedExtensions = this.pluginState.lastDependencies?.extensions || [];
|
|
if (!supportedExtensions.includes(extension)) return void debug('Detected new file remove but extension is not supported', file);
|
|
if (this.deletedFiles.has(file)) return void debug('Skipping duplicated unlink event.');
|
|
debug('Detected new file remove', file);
|
|
this.deletedFiles.add(file);
|
|
updateFilesChange(this.compiler, {
|
|
deletedFiles: [
|
|
file
|
|
]
|
|
});
|
|
this.watcher?._onRemove(dirToWatch, file, 'rename');
|
|
});
|
|
this.dirsWatchers.set(dirToWatch, dirWatcher);
|
|
});
|
|
this.paused = false;
|
|
return {
|
|
...standardWatcher,
|
|
close: ()=>{
|
|
clearFilesChange(this.compiler);
|
|
if (standardWatcher) standardWatcher.close();
|
|
this.dirsWatchers.forEach((dirWatcher)=>{
|
|
dirWatcher?.close();
|
|
});
|
|
this.dirsWatchers.clear();
|
|
this.paused = true;
|
|
},
|
|
pause: ()=>{
|
|
if (standardWatcher) standardWatcher.pause();
|
|
this.paused = true;
|
|
}
|
|
};
|
|
};
|
|
this.dirsWatchers = new Map();
|
|
this.deletedFiles = new Set();
|
|
}
|
|
}
|
|
function tapAfterEnvironmentToPatchWatching(compiler, state) {
|
|
const { debug } = getInfrastructureLogger(compiler);
|
|
compiler.hooks.afterEnvironment.tap('TsCheckerRspackPlugin', ()=>{
|
|
const watchFileSystem = compiler.watchFileSystem;
|
|
if (watchFileSystem) {
|
|
debug("Overwriting Rspack's watch file system.");
|
|
compiler.watchFileSystem = new InclusiveNodeWatchFileSystem(watchFileSystem, compiler, state);
|
|
} else debug('No watch file system found - plugin may not work correctly.');
|
|
});
|
|
}
|
|
const external_picocolors_namespaceObject = require("picocolors");
|
|
var external_picocolors_default = /*#__PURE__*/ __webpack_require__.n(external_picocolors_namespaceObject);
|
|
const lite_tapable_namespaceObject = require("@rspack/lite-tapable");
|
|
const compilerHookMap = new WeakMap();
|
|
function createPluginHooks() {
|
|
return {
|
|
start: new lite_tapable_namespaceObject.AsyncSeriesWaterfallHook([
|
|
'change',
|
|
'compilation'
|
|
]),
|
|
waiting: new lite_tapable_namespaceObject.SyncHook([
|
|
'compilation'
|
|
]),
|
|
canceled: new lite_tapable_namespaceObject.SyncHook([
|
|
'compilation'
|
|
]),
|
|
error: new lite_tapable_namespaceObject.SyncHook([
|
|
'error',
|
|
'compilation'
|
|
]),
|
|
issues: new lite_tapable_namespaceObject.SyncWaterfallHook([
|
|
'issues',
|
|
'compilation'
|
|
])
|
|
};
|
|
}
|
|
function forwardPluginHooks(source, target) {
|
|
source.start.tapPromise('TsCheckerRspackPlugin', target.start.promise);
|
|
source.waiting.tap('TsCheckerRspackPlugin', target.waiting.call);
|
|
source.canceled.tap('TsCheckerRspackPlugin', target.canceled.call);
|
|
source.error.tap('TsCheckerRspackPlugin', target.error.call);
|
|
source.issues.tap('TsCheckerRspackPlugin', target.issues.call);
|
|
}
|
|
function getPluginHooks(compiler) {
|
|
let hooks = compilerHookMap.get(compiler);
|
|
if (void 0 === hooks) {
|
|
hooks = createPluginHooks();
|
|
compilerHookMap.set(compiler, hooks);
|
|
if ('compilers' in compiler) compiler.compilers.forEach((childCompiler)=>{
|
|
const childHooks = getPluginHooks(childCompiler);
|
|
if (hooks) forwardPluginHooks(childHooks, hooks);
|
|
});
|
|
}
|
|
return hooks;
|
|
}
|
|
const external_node_process_namespaceObject = require("node:process");
|
|
function createControlledPromise() {
|
|
let resolve = ()=>void 0;
|
|
let reject = ()=>void 0;
|
|
const promise = new Promise((aResolve, aReject)=>{
|
|
resolve = aResolve;
|
|
reject = aReject;
|
|
});
|
|
return {
|
|
promise,
|
|
resolve,
|
|
reject
|
|
};
|
|
}
|
|
function rpc_error_define_property(obj, key, value) {
|
|
if (key in obj) Object.defineProperty(obj, key, {
|
|
value: value,
|
|
enumerable: true,
|
|
configurable: true,
|
|
writable: true
|
|
});
|
|
else obj[key] = value;
|
|
return obj;
|
|
}
|
|
class RpcExitError extends Error {
|
|
constructor(message, code, signal){
|
|
super(message), rpc_error_define_property(this, "code", void 0), rpc_error_define_property(this, "signal", void 0), this.code = code, this.signal = signal;
|
|
this.name = 'RpcExitError';
|
|
}
|
|
}
|
|
function wrapRpc(childProcess) {
|
|
return async (...args)=>{
|
|
if (childProcess.send) {
|
|
if (!childProcess.connected) throw new Error(`Process ${childProcess.pid} doesn't have open IPC channels`);
|
|
} else throw new Error(`Process ${childProcess.pid} doesn't have IPC channels`);
|
|
const id = uuid();
|
|
const { promise: resultPromise, resolve: resolveResult, reject: rejectResult } = createControlledPromise();
|
|
const { promise: sendPromise, resolve: resolveSend, reject: rejectSend } = createControlledPromise();
|
|
const handleMessage = (message)=>{
|
|
if (message?.id === id) {
|
|
if ('resolve' === message.type) {
|
|
resolveResult(message.value);
|
|
removeHandlers();
|
|
} else if ('reject' === message.type) {
|
|
rejectResult(message.error);
|
|
removeHandlers();
|
|
}
|
|
}
|
|
};
|
|
const handleClose = (code, signal)=>{
|
|
rejectResult(new RpcExitError(code ? `Process ${childProcess.pid} exited with code ${code}` + (signal ? ` [${signal}]` : '') : `Process ${childProcess.pid} exited` + (signal ? ` [${signal}]` : ''), code, signal));
|
|
removeHandlers();
|
|
};
|
|
const removeHandlers = ()=>{
|
|
childProcess.off('message', handleMessage);
|
|
childProcess.off('close', handleClose);
|
|
};
|
|
childProcess.on('message', handleMessage);
|
|
childProcess.on('close', handleClose);
|
|
childProcess.send({
|
|
type: 'call',
|
|
id,
|
|
args
|
|
}, (error)=>{
|
|
if (error) {
|
|
rejectSend(error);
|
|
removeHandlers();
|
|
} else resolveSend(void 0);
|
|
});
|
|
return sendPromise.then(()=>resultPromise);
|
|
};
|
|
}
|
|
function uuid() {
|
|
return new Array(4).fill(0).map(()=>Math.floor(Math.random() * Number.MAX_SAFE_INTEGER).toString(16)).join('-');
|
|
}
|
|
const external_node_child_process_namespaceObject = require("node:child_process");
|
|
const WORKER_DATA_ENV_KEY = 'WORKER_DATA';
|
|
function createRpcWorker(modulePath, data, memoryLimit) {
|
|
const options = {
|
|
env: {
|
|
...external_node_process_namespaceObject.env,
|
|
[WORKER_DATA_ENV_KEY]: JSON.stringify(data || {})
|
|
},
|
|
stdio: [
|
|
'inherit',
|
|
'inherit',
|
|
'inherit',
|
|
'ipc'
|
|
],
|
|
serialization: 'advanced'
|
|
};
|
|
if (memoryLimit) options.execArgv = [
|
|
`--max-old-space-size=${memoryLimit}`
|
|
];
|
|
let childProcess;
|
|
let remoteMethod;
|
|
const worker = {
|
|
connect () {
|
|
if (childProcess && !childProcess.connected) {
|
|
childProcess.kill('SIGTERM');
|
|
childProcess = void 0;
|
|
remoteMethod = void 0;
|
|
}
|
|
if (!childProcess?.connected) {
|
|
childProcess = external_node_child_process_namespaceObject.fork(modulePath, options);
|
|
remoteMethod = wrapRpc(childProcess);
|
|
}
|
|
},
|
|
terminate () {
|
|
if (childProcess) {
|
|
childProcess.kill('SIGTERM');
|
|
childProcess = void 0;
|
|
remoteMethod = void 0;
|
|
}
|
|
},
|
|
get connected () {
|
|
return Boolean(childProcess?.connected);
|
|
},
|
|
get process () {
|
|
return childProcess;
|
|
}
|
|
};
|
|
return Object.assign((...args)=>{
|
|
if (!worker.connected) worker.connect();
|
|
if (!remoteMethod) return Promise.reject('Worker is not connected - cannot perform RPC.');
|
|
return remoteMethod(...args);
|
|
}, worker);
|
|
}
|
|
class AbortError extends Error {
|
|
static throwIfAborted(signal) {
|
|
if (signal?.aborted) throw new AbortError();
|
|
}
|
|
constructor(message = 'Task aborted.'){
|
|
super(message);
|
|
this.name = 'AbortError';
|
|
}
|
|
}
|
|
function tapErrorToLogMessage(compiler, config) {
|
|
const hooks = getPluginHooks(compiler);
|
|
hooks.error.tap('TsCheckerRspackPlugin', (error)=>{
|
|
if (error instanceof AbortError) return;
|
|
config.logger.error(String(error));
|
|
if (error instanceof RpcExitError) if ('SIGINT' === error.signal) config.logger.error(external_picocolors_default().red("[type-check] Issues checking service interrupted - If running in a docker container, this may be caused by the container running out of memory. If so, try increasing the container's memory limit or lowering the `memoryLimit` value in the TsCheckerRspackPlugin configuration."));
|
|
else config.logger.error(external_picocolors_default().red("[type-check] Issues checking service aborted - probably out of memory. Check the `memoryLimit` option in the TsCheckerRspackPlugin configuration.\nIf increasing the memory doesn't solve the issue, it's most probably a bug in the TypeScript."));
|
|
});
|
|
}
|
|
const external_node_os_namespaceObject = require("node:os");
|
|
var external_node_os_default = /*#__PURE__*/ __webpack_require__.n(external_node_os_namespaceObject);
|
|
function createPool(size) {
|
|
let pendingPromises = [];
|
|
const pool = {
|
|
async submit (task, signal) {
|
|
while(pendingPromises.length >= pool.size){
|
|
AbortError.throwIfAborted(signal);
|
|
await Promise.race(pendingPromises).catch(()=>void 0);
|
|
}
|
|
AbortError.throwIfAborted(signal);
|
|
const taskPromise = task(signal).finally(()=>{
|
|
pendingPromises = pendingPromises.filter((pendingPromise)=>pendingPromise !== taskPromise);
|
|
});
|
|
pendingPromises.push(taskPromise);
|
|
return taskPromise;
|
|
},
|
|
size,
|
|
get pending () {
|
|
return pendingPromises.length;
|
|
},
|
|
get drained () {
|
|
return new Promise(async (resolve)=>{
|
|
while(pendingPromises.length > 0)await Promise.race(pendingPromises).catch(()=>void 0);
|
|
resolve(void 0);
|
|
});
|
|
}
|
|
};
|
|
return pool;
|
|
}
|
|
const issuesPool = createPool(Math.max(1, external_node_os_namespaceObject.cpus().length));
|
|
const dependenciesPool = createPool(Math.max(1, external_node_os_namespaceObject.cpus().length));
|
|
function interceptDoneToGetDevServerTap(compiler, config, state) {
|
|
const { debug } = getInfrastructureLogger(compiler);
|
|
compiler.hooks.done.intercept({
|
|
register: (tap)=>{
|
|
if ([
|
|
'webpack-dev-server',
|
|
'rsbuild-dev-server'
|
|
].includes(tap.name) && 'sync' === tap.type && config.devServer) {
|
|
debug('Intercepting dev-server tap.');
|
|
state.DevServerDoneTap = tap;
|
|
}
|
|
return tap;
|
|
}
|
|
});
|
|
}
|
|
function forwardSlash(input) {
|
|
return external_node_path_default().normalize(input).replace(/\\+/g, '/');
|
|
}
|
|
function relativeToContext(file, context) {
|
|
let fileInContext = forwardSlash(external_node_path_default().relative(context, file));
|
|
if (!fileInContext.startsWith('../')) fileInContext = './' + fileInContext;
|
|
return fileInContext;
|
|
}
|
|
function formatIssueLocation(location) {
|
|
return `${location.start.line}:${location.start.column}`;
|
|
}
|
|
function issue_rspack_error_define_property(obj, key, value) {
|
|
if (key in obj) Object.defineProperty(obj, key, {
|
|
value: value,
|
|
enumerable: true,
|
|
configurable: true,
|
|
writable: true
|
|
});
|
|
else obj[key] = value;
|
|
return obj;
|
|
}
|
|
class IssueRspackError extends Error {
|
|
constructor(message, pathType, issue){
|
|
super(message), issue_rspack_error_define_property(this, "issue", void 0), issue_rspack_error_define_property(this, "hideStack", void 0), issue_rspack_error_define_property(this, "file", void 0), this.issue = issue, this.hideStack = true;
|
|
if (issue.file) {
|
|
this.file = 'absolute' === pathType ? forwardSlash(external_node_path_default().resolve(issue.file)) : relativeToContext(issue.file, process.cwd());
|
|
if (issue.location) this.file += `:${formatIssueLocation(issue.location)}`;
|
|
}
|
|
Error.captureStackTrace(this, this.constructor);
|
|
}
|
|
}
|
|
function tapAfterCompileToGetIssues(compiler, config, state) {
|
|
const hooks = getPluginHooks(compiler);
|
|
const { debug } = getInfrastructureLogger(compiler);
|
|
compiler.hooks.afterCompile.tapPromise('TsCheckerRspackPlugin', async (compilation)=>{
|
|
if (compilation.compiler !== compiler) return;
|
|
let issues = [];
|
|
try {
|
|
issues = await state.issuesPromise;
|
|
} catch (error) {
|
|
hooks.error.call(error, compilation);
|
|
return;
|
|
}
|
|
debug('Got issues from getIssuesWorker.', issues?.length);
|
|
if (!issues) return;
|
|
issues = issues.filter(config.issue.predicate);
|
|
issues = hooks.issues.call(issues, compilation);
|
|
issues.forEach((issue)=>{
|
|
const error = new IssueRspackError(config.formatter.format(issue), config.formatter.pathType, issue);
|
|
if ('warning' === issue.severity) compilation.warnings.push(error);
|
|
else compilation.errors.push(error);
|
|
});
|
|
});
|
|
}
|
|
function statsFormatter(issues, stats) {
|
|
const errorsNumber = issues.filter((issue)=>'error' === issue.severity).length;
|
|
const warningsNumber = issues.filter((issue)=>'warning' === issue.severity).length;
|
|
const errorsFormatted = errorsNumber ? external_picocolors_default().bold(external_picocolors_default().red(`${errorsNumber} ${1 === errorsNumber ? 'error' : 'errors'}`)) : '';
|
|
const warningsFormatted = warningsNumber ? external_picocolors_default().bold(external_picocolors_default().yellow(`${warningsNumber} ${1 === warningsNumber ? 'warning' : 'warnings'}`)) : '';
|
|
const timeFormatted = stats.startTime ? Math.round(Date.now() - stats.startTime) : 0;
|
|
if (!errorsFormatted && !warningsFormatted) return external_picocolors_default().green(`[type-check] no errors found in ${timeFormatted} ms`);
|
|
return [
|
|
'[type-check] found ',
|
|
errorsFormatted,
|
|
errorsFormatted && warningsFormatted ? ' and ' : '',
|
|
warningsFormatted,
|
|
timeFormatted ? ` in ${timeFormatted} ms` : ''
|
|
].join('');
|
|
}
|
|
function createRspackFormatter(formatter, pathType) {
|
|
return function(issue) {
|
|
const color = 'warning' === issue.severity ? external_picocolors_default().yellow : external_picocolors_default().red;
|
|
const severity = issue.severity.toUpperCase();
|
|
if (!issue.file) return [
|
|
`${external_picocolors_default().bold(color(severity))} in ` + formatter(issue),
|
|
''
|
|
].join(external_node_os_default().EOL);
|
|
{
|
|
let location = external_picocolors_default().bold('absolute' === pathType ? forwardSlash(external_node_path_default().resolve(issue.file)) : relativeToContext(issue.file, process.cwd()));
|
|
if (issue.location) location += `:${external_picocolors_default().bold(external_picocolors_default().green(formatIssueLocation(issue.location)))}`;
|
|
return [
|
|
`${external_picocolors_default().bold(color(severity))} in ${location}`,
|
|
formatter(issue),
|
|
''
|
|
].join(external_node_os_default().EOL);
|
|
}
|
|
};
|
|
}
|
|
function isPending(promise, timeout = 100) {
|
|
return Promise.race([
|
|
promise.then(()=>false).catch(()=>false),
|
|
new Promise((resolve)=>setTimeout(()=>resolve(true), timeout))
|
|
]);
|
|
}
|
|
function wait(timeout) {
|
|
return new Promise((resolve)=>setTimeout(resolve, timeout));
|
|
}
|
|
function tapDoneToAsyncGetIssues(compiler, config, state) {
|
|
const hooks = getPluginHooks(compiler);
|
|
const { debug } = getInfrastructureLogger(compiler);
|
|
compiler.hooks.done.tap('TsCheckerRspackPlugin', async (stats)=>{
|
|
if (stats.compilation.compiler !== compiler) return;
|
|
const issuesPromise = state.issuesPromise;
|
|
let issues;
|
|
try {
|
|
if (await isPending(issuesPromise)) {
|
|
hooks.waiting.call(stats.compilation);
|
|
config.logger.log(external_picocolors_default().cyan('[type-check] in progress...'));
|
|
} else await wait(10);
|
|
issues = await issuesPromise;
|
|
} catch (error) {
|
|
hooks.error.call(error, stats.compilation);
|
|
return;
|
|
}
|
|
if (!issues || state.issuesPromise !== issuesPromise) return;
|
|
debug(`Got ${issues?.length || 0} issues from getIssuesWorker.`);
|
|
issues = issues.filter(config.issue.predicate);
|
|
issues = hooks.issues.call(issues, stats.compilation);
|
|
const formatter = createRspackFormatter(config.formatter.format, config.formatter.pathType);
|
|
if (issues.length) config.logger.error(issues.map((issue)=>formatter(issue)).join('\n'));
|
|
config.logger.log(statsFormatter(issues, stats));
|
|
if (issues.length && state.DevServerDoneTap) {
|
|
issues.forEach((issue)=>{
|
|
const error = new IssueRspackError(config.formatter.format(issue), config.formatter.pathType, issue);
|
|
if ('warning' === issue.severity) stats.compilation.warnings.push(error);
|
|
else stats.compilation.errors.push(error);
|
|
});
|
|
debug('Sending issues to the dev-server.');
|
|
state.DevServerDoneTap.fn(stats);
|
|
}
|
|
});
|
|
}
|
|
function tapStartToRunWorkers(compiler, getIssuesWorker, getDependenciesWorker, config, state) {
|
|
const hooks = getPluginHooks(compiler);
|
|
const { log, debug } = getInfrastructureLogger(compiler);
|
|
compiler.hooks.run.tap('TsCheckerRspackPlugin', ()=>{
|
|
if (!state.initialized) {
|
|
debug('Initializing plugin for single run (not async).');
|
|
state.initialized = true;
|
|
state.watching = false;
|
|
tapAfterCompileToGetIssues(compiler, config, state);
|
|
}
|
|
});
|
|
compiler.hooks.watchRun.tap('TsCheckerRspackPlugin', async ()=>{
|
|
if (!state.initialized) {
|
|
state.initialized = true;
|
|
state.watching = true;
|
|
if (config.async) {
|
|
debug('Initializing plugin for watch run (async).');
|
|
tapDoneToAsyncGetIssues(compiler, config, state);
|
|
interceptDoneToGetDevServerTap(compiler, config, state);
|
|
} else {
|
|
debug('Initializing plugin for watch run (not async).');
|
|
tapAfterCompileToGetIssues(compiler, config, state);
|
|
}
|
|
}
|
|
});
|
|
compiler.hooks.compilation.tap('TsCheckerRspackPlugin', async (compilation)=>{
|
|
if (compilation.compiler !== compiler) return;
|
|
const iteration = ++state.iteration;
|
|
if (state.abortController) {
|
|
debug(`Aborting iteration ${iteration - 1}.`);
|
|
state.abortController.abort();
|
|
}
|
|
const abortController = new AbortController();
|
|
state.abortController = abortController;
|
|
let filesChange = {};
|
|
if (state.watching) {
|
|
filesChange = consumeFilesChange(compiler);
|
|
log([
|
|
'Calling reporter service for incremental check.',
|
|
` Changed files: ${JSON.stringify(filesChange.changedFiles)}`,
|
|
` Deleted files: ${JSON.stringify(filesChange.deletedFiles)}`
|
|
].join('\n'));
|
|
} else log('Calling reporter service for single check.');
|
|
filesChange = await hooks.start.promise(filesChange, compilation);
|
|
let aggregatedFilesChange = filesChange;
|
|
if (state.aggregatedFilesChange) {
|
|
aggregatedFilesChange = aggregateFilesChanges([
|
|
aggregatedFilesChange,
|
|
filesChange
|
|
]);
|
|
debug([
|
|
`Aggregating with previous files change, iteration ${iteration}.`,
|
|
` Changed files: ${JSON.stringify(aggregatedFilesChange.changedFiles)}`,
|
|
` Deleted files: ${JSON.stringify(aggregatedFilesChange.deletedFiles)}`
|
|
].join('\n'));
|
|
}
|
|
state.aggregatedFilesChange = aggregatedFilesChange;
|
|
state.issuesPromise = (state.issuesPromise || Promise.resolve()).catch(()=>void 0).then(()=>{
|
|
if (abortController.signal.aborted) return;
|
|
debug(`Submitting the getIssuesWorker to the pool, iteration ${iteration}.`);
|
|
return issuesPool.submit(async ()=>{
|
|
try {
|
|
debug(`Running the getIssuesWorker, iteration ${iteration}.`);
|
|
const issues = await getIssuesWorker(aggregatedFilesChange, state.watching, config.issue.defaultSeverity);
|
|
if (state.aggregatedFilesChange === aggregatedFilesChange) state.aggregatedFilesChange = void 0;
|
|
if (state.abortController === abortController) state.abortController = void 0;
|
|
return issues;
|
|
} catch (error) {
|
|
hooks.error.call(error, compilation);
|
|
return;
|
|
} finally{
|
|
debug(`The getIssuesWorker finished its job, iteration ${iteration}.`);
|
|
}
|
|
}, abortController.signal);
|
|
});
|
|
debug(`Submitting the getDependenciesWorker to the pool, iteration ${iteration}.`);
|
|
state.dependenciesPromise = dependenciesPool.submit(async ()=>{
|
|
try {
|
|
debug(`Running the getDependenciesWorker, iteration ${iteration}.`);
|
|
return await getDependenciesWorker(filesChange);
|
|
} catch (error) {
|
|
hooks.error.call(error, compilation);
|
|
return;
|
|
} finally{
|
|
debug(`The getDependenciesWorker finished its job, iteration ${iteration}.`);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
function tapStopToTerminateWorkers(compiler, getIssuesWorker, getDependenciesWorker, state) {
|
|
const { debug } = getInfrastructureLogger(compiler);
|
|
const terminateWorkers = ()=>{
|
|
debug('Compiler is going to close - terminating workers...');
|
|
getIssuesWorker.terminate();
|
|
getDependenciesWorker.terminate();
|
|
};
|
|
compiler.hooks.watchClose.tap('TsCheckerRspackPlugin', ()=>{
|
|
terminateWorkers();
|
|
});
|
|
compiler.hooks.done.tap('TsCheckerRspackPlugin', ()=>{
|
|
if (!state.watching) terminateWorkers();
|
|
});
|
|
compiler.hooks.failed.tap('TsCheckerRspackPlugin', ()=>{
|
|
if (!state.watching) terminateWorkers();
|
|
});
|
|
}
|
|
function createBasicFormatter() {
|
|
return function(issue) {
|
|
return external_picocolors_default().gray(issue.code + ': ') + issue.message;
|
|
};
|
|
}
|
|
const code_frame_namespaceObject = require("@babel/code-frame");
|
|
const external_node_fs_namespaceObject = require("node:fs");
|
|
var external_node_fs_default = /*#__PURE__*/ __webpack_require__.n(external_node_fs_namespaceObject);
|
|
function createCodeFrameFormatter(options) {
|
|
const basicFormatter = createBasicFormatter();
|
|
return function(issue) {
|
|
const source = issue.file && external_node_fs_default().existsSync(issue.file) && external_node_fs_default().readFileSync(issue.file, 'utf-8');
|
|
let frame = '';
|
|
if (source && issue.location) frame = (0, code_frame_namespaceObject.codeFrameColumns)(source, issue.location, {
|
|
highlightCode: true,
|
|
...options || {}
|
|
}).split('\n').map((line)=>' ' + line).join(external_node_os_default().EOL);
|
|
const lines = [
|
|
basicFormatter(issue)
|
|
];
|
|
if (frame) lines.push(frame);
|
|
return lines.join(external_node_os_default().EOL);
|
|
};
|
|
}
|
|
function createFormatterConfig(options) {
|
|
if ('function' == typeof options) return {
|
|
format: options,
|
|
pathType: 'relative'
|
|
};
|
|
const type = options ? 'object' == typeof options ? options.type || 'codeframe' : options : 'codeframe';
|
|
const pathType = options && 'object' == typeof options ? options.pathType || 'relative' : 'relative';
|
|
if (!type || 'basic' === type) return {
|
|
format: createBasicFormatter(),
|
|
pathType
|
|
};
|
|
if ('codeframe' === type) {
|
|
const config = options && 'object' == typeof options ? options.options || {} : {};
|
|
return {
|
|
format: createCodeFrameFormatter(config),
|
|
pathType
|
|
};
|
|
}
|
|
throw new Error(`Unknown "${type}" formatter. Available types are: "basic", "codeframe" or a custom function.`);
|
|
}
|
|
function createIssuePredicateFromIssueMatch(context, match) {
|
|
return (issue)=>{
|
|
const matchesSeverity = !match.severity || match.severity === issue.severity;
|
|
const matchesCode = !match.code || match.code === issue.code;
|
|
const matchesFile = !issue.file || !!issue.file && (!match.file || (0, external_minimatch_namespaceObject.minimatch)(forwardSlash(external_node_path_default().relative(context, issue.file)), match.file));
|
|
return matchesSeverity && matchesCode && matchesFile;
|
|
};
|
|
}
|
|
function createTrivialIssuePredicate(result) {
|
|
return ()=>result;
|
|
}
|
|
function composeIssuePredicates(predicates) {
|
|
return (issue)=>predicates.some((predicate)=>predicate(issue));
|
|
}
|
|
function createIssuePredicateFromOption(context, option) {
|
|
if (Array.isArray(option)) return composeIssuePredicates(option.map((option)=>'function' == typeof option ? option : createIssuePredicateFromIssueMatch(context, option)));
|
|
return 'function' == typeof option ? option : createIssuePredicateFromIssueMatch(context, option);
|
|
}
|
|
function createIssueConfig(compiler, options) {
|
|
const context = compiler.options.context || process.cwd();
|
|
if (!options) options = {};
|
|
const include = options.include ? createIssuePredicateFromOption(context, options.include) : createTrivialIssuePredicate(true);
|
|
const exclude = options.exclude ? createIssuePredicateFromOption(context, options.exclude) : createTrivialIssuePredicate(false);
|
|
const defaultSeverity = options.defaultSeverity ?? 'auto';
|
|
return {
|
|
predicate: (issue)=>include(issue) && !exclude(issue),
|
|
defaultSeverity
|
|
};
|
|
}
|
|
function createTypeScriptWorkerConfig(compiler, options) {
|
|
let configFile = 'object' == typeof options ? options.configFile || 'tsconfig.json' : 'tsconfig.json';
|
|
configFile = external_node_path_default().normalize(external_node_path_default().isAbsolute(configFile) ? configFile : external_node_path_default().resolve(compiler.options.context || process.cwd(), configFile));
|
|
const optionsAsObject = 'object' == typeof options ? options : {};
|
|
const typescriptPath = optionsAsObject.typescriptPath || require.resolve("typescript");
|
|
return {
|
|
enabled: Boolean(options) || void 0 === options,
|
|
memoryLimit: 8192,
|
|
build: false,
|
|
mode: optionsAsObject.build ? 'write-tsbuildinfo' : 'readonly',
|
|
profile: false,
|
|
...optionsAsObject,
|
|
configFile: configFile,
|
|
configOverwrite: optionsAsObject.configOverwrite || {},
|
|
context: optionsAsObject.context || external_node_path_default().dirname(configFile),
|
|
diagnosticOptions: {
|
|
syntactic: false,
|
|
semantic: true,
|
|
declaration: false,
|
|
global: false,
|
|
...optionsAsObject.diagnosticOptions || {}
|
|
},
|
|
typescriptPath: typescriptPath
|
|
};
|
|
}
|
|
function createPluginConfig(compiler, options = {}) {
|
|
return {
|
|
async: void 0 === options.async ? 'development' === compiler.options.mode : options.async,
|
|
typescript: createTypeScriptWorkerConfig(compiler, options.typescript),
|
|
issue: createIssueConfig(compiler, options.issue),
|
|
formatter: createFormatterConfig(options.formatter),
|
|
logger: 'webpack-infrastructure' === options.logger ? (()=>{
|
|
const { info, error } = getInfrastructureLogger(compiler);
|
|
return {
|
|
log: info,
|
|
error
|
|
};
|
|
})() : options.logger || console,
|
|
devServer: false !== options.devServer
|
|
};
|
|
}
|
|
function createPluginState() {
|
|
return {
|
|
issuesPromise: Promise.resolve(void 0),
|
|
dependenciesPromise: Promise.resolve(void 0),
|
|
abortController: void 0,
|
|
aggregatedFilesChange: void 0,
|
|
lastDependencies: void 0,
|
|
watching: false,
|
|
initialized: false,
|
|
iteration: 0,
|
|
DevServerDoneTap: void 0
|
|
};
|
|
}
|
|
function assertTypeScriptSupport(config) {
|
|
let typescriptVersion;
|
|
try {
|
|
typescriptVersion = require(config.typescriptPath).version;
|
|
} catch {}
|
|
if (!typescriptVersion) throw new Error("When you use TsCheckerRspackPlugin with typescript reporter enabled, you must install `typescript` package.");
|
|
if (!external_node_fs_default().existsSync(config.configFile)) throw new Error([
|
|
`Cannot find the "${config.configFile}" file.`,
|
|
"Please check Rspack and TsCheckerRspackPlugin configuration.",
|
|
"Possible errors:",
|
|
' - wrong `context` directory in Rspack configuration (if `configFile` is not set or is a relative path in the fork plugin configuration)',
|
|
" - wrong `typescript.configFile` path in the plugin configuration (should be a relative or absolute path)"
|
|
].join(external_node_os_default().EOL));
|
|
}
|
|
function plugin_define_property(obj, key, value) {
|
|
if (key in obj) Object.defineProperty(obj, key, {
|
|
value: value,
|
|
enumerable: true,
|
|
configurable: true,
|
|
writable: true
|
|
});
|
|
else obj[key] = value;
|
|
return obj;
|
|
}
|
|
const pkgJson = JSON.parse((0, external_node_fs_namespaceObject.readFileSync)(external_node_path_namespaceObject.join(__dirname, '../package.json'), 'utf-8'));
|
|
class TsCheckerRspackPlugin {
|
|
static getCompilerHooks(compiler) {
|
|
return getPluginHooks(compiler);
|
|
}
|
|
apply(compiler) {
|
|
const config = createPluginConfig(compiler, this.options);
|
|
const state = createPluginState();
|
|
assertTypeScriptSupport(config.typescript);
|
|
const getIssuesWorker = createRpcWorker(external_node_path_namespaceObject.resolve(__dirname, './getIssuesWorker.js'), config.typescript, config.typescript.memoryLimit);
|
|
const getDependenciesWorker = createRpcWorker(external_node_path_namespaceObject.resolve(__dirname, './getDependenciesWorker.js'), config.typescript);
|
|
tapAfterEnvironmentToPatchWatching(compiler, state);
|
|
tapStartToRunWorkers(compiler, getIssuesWorker, getDependenciesWorker, config, state);
|
|
tapAfterCompileToAddDependencies(compiler, config, state);
|
|
tapStopToTerminateWorkers(compiler, getIssuesWorker, getDependenciesWorker, state);
|
|
tapErrorToLogMessage(compiler, config);
|
|
}
|
|
constructor(options = {}){
|
|
plugin_define_property(this, "options", void 0);
|
|
this.options = options;
|
|
}
|
|
}
|
|
plugin_define_property(TsCheckerRspackPlugin, "version", pkgJson.version);
|
|
plugin_define_property(TsCheckerRspackPlugin, "issuesPool", issuesPool);
|
|
plugin_define_property(TsCheckerRspackPlugin, "dependenciesPool", dependenciesPool);
|
|
plugin_define_property(TsCheckerRspackPlugin, "pool", issuesPool);
|
|
exports.TsCheckerRspackPlugin = __webpack_exports__.TsCheckerRspackPlugin;
|
|
for(var __webpack_i__ in __webpack_exports__)if (-1 === [
|
|
"TsCheckerRspackPlugin"
|
|
].indexOf(__webpack_i__)) exports[__webpack_i__] = __webpack_exports__[__webpack_i__];
|
|
Object.defineProperty(exports, '__esModule', {
|
|
value: true
|
|
});
|
|
|