ucbuilder
Version:
:Shree Ganeshay Namah: new way app design
213 lines (209 loc) • 8.74 kB
JavaScript
import chokidar from "chokidar";
import fs from "fs";
import path from "path";
import { IpcMainGroup } from "../main/ipc/IpcMainHelper.js";
import { ucUtil } from "../global/ucUtil.js";
import url from "url";
import { PathBridge } from "./pathBridge.js";
import { GetProject, isSamePath } from "../common/ipc/enumAndMore.js";
export default function () {
const main = IpcMainGroup('ucbuilder/src/build/fileWatcher.ts');
const projectRoot = path.resolve();
const srcPath = projectRoot; //path.join(projectRoot, "src");
const pathMapFile = path.join(projectRoot, "path-map.json");
const ignoredList = [
path.join(projectRoot, 'node_modules'),
path.join(projectRoot, '.git'),
path.join(projectRoot, 'out'),
path.join(projectRoot, 'dist'),
];
let rendererIgnorance = [];
const watcherOptions = {
ignoreInitial: true,
ignored: (file) => ignoredList.findIndex(s => isSamePath(s, file, path)) >= 0 &&
rendererIgnorance.findIndex(s => isSamePath(s, file, path)) >= 0,
// [
// '**/node_modules/**',
// '**/.git/**',
// // '**/out/**',
// // '**/assets/**',
// // '**/dist/**',
// path.join(srcPath, 'out'),
// path.join(srcPath, 'dist'),
// ],
persistent: true,
depth: undefined, // watch all subfolders
usePolling: true, // more stable across OS types
interval: 200, // poll every 200ms
};
let eleEvent;
let IS_ON = false;
main.On("startWatch", (e, _path) => {
eleEvent = e;
IS_ON = true;
startWatch();
});
main.On("writeContents", (e, changedFiles) => {
let __KEYS = Object.keys(changedFiles);
rendererIgnorance.push(...__KEYS);
rendererIgnorance = ucUtil.distinct(rendererIgnorance);
for (const [_path, contents] of Object.entries(changedFiles)) {
// console.log([_path, contents]);
fs.writeFileSync(_path, contents, 'binary');
}
setTimeout(() => {
rendererIgnorance = rendererIgnorance.filter(s => !__KEYS.includes(s));
}, 1000);
e.returnValue = true;
});
main.Handle("stopWatch", async (evt, _path) => {
//watcher?.unwatch(srcPath);
if (watcher != undefined)
await watcher.close(); //.then(() => console.log("Chokidar watcher stopped"));
IS_ON = false;
clearInterval(interval);
return true;
});
// ---- STATE ----
let pathMap = fs.existsSync(pathMapFile)
? JSON.parse(fs.readFileSync(pathMapFile, "utf-8"))
: {};
let unlinkCache = []; // store recently removed files (for rename detection)
const MOVE_TIME_DIFFERENCE = 3200;
const WATCH_LIST = {
unlink: {},
modified: {},
add: {},
renamed: [],
moved: [],
};
let watcher;
let interval = null;
function startWatch() {
// ---- WATCHER ----
watcher = chokidar.watch(srcPath, watcherOptions);
console.log(`[path-watcher] Watching ${srcPath}`);
watcher
.on("add", newPath => {
WATCH_LIST.add[newPath] = Date.now();
doProcess();
})
.on("unlink", removedPath => {
WATCH_LIST.unlink[removedPath] = Date.now();
doProcess();
});
}
const project = GetProject(path.resolve(), PathBridge.source, url);
const mainProjectUcConfig = project?.config;
const preference = mainProjectUcConfig?.preference;
const dirDeclaration = mainProjectUcConfig?.preference?.dirDeclaration;
const srcDirDec = dirDeclaration[preference.srcDir];
const srcFileWisePath = srcDirDec.fileDeclaration;
const codeExtension = srcFileWisePath.code.extension;
const outDirDec = dirDeclaration[preference.outDir];
const outFileWisePath = outDirDec.fileDeclaration;
const outcodeExtension = outFileWisePath.code.extension;
// const outFileWisePath = outDirDec.fileWisePath;
// const dirDecEntries = Object.entries(dirDeclaration);
let isProcessing = false;
function doProcess() {
if (isProcessing)
return;
isProcessing = true;
function analysis() {
const newAr = ucUtil.JsonCopy(WATCH_LIST);
mainProjectUcConfig.preference.dirDeclaration;
isProcessing = false;
WATCH_LIST.add = {};
WATCH_LIST.modified = {};
WATCH_LIST.unlink = {};
for (let [addedPath, addedTime] of Object.entries(newAr.add)) {
for (let [unlinkPath, unlinkTime] of Object.entries(newAr.unlink)) {
if ((addedTime - unlinkTime) < MOVE_TIME_DIFFERENCE) {
const addedBaseName = path.basename(addedPath);
const unlinkBaseName = path.basename(unlinkPath);
if (addedBaseName === unlinkBaseName) {
delete newAr.add[addedPath];
delete newAr.unlink[unlinkPath];
if (unlinkPath.endsWith(codeExtension)) {
if (unlinkPath.endsWith(`.uc${codeExtension}`) ||
unlinkPath.endsWith(`.tpt${codeExtension}`)) {
let fromResult = PathBridge.Convert(unlinkPath, preference.srcDir, 'code');
let toResult = PathBridge.Convert(addedPath, preference.srcDir, 'code');
for (const [k, fromfile] of Object.entries(fromResult)) {
if (fromfile.code != undefined)
newAr.moved.push({ from: fromfile.code, to: toResult[k]?.code });
if (fromfile.designer != undefined)
newAr.moved.push({ from: fromfile.designer, to: toResult[k]?.designer });
}
}
else {
newAr.moved.push({
from: ucUtil.changeExtension(unlinkPath, codeExtension, outcodeExtension),
to: ucUtil.changeExtension(addedPath, codeExtension, outcodeExtension),
});
}
}
else {
newAr.moved.push({ from: unlinkPath, to: addedPath });
}
break;
}
}
}
}
main.Reply("updates", eleEvent, JSON.stringify(newAr));
}
let to = setTimeout(analysis, 3000);
}
}
/*function detectRename(newFile) {
const now = Date.now();
const matchIndex = unlinkCache.findIndex(
e => {
return now - e.time < MOVE_TIME_DIFFERENCE && path.basename(e.path) === path.basename(newFile);
}
);
if (matchIndex !== -1) {
const oldFile = unlinkCache[matchIndex].path;
unlinkCache.splice(matchIndex, 1);
main.Reply("watch_moved", eleEvent, oldFile, newFile);
const key = Object.keys(pathMap).find(k => pathMap[k] === oldFile);
if (key) {
pathMap[key] = newFile;
savePathMap();
}
return true;
}
return false;
}
function startWatch() {
// ---- WATCHER ----
console.log(watcherOptions);
watcher = chokidar.watch(srcPath, watcherOptions);
console.log(`[path-watcher] Watching ${srcPath}`);
watcher
.on("add", newPath => {
if (!detectRename(newPath)) {
// console.log("🟢 File added:", newPath);
pathMap[newPath] = newPath;
//savePathMap();
}
})
.on("unlink", removedPath => {
//console.log("🔴 File removed:", removedPath);
unlinkCache.push({ path: removedPath, time: Date.now() });
const entry = Object.keys(pathMap).find(k => pathMap[k] === removedPath);
if (entry) delete pathMap[entry];
//savePathMap();
main.Reply("watch_removed", eleEvent, removedPath);
})
// ---- PERIODIC SYNC ----
interval = setInterval(() => {
console.log("🧩 Background sync running...");
const now = Date.now();
unlinkCache = unlinkCache.filter(e => now - e.time < MOVE_TIME_DIFFERENCE);
}, 5000);
}
*/
//# sourceMappingURL=fileWatcher.ipc.js.map