UNPKG

@nx/js

Version:

The JS plugin for Nx contains executors and generators that provide the best experience for developing JavaScript and TypeScript projects.

164 lines (163 loc) • 6.86 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.CopyAssetsHandler = exports.defaultFileEventHandler = void 0; const picomatch = require("picomatch"); const node_fs_1 = require("node:fs"); const pathPosix = require("node:path/posix"); const path = require("node:path"); const ignore_1 = require("ignore"); const tinyglobby_1 = require("tinyglobby"); const devkit_1 = require("@nx/devkit"); const client_1 = require("nx/src/daemon/client/client"); const picocolors_1 = require("picocolors"); const defaultFileEventHandler = (events) => { const dirs = new Set(events.map((event) => path.dirname(event.dest))); dirs.forEach((d) => (0, node_fs_1.mkdirSync)(d, { recursive: true })); events.forEach((event) => { if (event.type === 'create' || event.type === 'update') { if ((0, node_fs_1.lstatSync)(event.src).isFile()) { (0, node_fs_1.copyFileSync)(event.src, event.dest); } } else if (event.type === 'delete') { (0, node_fs_1.rmSync)(event.dest, { recursive: true, force: true }); } else { devkit_1.logger.error(`Unknown file event: ${event.type}`); } const eventDir = path.dirname(event.src); const relativeDest = path.relative(eventDir, event.dest); devkit_1.logger.log(`\n${(0, picocolors_1.dim)(relativeDest)}`); }); }; exports.defaultFileEventHandler = defaultFileEventHandler; class CopyAssetsHandler { constructor(opts) { this.rootDir = opts.rootDir; this.projectDir = opts.projectDir; this.outputDir = opts.outputDir; this.callback = opts.callback ?? exports.defaultFileEventHandler; // TODO(jack): Should handle nested .gitignore files this.ignore = (0, ignore_1.default)(); const gitignore = pathPosix.join(opts.rootDir, '.gitignore'); const nxignore = pathPosix.join(opts.rootDir, '.nxignore'); if ((0, node_fs_1.existsSync)(gitignore)) this.ignore.add((0, node_fs_1.readFileSync)(gitignore).toString()); if ((0, node_fs_1.existsSync)(nxignore)) this.ignore.add((0, node_fs_1.readFileSync)(nxignore).toString()); this.assetGlobs = opts.assets.map((f) => { let isGlob = false; let pattern; // Input and output directories are normalized to be relative to root let input; let output; let ignore = null; if (typeof f === 'string') { pattern = f; input = path.relative(opts.rootDir, opts.projectDir); output = path.relative(opts.rootDir, opts.outputDir); } else { isGlob = true; pattern = pathPosix.join(f.input, f.glob); input = f.input; output = pathPosix.join(path.relative(opts.rootDir, opts.outputDir), f.output); if (f.ignore) ignore = f.ignore.map((ig) => pathPosix.join(f.input, ig)); } return { isGlob, input, pattern, ignore, output, }; }); } async processAllAssetsOnce() { await Promise.all(this.assetGlobs.map(async (ag) => { const pattern = this.normalizeAssetPattern(ag); // globbing only supports Unix paths const files = await (0, tinyglobby_1.globSync)(pattern.replace(/\\/g, '/'), { cwd: this.rootDir, dot: true, // enable hidden files expandDirectories: false, }); this.callback(this.filesToEvent(files, ag)); })); } processAllAssetsOnceSync() { this.assetGlobs.forEach((ag) => { const pattern = this.normalizeAssetPattern(ag); // globbing only supports Unix paths const files = (0, tinyglobby_1.globSync)(pattern.replace(/\\/g, '/'), { cwd: this.rootDir, dot: true, // enable hidden files expandDirectories: false, }); this.callback(this.filesToEvent(files, ag)); }); } async watchAndProcessOnAssetChange() { const unregisterFileWatcher = await client_1.daemonClient.registerFileWatcher({ watchProjects: 'all', includeGlobalWorkspaceFiles: true, }, (err, data) => { if (err === 'closed') { devkit_1.logger.error(`Watch error: Daemon closed the connection`); process.exit(1); } else if (err) { devkit_1.logger.error(`Watch error: ${err?.message ?? 'Unknown'}`); } else { this.processWatchEvents(data.changedFiles); } }); return () => unregisterFileWatcher(); } async processWatchEvents(events) { const fileEvents = []; for (const event of events) { const pathFromRoot = event.path.startsWith(this.rootDir) ? path.relative(this.rootDir, event.path) : event.path; for (const ag of this.assetGlobs) { if (picomatch(ag.pattern)(pathFromRoot) && !ag.ignore?.some((ig) => picomatch(ig)(pathFromRoot)) && !this.ignore.ignores(pathFromRoot)) { const relPath = path.relative(ag.input, pathFromRoot); const destPath = relPath.startsWith('..') ? pathFromRoot : relPath; fileEvents.push({ type: event.type, src: path.join(this.rootDir, pathFromRoot), dest: path.join(this.rootDir, ag.output, destPath), }); // Match first entry and skip the rest for this file. break; } } } if (fileEvents.length > 0) this.callback(fileEvents); } filesToEvent(files, assetGlob) { return files.reduce((acc, src) => { if (!assetGlob.ignore?.some((ig) => picomatch(ig)(src)) && !this.ignore.ignores(src)) { const relPath = path.relative(assetGlob.input, src); const dest = relPath.startsWith('..') ? src : relPath; acc.push({ type: 'create', src: path.join(this.rootDir, src), dest: path.join(this.rootDir, assetGlob.output, dest), }); } return acc; }, []); } normalizeAssetPattern(assetEntry) { return typeof assetEntry === 'string' ? assetEntry : assetEntry.pattern; } } exports.CopyAssetsHandler = CopyAssetsHandler;