/**
 * This file is part of the vscode-helpers distribution.
 * Copyright (c) Marcel Joachim Kloubert.
 *
 * vscode-helpers is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, version 3.
 *
 * vscode-helpers is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */ import * as FastGlob from 'fast-glob' ; import * as FS from 'fs' ; import * as Glob from 'glob' ; const MergeDeep = require ( 'merge-deep' ) ; import * as Mkdirp from 'mkdirp' ; import * as Path from 'path' ; import * as TMP from 'tmp' ; import * as vscode_helpers from '../index' ; import * as vscode_workflows from '../workflows' ; export declare type FastGlobEntryItem = string | IFastGlobEntry ; export type FastGlobOptions = FastGlob . Options ; export interface IFastGlobEntry extends FS . Stats { path : string ; depth : number ; } /**
 * Options for a temp file.
 */ export interface TempFileOptions { /**
     * The custom directory for the file.
     */ dir ? : string ; /**
     * Keep temp file or not.
     */ keep ? : boolean ; /**
     * The optional prefix for the name of the file.
     */ prefix ? : string ; /**
     * The optional suffix for the name of the file.
     */ suffix ? : string ; } const lstat = FS . promises . lstat ; const stat = FS . promises . stat ; type TempFilePath = string | false ; param { string } dir return { Promise < boolean > } export async function createDirectoryIfNeeded ( dir ) { dir = vscode_helpers . toStringSafe ( dir ) ; if ( ! ( await exists ( dir ) ) ) { await Mkdirp ( dir ) ; return true ; } return false ; } param { string | Buffer } path return { Promise < boolean > } export function exists ( path ) { return new Promise < boolean > ( ( resolve , reject ) => { const COMPLETED = vscode_helpers . createCompletedAction ( resolve , reject ) ; try { FS . exists ( path , ( doesExist ) => { COMPLETED ( null , doesExist ) ; } ) ; } catch ( e ) { COMPLETED ( e ) ; } } ) ; } param { string | string [ ] } patterns param { FastGlob . Options } opts return { Promise < FastGlobEntryItem [ ] > } export function fastGlob ( patterns , opts ? ) { return FastGlob ( patterns , opts ) ; } param { string | string [ ] } patterns param { FastGlob . Options } opts return { FastGlobEntryItem [ ] } export function fastGlobSync ( patterns , opts ? ) { return FastGlob . sync ( patterns , opts ) ; } param { string | string [ ] } patterns param { Glob . IOptions } opts return { Promise < string [ ] > } export async function glob ( patterns , opts ? ) { opts = normalizeGlobOptions ( opts , { sync : false , } ) ; const WF = vscode_workflows . buildWorkflow ( ) ; WF . next ( ( ) => { return [ ] ; } ) ; vscode_helpers . asArray ( patterns ) . forEach ( p => { WF . next ( ( allMatches ) => { return new Promise < string [ ] > ( ( res , rej ) => { const COMPLETED = vscode_helpers . createCompletedAction ( res , rej ) ; try { Glob ( p , opts , ( err , matches ) => { if ( err ) { COMPLETED ( err ) ; } else { allMatches . push . apply ( allMatches , matches ) ; COMPLETED ( null , allMatches ) ; } } ) ; } catch ( e ) { COMPLETED ( e ) ; } } ) ; } ) ; } ) ; return vscode_helpers . from ( await WF . start < string [ ] > ( ) ) . select ( m => Path . resolve ( m ) ) . distinct ( ) . toArray ( ) ; } param { string | string [ ] } patterns param { Glob . IOptions } opts return { string [ ] } export function globSync ( patterns , opts ? ) { opts = normalizeGlobOptions ( opts , { sync : true , } ) ; const ALL_MATCHES = [ ] ; vscode_helpers . asArray ( patterns ) . forEach ( p => { ALL_MATCHES . push . apply ( ALL_MATCHES , Glob . sync ( p , opts ) ) ; } ) ; return vscode_helpers . from ( ALL_MATCHES ) . select ( m => Path . resolve ( m ) ) . distinct ( ) . toArray ( ) ; } async function invokeForStats < TResult = any > ( path , useLSTAT , func , defaultValue ? ) { path = vscode_helpers . toStringSafe ( path ) ; useLSTAT = vscode_helpers . toBooleanSafe ( useLSTAT , true ) ; if ( await exists ( path ) ) { const STATS = useLSTAT ? ( await lstat ( path ) ) : ( await stat ( path ) ) ; if ( STATS ) { return func ( STATS ) ; } } return defaultValue ; } function invokeForStatsSync < TResult = any > ( path , useLSTAT , func , defaultValue ? ) { path = vscode_helpers . toStringSafe ( path ) ; useLSTAT = vscode_helpers . toBooleanSafe ( useLSTAT , true ) ; if ( FS . existsSync ( path ) ) { const STATS = useLSTAT ? FS . lstatSync ( path ) : FS . statSync ( path ) ; if ( STATS ) { return func ( STATS ) ; } } return defaultValue ; } param { string } path param { boolean } useLSTAT return { Promise < boolean > } export async function isBlockDevice ( path , useLSTAT = true ) { return invokeForStats < boolean > ( path , useLSTAT , ( stats ) => stats . isBlockDevice ( ) , false ) ; } param { string } path param { boolean } useLSTAT return { boolean } export function isBlockDeviceSync ( path , useLSTAT = true ) { return invokeForStatsSync < boolean > ( path , useLSTAT , ( stats ) => stats . isBlockDevice ( ) , false ) ; } param { string } path param { boolean } useLSTAT return { Promise < boolean > } export async function isCharacterDevice ( path , useLSTAT = true ) { return invokeForStats < boolean > ( path , useLSTAT , ( stats ) => stats . isCharacterDevice ( ) , false ) ; } param { string } path param { boolean } useLSTAT return { boolean } export function isCharacterDeviceSync ( path , useLSTAT = true ) { return invokeForStatsSync < boolean > ( path , useLSTAT , ( stats ) => stats . isCharacterDevice ( ) , false ) ; } param { string } path param { boolean } useLSTAT return { Promise < boolean > } export async function isDirectory ( path , useLSTAT = true ) { return invokeForStats < boolean > ( path , useLSTAT , ( stats ) => stats . isDirectory ( ) , false ) ; } param { string } path param { boolean } useLSTAT return { boolean } export function isDirectorySync ( path , useLSTAT = true ) { return invokeForStatsSync < boolean > ( path , useLSTAT , ( stats ) => stats . isDirectory ( ) , false ) ; } param { string } path param { boolean } useLSTAT return { Promise < boolean > } export async function isFIFO ( path , useLSTAT = true ) { return invokeForStats < boolean > ( path , useLSTAT , ( stats ) => stats . isFIFO ( ) , false ) ; } param { string } path param { boolean } useLSTAT return { boolean } export function isFIFOSync ( path , useLSTAT = true ) { return invokeForStatsSync < boolean > ( path , useLSTAT , ( stats ) => stats . isFIFO ( ) , false ) ; } param { string } path param { boolean } useLSTAT return { Promise < boolean > } export async function isFile ( path , useLSTAT = true ) { return invokeForStats < boolean > ( path , useLSTAT , ( stats ) => stats . isFile ( ) , false ) ; } param { string } path param { boolean } useLSTAT return { boolean } export function isFileSync ( path , useLSTAT = true ) { return invokeForStatsSync < boolean > ( path , useLSTAT , ( stats ) => stats . isFile ( ) , false ) ; } param { string } path param { boolean } useLSTAT return { Promise < boolean > } export async function isSocket ( path , useLSTAT = true ) { return invokeForStats < boolean > ( path , useLSTAT , ( stats ) => stats . isSocket ( ) , false ) ; } param { string } path param { boolean } useLSTAT return { boolean } export function isSocketSync ( path , useLSTAT = true ) { return invokeForStatsSync < boolean > ( path , useLSTAT , ( stats ) => stats . isSocket ( ) , false ) ; } param { string } path param { boolean } useLSTAT return { Promise < boolean > } export async function isSymbolicLink ( path , useLSTAT = true ) { return invokeForStats < boolean > ( path , useLSTAT , ( stats ) => stats . isSymbolicLink ( ) , false ) ; } param { string } path param { boolean } useLSTAT return { boolean } export function isSymbolicLinkSync ( path , useLSTAT = true ) { return invokeForStatsSync < boolean > ( path , useLSTAT , ( stats ) => stats . isSymbolicLink ( ) , false ) ; } function normalizeGlobOptions ( opts , callerDefaultOpts ) { const DEFAULT_OPTS = { absolute : true , dot : false , nocase : true , nodir : true , nonull : false , nosort : false , } ; return MergeDeep ( { } , DEFAULT_OPTS , callerDefaultOpts , opts ) ; } function normalizeTempFileOptions ( opts ) { const DEFAULT_OPTS = { } ; opts = MergeDeep ( { } , DEFAULT_OPTS , opts ) ; opts . dir = vscode_helpers . toStringSafe ( opts . dir ) ; if ( vscode_helpers . isEmptyString ( opts . dir ) ) { opts . dir = undefined ; } opts . prefix = vscode_helpers . toStringSafe ( opts . prefix ) ; if ( '' === opts . prefix ) { opts . prefix = undefined ; } opts . suffix = vscode_helpers . toStringSafe ( opts . suffix ) ; if ( '' === opts . suffix ) { opts . suffix = undefined ; } return opts ; } param { string | Buffer } path param { boolean } useLSTAT return { Promise < number > } export async function size ( path , useLSTAT = true ) { useLSTAT = vscode_helpers . toBooleanSafe ( useLSTAT , true ) ; return useLSTAT ? ( await lstat ( path ) ) . size : ( await stat ( path ) ) . size ; } param { string | Buffer } path param { boolean } useLSTAT return { number } export function sizeSync ( path , useLSTAT = true ) { useLSTAT = vscode_helpers . toBooleanSafe ( useLSTAT , true ) ; return useLSTAT ? FS . lstatSync ( path ) . size : FS . statSync ( path ) . size ; } param { Function } action param { TempFileOptions } opts return { Promise < TResult > } export function tempFile < TResult = any > ( action , opts ? ) { opts = normalizeTempFileOptions ( opts ) ; return new Promise < TResult > ( ( resolve , reject ) => { let completedInvoked = false ; let tempFile = false ; const COMPLETED = ( err , result ? ) => { if ( completedInvoked ) { return ; } completedInvoked = true ; try { if ( err ) { reject ( err ) ; } else { resolve ( result ) ; } } finally { tryUnlinkTempFile ( tempFile , opts ) ; } } ; try { TMP . tmpName ( toTmpSimpleOptions ( opts ) , ( err , path ) => { if ( err ) { COMPLETED ( err ) ; } else { tempFile = path ; try { Promise . resolve ( action ( tempFile ) ) . then ( ( result ) => { COMPLETED ( null , result ) ; } ) . catch ( ( e ) => { COMPLETED ( e ) ; } ) ; } catch ( e ) { COMPLETED ( e ) ; } } } ) ; } catch ( e ) { COMPLETED ( e ) ; } } ) ; } function toTmpSimpleOptions ( opts ) { return { dir : opts . dir , keep : true , prefix : opts . prefix , postfix : opts . suffix , } ; } param { Function } action param { TempFileOptions } opts return { TResult } export function tempFileSync < TResult = any > ( action , opts ? ) { opts = normalizeTempFileOptions ( opts ) ; let tempFile = false ; try { tempFile = TMP . tmpNameSync ( toTmpSimpleOptions ( opts ) ) ; return action ( tempFile ) ; } finally { tryUnlinkTempFile ( tempFile , opts ) ; } } function tryUnlinkTempFile ( file , opts ? ) { try { if ( false !== file ) { if ( ! vscode_helpers . toBooleanSafe ( opts . keep ) ) { if ( isFileSync ( file ) ) { FS . unlinkSync ( file ) ; } } } return true ; } catch { return false ; } }