const path = require('path') const fs = require('fs-extra') const LRU = require('lru-cache') const winattr = require('@akryum/winattr') const hiddenPrefix = '.' const isPlatformWindows = process.platform.indexOf('win') === 0 const pkgCache = new LRU({ max: 500, maxAge: 1000 * 5 }) const cwd = require('./cwd') function isDirectory (file) { file = file.replace(/\\/g, path.sep) try { return fs.stat(file).then((x) => x.isDirectory()) } catch (e) { if (process.env.VUE_APP_CLI_UI_DEBUG) console.warn(e.message) } return false } async function list (base, context) { let dir = base if (isPlatformWindows) { if (base.match(/^([A-Z]{1}:)$/)) { dir = path.join(base, '\\') } } const files = await fs.readdir(dir, 'utf8') const f = await Promise.all( files.map(async (file) => { const folderPath = path.join(base, file) const [directory, hidden] = await Promise.all([ isDirectory(folderPath), isHidden(folderPath) ]) if (!directory) { return null } return { path: folderPath, name: file, hidden } }) ) return f.filter((x) => !!x) } async function isHiddenWindows (file) { const windowsFile = file.replace(/\\/g, '\\\\') return new Promise((resolve, reject) => { winattr.get(windowsFile, (file, error) => { if (error) { return reject(error) } resolve(file) }) }).then((x) => x.hidden) } async function isHidden (file) { try { const prefixed = path.basename(file).charAt(0) === hiddenPrefix const result = { unix: prefixed, windows: false } if (isPlatformWindows) { result.windows = await isHiddenWindows(file) } return ( (!isPlatformWindows && result.unix) || (isPlatformWindows && result.windows) ) } catch (e) { if (process.env.VUE_APP_CLI_UI_DEBUG) { console.log('file:', file) console.error(e) } } } function generateFolder (file, context) { return { name: path.basename(file), path: file } } function getCurrent (args, context) { const base = cwd.get() return generateFolder(base, context) } function open (file, context) { cwd.set(file, context) return generateFolder(cwd.get(), context) } function openParent (file, context) { const newFile = path.dirname(file) cwd.set(newFile, context) return generateFolder(cwd.get(), context) } function isPackage (file, context) { try { return fs.existsSync(path.join(file, 'package.json')) } catch (e) { console.warn(e.message) } return false } function readPackage (file, context, force = false) { if (!force) { const cachedValue = pkgCache.get(file) if (cachedValue) { return cachedValue } } const pkgFile = path.join(file, 'package.json') if (fs.existsSync(pkgFile)) { const pkg = fs.readJsonSync(pkgFile) pkgCache.set(file, pkg) return pkg } } function writePackage ({ file, data }, context) { fs.outputJsonSync(path.join(file, 'package.json'), data, { spaces: 2 }) invalidatePackage(file, context) return true } function invalidatePackage (file, context) { pkgCache.del(file) return true } function isVueProject (file, context) { if (!isPackage(file)) return false try { const pkg = readPackage(file, context) return Object.keys(pkg.devDependencies || {}).includes('@vue/cli-service') } catch (e) { if (process.env.VUE_APP_CLI_UI_DEBUG) { console.log(e) } } return false } function listFavorite (context) { return context.db .get('foldersFavorite') .value() .map((file) => generateFolder(file.id, context)) } function isFavorite (file, context) { return !!context.db.get('foldersFavorite').find({ id: file }).size().value() } function setFavorite ({ file, favorite }, context) { const collection = context.db.get('foldersFavorite') if (favorite) { collection.push({ id: file }).write() } else { collection.remove({ id: file }).write() } return generateFolder(file, context) } async function deleteFolder (file) { await fs.remove(file) } function createFolder (name, context) { const file = path.join(cwd.get(), name) fs.mkdirpSync(file) return generateFolder(file, context) } module.exports = { isDirectory, getCurrent, list, open, openParent, isPackage, readPackage, writePackage, invalidatePackage, isVueProject, isFavorite, listFavorite, setFavorite, delete: deleteFolder, create: createFolder }