import fs from 'fs' import os from 'os' import path from 'path' import * as is from './is.mjs' let IS_SUPPORT let TEMP_DIR = os.tmpdir && os.tmpdir() || process.env.TMPDIR || process.env.TEMP || process.cwd() function TempStack() { this.stack = [] } TempStack.prototype.create = function(type, base) { let name = path.join(base, 'node-watch-' + Math.random().toString(16).substr(2) ) this.stack.push({ name: name, type: type }) return name } TempStack.prototype.write = function(/* file */) { for (let i = 0; i < arguments.length; ++i) { fs.writeFileSync(arguments[i], ' ') } } TempStack.prototype.mkdir = function(/* dirs */) { for (let i = 0; i < arguments.length; ++i) { fs.mkdirSync(arguments[i]) } } TempStack.prototype.cleanup = function(fn) { try { let temp while ((temp = this.stack.pop())) { let type = temp.type let name = temp.name if (type === 'file' && is.file(name)) { fs.unlinkSync(name) } else if (type === 'dir' && is.directory(name)) { fs.rmdirSync(name) } } } finally { if (is.func(fn)) fn() } } let pending = false export default function hasNativeRecursive(fn, opts = {}) { if (!is.func(fn)) { return false } if (IS_SUPPORT !== undefined) { return fn(IS_SUPPORT) } if (opts.quickCheck) { return fn(IS_SUPPORT = (process.platform === 'darwin' || process.platform === 'win32')) } if (!pending) { pending = true } // check again later else { return setTimeout(function() { hasNativeRecursive(fn) }, 300) } let stack = new TempStack() let parent = stack.create('dir', TEMP_DIR) let child = stack.create('dir', parent) let file = stack.create('file', child) stack.mkdir(parent, child) let options = { recursive: true } let watcher try { watcher = fs.watch(parent, options) } catch (e) { if (e.code == 'ERR_FEATURE_UNAVAILABLE_ON_PLATFORM') { return fn(IS_SUPPORT = false) } else { throw e } } if (!watcher) { return false } let timer = setTimeout(function() { watcher.close() stack.cleanup(function() { fn(IS_SUPPORT = false) }) }, 200) watcher.on('change', function(evt, name) { if (path.basename(file) === path.basename(name)) { watcher.close() clearTimeout(timer) stack.cleanup(function() { fn(IS_SUPPORT = true) }) } }) stack.write(file) }