@@ -334,6 +334,21 @@ export interface IWatchOptions extends IOptions {
334334 recursive ?: boolean ,
335335}
336336
337+ // Options for `fs.mkdir` and `fs.mkdirSync`
338+ export interface IMkdirOptions {
339+ mode ?: TMode ,
340+ recursive ?: boolean ,
341+ } ;
342+ const mkdirDefaults : IMkdirOptions = {
343+ mode : MODE . DIR ,
344+ recursive : false ,
345+ } ;
346+ const getMkdirOptions = options => {
347+ if ( typeof options === 'number' )
348+ return extend ( { } , mkdirDefaults , { mode : options } ) ;
349+ return extend ( { } , mkdirDefaults , options ) ;
350+ }
351+
337352
338353
339354// ---------------------------------------- Utility functions
@@ -1725,19 +1740,63 @@ export class Volume {
17251740 dir . createChild ( name , this . createNode ( true , modeNum ) ) ;
17261741 }
17271742
1728- mkdirSync ( path : TFilePath , mode ?: TMode ) {
1729- const modeNum = modeToNumber ( mode , 0o777 ) ;
1743+ /**
1744+ * Creates directory tree recursively.
1745+ * @param filename
1746+ * @param modeNum
1747+ */
1748+ private mkdirpBase ( filename : string , modeNum : number ) {
1749+ const steps = filenameToSteps ( filename ) ;
1750+ let link = this . root ;
1751+ for ( let i = 0 ; i < steps . length ; i ++ ) {
1752+ const step = steps [ i ] ;
1753+
1754+ if ( ! link . getNode ( ) . isDirectory ( ) )
1755+ throwError ( ENOTDIR , 'mkdir' , link . getPath ( ) ) ;
1756+
1757+ const child = link . getChild ( step ) ;
1758+ if ( child ) {
1759+ if ( child . getNode ( ) . isDirectory ( ) ) link = child ;
1760+ else throwError ( ENOTDIR , 'mkdir' , child . getPath ( ) ) ;
1761+ } else {
1762+ link = link . createChild ( step , this . createNode ( true , modeNum ) ) ;
1763+ }
1764+ }
1765+ }
1766+
1767+ mkdirSync ( path : TFilePath , options ?: TMode | IMkdirOptions ) {
1768+ const opts = getMkdirOptions ( options ) ;
1769+ const modeNum = modeToNumber ( opts . mode , 0o777 ) ;
17301770 const filename = pathToFilename ( path ) ;
1731- this . mkdirBase ( filename , modeNum ) ;
1771+ if ( opts . recursive )
1772+ this . mkdirpBase ( filename , modeNum ) ;
1773+ else
1774+ this . mkdirBase ( filename , modeNum ) ;
17321775 }
17331776
17341777 mkdir ( path : TFilePath , callback : TCallback < void > ) ;
1735- mkdir ( path : TFilePath , mode : TMode , callback : TCallback < void > ) ;
1736- mkdir ( path : TFilePath , a : TCallback < void > | TMode , b ?: TCallback < void > ) {
1737- const [ mode , callback ] = getArgAndCb < TMode , void > ( a , b ) ;
1738- const modeNum = modeToNumber ( mode , 0o777 ) ;
1778+ mkdir ( path : TFilePath , mode : TMode | IMkdirOptions , callback : TCallback < void > ) ;
1779+ mkdir ( path : TFilePath , a : TCallback < void > | TMode | IMkdirOptions , b ?: TCallback < void > ) {
1780+ const [ options , callback ] = getArgAndCb < TMode | IMkdirOptions , void > ( a , b ) ;
1781+ const opts = getMkdirOptions ( options ) ;
1782+ const modeNum = modeToNumber ( opts . mode , 0o777 ) ;
17391783 const filename = pathToFilename ( path ) ;
1740- this . wrapAsync ( this . mkdirBase , [ filename , modeNum ] , callback ) ;
1784+ if ( opts . recursive )
1785+ this . wrapAsync ( this . mkdirpBase , [ filename , modeNum ] , callback ) ;
1786+ else
1787+ this . wrapAsync ( this . mkdirBase , [ filename , modeNum ] , callback ) ;
1788+ }
1789+
1790+ // legacy interface
1791+ mkdirpSync ( path : TFilePath , mode ?: TMode ) {
1792+ this . mkdirSync ( path , { mode, recursive : true } ) ;
1793+ }
1794+
1795+ mkdirp ( path : TFilePath , callback : TCallback < void > ) ;
1796+ mkdirp ( path : TFilePath , mode : TMode , callback : TCallback < void > ) ;
1797+ mkdirp ( path : TFilePath , a : TCallback < void > | TMode , b ?: TCallback < void > ) {
1798+ const [ mode , callback ] = getArgAndCb < TMode , void > ( a , b ) ;
1799+ this . mkdir ( path , { mode, recursive : true } , callback ) ;
17411800 }
17421801
17431802 private mkdtempBase ( prefix : string , encoding : TEncodingExtended , retry : number = 5 ) : TDataOut {
@@ -1777,45 +1836,6 @@ export class Volume {
17771836 this . wrapAsync ( this . mkdtempBase , [ prefix , encoding ] , callback ) ;
17781837 }
17791838
1780- /**
1781- * Creates directory tree recursively.
1782- * @param filename
1783- * @param modeNum
1784- */
1785- private mkdirpBase ( filename : string , modeNum : number ) {
1786- const steps = filenameToSteps ( filename ) ;
1787- let link = this . root ;
1788- for ( let i = 0 ; i < steps . length ; i ++ ) {
1789- const step = steps [ i ] ;
1790-
1791- if ( ! link . getNode ( ) . isDirectory ( ) )
1792- throwError ( ENOTDIR , 'mkdirp' , link . getPath ( ) ) ;
1793-
1794- const child = link . getChild ( step ) ;
1795- if ( child ) {
1796- if ( child . getNode ( ) . isDirectory ( ) ) link = child ;
1797- else throwError ( ENOTDIR , 'mkdirp' , child . getPath ( ) ) ;
1798- } else {
1799- link = link . createChild ( step , this . createNode ( true , modeNum ) ) ;
1800- }
1801- }
1802- }
1803-
1804- mkdirpSync ( path : TFilePath , mode ?: TMode ) {
1805- const modeNum = modeToNumber ( mode , 0o777 ) ;
1806- const filename = pathToFilename ( path ) ;
1807- this . mkdirpBase ( filename , modeNum ) ;
1808- }
1809-
1810- mkdirp ( path : TFilePath , callback : TCallback < void > ) ;
1811- mkdirp ( path : TFilePath , mode : TMode , callback : TCallback < void > ) ;
1812- mkdirp ( path : TFilePath , a : TCallback < void > | TMode , b ?: TCallback < void > ) {
1813- const [ mode , callback ] = getArgAndCb < TMode , void > ( a , b ) ;
1814- const modeNum = modeToNumber ( mode , 0o777 ) ;
1815- const filename = pathToFilename ( path ) ;
1816- this . wrapAsync ( this . mkdirpBase , [ filename , modeNum ] , callback ) ;
1817- }
1818-
18191839 private rmdirBase ( filename : string ) {
18201840 const link = this . getLinkAsDirOrThrow ( filename , 'rmdir' ) ;
18211841
0 commit comments