Skip to content

Commit 96592fe

Browse files
Richienbsindresorhus
andauthoredSep 13, 2020
Add cleanup methods (#25)
Co-authored-by: Sindre Sorhus <sindresorhus@gmail.com>
1 parent c6e32f1 commit 96592fe

File tree

6 files changed

+181
-45
lines changed

6 files changed

+181
-45
lines changed
 

‎index.d.ts

+98-38
Original file line numberDiff line numberDiff line change
@@ -35,59 +35,119 @@ declare namespace tempy {
3535
*/
3636
readonly prefix?: string;
3737
};
38+
39+
/**
40+
The temporary path created by the function. Can be asynchronous.
41+
*/
42+
type TaskCallback = (tempPath: string) => Promise<void> | void;
3843
}
3944

4045
declare const tempy: {
41-
/**
42-
Get a temporary file path you can write to.
46+
file: {
47+
/**
48+
The `callback` resolves with a temporary file path you can write to. The file is automatically cleaned up after the callback is executed.
4349
44-
@example
45-
```
46-
import tempy = require('tempy');
50+
@returns A promise that resolves after the callback is executed and the file is cleaned up.
4751
48-
tempy.file();
49-
//=> '/private/var/folders/3x/jf5977fn79jbglr7rk0tq4d00000gn/T/4f504b9edb5ba0e89451617bf9f971dd'
52+
@example
53+
```
54+
import tempy = require('tempy');
5055
51-
tempy.file({extension: 'png'});
52-
//=> '/private/var/folders/3x/jf5977fn79jbglr7rk0tq4d00000gn/T/a9fb0decd08179eb6cf4691568aa2018.png'
56+
await tempy.file.task(tempFile => {
57+
console.log(tempFile);
58+
//=> '/private/var/folders/3x/jf5977fn79jbglr7rk0tq4d00000gn/T/4f504b9edb5ba0e89451617bf9f971dd'
59+
});
60+
```
61+
*/
62+
task: (callback: tempy.TaskCallback, options?: tempy.FileOptions) => Promise<void>;
5363

54-
tempy.file({name: 'unicorn.png'});
55-
//=> '/private/var/folders/3x/jf5977fn79jbglr7rk0tq4d00000gn/T/f7f62bfd4e2a05f1589947647ed3f9ec/unicorn.png'
64+
/**
65+
Get a temporary file path you can write to.
5666
57-
tempy.directory();
58-
//=> '/private/var/folders/3x/jf5977fn79jbglr7rk0tq4d00000gn/T/2f3d094aec2cb1b93bb0f4cffce5ebd6'
59-
```
60-
*/
61-
file: (options?: tempy.FileOptions) => string;
67+
@example
68+
```
69+
import tempy = require('tempy');
6270
63-
/**
64-
Get a temporary directory path. The directory is created for you.
71+
tempy.file();
72+
//=> '/private/var/folders/3x/jf5977fn79jbglr7rk0tq4d00000gn/T/4f504b9edb5ba0e89451617bf9f971dd'
6573
66-
@example
67-
```
68-
import tempy = require('tempy');
74+
tempy.file({extension: 'png'});
75+
//=> '/private/var/folders/3x/jf5977fn79jbglr7rk0tq4d00000gn/T/a9fb0decd08179eb6cf4691568aa2018.png'
6976
70-
tempy.directory();
71-
//=> '/private/var/folders/3x/jf5977fn79jbglr7rk0tq4d00000gn/T/2f3d094aec2cb1b93bb0f4cffce5ebd6'
77+
tempy.file({name: 'unicorn.png'});
78+
//=> '/private/var/folders/3x/jf5977fn79jbglr7rk0tq4d00000gn/T/f7f62bfd4e2a05f1589947647ed3f9ec/unicorn.png'
7279
73-
tempy.directory({prefix: 'a'});
74-
//=> '/private/var/folders/3x/jf5977fn79jbglr7rk0tq4d00000gn/T/name_3c085674ad31223b9653c88f725d6b41'
75-
```
76-
*/
77-
directory: (options?: tempy.DirectoryOptions) => string;
80+
tempy.directory();
81+
//=> '/private/var/folders/3x/jf5977fn79jbglr7rk0tq4d00000gn/T/2f3d094aec2cb1b93bb0f4cffce5ebd6'
82+
```
83+
*/
84+
(options?: tempy.FileOptions): string;
85+
};
7886

79-
/**
80-
Write data to a random temp file.
87+
directory: {
88+
/**
89+
The `callback` resolves with a temporary directory path you can write to. The directory is automatically cleaned up after the callback is executed.
8190
82-
@example
83-
```
84-
import tempy = require('tempy');
91+
@returns A promise that resolves after the callback is executed and the directory is cleaned up.
8592
86-
await tempy.write('🦄');
87-
//=> '/private/var/folders/3x/jf5977fn79jbglr7rk0tq4d00000gn/T/2f3d094aec2cb1b93bb0f4cffce5ebd6'
88-
```
89-
*/
90-
write: (fileContent: string | Buffer | TypedArray | DataView | NodeJS.ReadableStream, options?: tempy.FileOptions) => Promise<string>;
93+
@example
94+
```
95+
import tempy = require('tempy');
96+
97+
await tempy.directory.task(tempDirectory => {
98+
//=> '/private/var/folders/3x/jf5977fn79jbglr7rk0tq4d00000gn/T/2f3d094aec2cb1b93bb0f4cffce5ebd6'
99+
})
100+
```
101+
*/
102+
task: (callback: tempy.TaskCallback, options?: tempy.DirectoryOptions) => Promise<void>;
103+
104+
/**
105+
Get a temporary directory path. The directory is created for you.
106+
107+
@example
108+
```
109+
import tempy = require('tempy');
110+
111+
tempy.directory();
112+
//=> '/private/var/folders/3x/jf5977fn79jbglr7rk0tq4d00000gn/T/2f3d094aec2cb1b93bb0f4cffce5ebd6'
113+
114+
tempy.directory({prefix: 'a'});
115+
//=> '/private/var/folders/3x/jf5977fn79jbglr7rk0tq4d00000gn/T/name_3c085674ad31223b9653c88f725d6b41'
116+
```
117+
*/
118+
(options?: tempy.DirectoryOptions): string;
119+
};
120+
121+
write: {
122+
/**
123+
Write data to a random temp file. The file is automatically cleaned up after the callback is executed.
124+
125+
@returns A promise that resolves after the callback is executed and the file is cleaned up.
126+
127+
@example
128+
```
129+
import tempy = require('tempy');
130+
131+
await tempy.write.task('🦄', tempFile => {
132+
//=> '/private/var/folders/3x/jf5977fn79jbglr7rk0tq4d00000gn/T/4f504b9edb5ba0e89451617bf9f971dd'
133+
});
134+
```
135+
*/
136+
task: (fileContent: string | Buffer | TypedArray | DataView | NodeJS.ReadableStream, callback: tempy.TaskCallback, options?: tempy.FileOptions) => Promise<void>;
137+
138+
/**
139+
Write data to a random temp file.
140+
141+
@example
142+
```
143+
import tempy = require('tempy');
144+
145+
await tempy.write('🦄');
146+
//=> '/private/var/folders/3x/jf5977fn79jbglr7rk0tq4d00000gn/T/2f3d094aec2cb1b93bb0f4cffce5ebd6'
147+
```
148+
*/
149+
(fileContent: string | Buffer | TypedArray | DataView | NodeJS.ReadableStream, options?: tempy.FileOptions): Promise<string>;
150+
};
91151

92152
/**
93153
Synchronously write data to a random temp file.

‎index.js

+14
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ const path = require('path');
44
const uniqueString = require('unique-string');
55
const tempDir = require('temp-dir');
66
const isStream = require('is-stream');
7+
const del = require('del');
78
const stream = require('stream');
89
const {promisify} = require('util');
910

@@ -14,6 +15,13 @@ const getPath = (prefix = '') => path.join(tempDir, prefix + uniqueString());
1415

1516
const writeStream = async (filePath, data) => pipeline(data, fs.createWriteStream(filePath));
1617

18+
const createTask = (tempyFunction, {extraArguments = 0} = {}) => async (...arguments_) => {
19+
const [callback, options] = arguments_.slice(extraArguments);
20+
const result = await tempyFunction(...arguments_.slice(0, extraArguments), options);
21+
await callback(result);
22+
await del(result, {force: true});
23+
};
24+
1725
module.exports.file = options => {
1826
options = {
1927
...options
@@ -30,19 +38,25 @@ module.exports.file = options => {
3038
return getPath() + (options.extension === undefined || options.extension === null ? '' : '.' + options.extension.replace(/^\./, ''));
3139
};
3240

41+
module.exports.file.task = createTask(module.exports.file);
42+
3343
module.exports.directory = ({prefix = ''} = {}) => {
3444
const directory = getPath(prefix);
3545
fs.mkdirSync(directory);
3646
return directory;
3747
};
3848

49+
module.exports.directory.task = createTask(module.exports.directory);
50+
3951
module.exports.write = async (data, options) => {
4052
const filename = module.exports.file(options);
4153
const write = isStream(data) ? writeStream : writeFile;
4254
await write(filename, data);
4355
return filename;
4456
};
4557

58+
module.exports.write.task = createTask(module.exports.write, {extraArguments: 1});
59+
4660
module.exports.writeSync = (data, options) => {
4761
const filename = module.exports.file(options);
4862
fs.writeFileSync(filename, data);

‎index.test-d.ts

+9
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ const options: tempy.FileOptions = {}; // eslint-disable-line @typescript-eslint
55
expectType<string>(tempy.directory());
66
expectType<string>(tempy.directory({prefix: 'name_'}));
77
expectType<string>(tempy.file());
8+
expectType<Promise<void>>(tempy.file.task(temporaryFile => {
9+
expectType<string>(temporaryFile);
10+
}));
11+
expectType<Promise<void>>(tempy.directory.task(temporaryDirectory => {
12+
expectType<string>(temporaryDirectory);
13+
}));
814
expectType<string>(tempy.file({extension: 'png'}));
915
expectType<string>(tempy.file({name: 'afile.txt'}));
1016
expectError(tempy.file({extension: 'png', name: 'afile.txt'}));
@@ -14,6 +20,9 @@ expectType<Promise<string>>(tempy.write('unicorn'));
1420
expectType<Promise<string>>(tempy.write('unicorn', {name: 'pony.png'}));
1521
expectType<Promise<string>>(tempy.write(process.stdin, {name: 'pony.png'}));
1622
expectType<Promise<string>>(tempy.write(Buffer.from('pony'), {name: 'pony.png'}));
23+
expectType<Promise<void>>(tempy.write.task('', temporaryFile => {
24+
expectType<string>(temporaryFile);
25+
}));
1726

1827
expectType<string>(tempy.writeSync('unicorn'));
1928
expectType<string>(tempy.writeSync(Buffer.from('unicorn')));

‎package.json

+3
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,16 @@
3535
"unique"
3636
],
3737
"dependencies": {
38+
"del": "^5.1.0",
3839
"is-stream": "^2.0.0",
3940
"temp-dir": "^2.0.0",
4041
"type-fest": "^0.16.0",
4142
"unique-string": "^2.0.0"
4243
},
4344
"devDependencies": {
4445
"ava": "^2.4.0",
46+
"path-exists": "^4.0.0",
47+
"touch": "^3.1.0",
4548
"tsd": "^0.13.1",
4649
"xo": "^0.32.1"
4750
},

‎readme.md

+30-7
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,16 @@ tempy.directory({prefix: 'name'});
3535

3636
Get a temporary file path you can write to.
3737

38+
### tempy.file.task(callback, options?)
39+
40+
The `callback` resolves with a temporary file path you can write to. The file is automatically cleaned up after the callback is executed. Returns a promise that resolves after the callback is executed and the file is cleaned up.
41+
42+
#### callback
43+
44+
Type: `(tempPath: string) => void`
45+
46+
A callback that is executed with the temp file path. Can be asynchronous.
47+
3848
#### options
3949

4050
Type: `object`
@@ -57,13 +67,22 @@ Filename. Mutually exclusive with the `extension` option.
5767

5868
Get a temporary directory path. The directory is created for you.
5969

70+
### tempy.directory.task(callback, options?)
71+
72+
The `callback` resolves with a temporary directory path you can write to. The directory is automatically cleaned up after the callback is executed. Returns a promise that resolves after the callback is executed and the directory is cleaned up.
73+
74+
##### callback
75+
76+
Type: `(tempPath: string) => void`
77+
78+
A callback that is executed with the temp directory path. Can be asynchronous.
79+
6080
#### options
6181

6282
Type: `Object`
6383

6484
##### prefix
6585

66-
6786
Type: `string`
6887

6988
Directory prefix.
@@ -76,12 +95,22 @@ Useful for testing by making it easier to identify cache directories that are cr
7695

7796
Write data to a random temp file.
7897

98+
### tempy.write.task(fileContent, callback, options?)
99+
100+
Write data to a random temp file. The file is automatically cleaned up after the callback is executed. Returns a promise that resolves after the callback is executed and the file is cleaned up.
101+
79102
##### fileContent
80103

81104
Type: `string | Buffer | TypedArray | DataView | stream.Readable`
82105

83106
Data to write to the temp file.
84107

108+
##### callback
109+
110+
Type: `(tempPath: string) => void`
111+
112+
A callback that is executed with the temp file path. Can be asynchronous.
113+
85114
##### options
86115

87116
See [options](#options).
@@ -103,9 +132,3 @@ See [options](#options).
103132
### tempy.root
104133

105134
Get the root temporary directory path. For example: `/private/var/folders/3x/jf5977fn79jbglr7rk0tq4d00000gn/T`
106-
107-
## FAQ
108-
109-
#### Why doesn't it have a cleanup method?
110-
111-
Temp files will be periodically cleaned up on macOS. Most Linux distros will clean up on reboot. If you're generating a lot of temp files, it's recommended to use a complementary module like [`del`](https://github.com/sindresorhus/del) for cleanup.

‎test.js

+27
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import path from 'path';
22
import tempDir from 'temp-dir';
3+
import pathExists from 'path-exists';
4+
import touch from 'touch';
35
import fs from 'fs';
46
import stream from 'stream';
57
import test from 'ava';
@@ -32,19 +34,44 @@ test('.file()', t => {
3234
});
3335
});
3436

37+
test('.file.task()', async t => {
38+
let temporaryFilePath;
39+
await tempy.file.task(async temporaryFile => {
40+
await touch(temporaryFile);
41+
temporaryFilePath = temporaryFile;
42+
});
43+
t.false(await pathExists(temporaryFilePath));
44+
});
45+
3546
test('.directory()', t => {
3647
const prefix = 'name_';
3748

3849
t.true(tempy.directory().includes(tempDir));
3950
t.true(path.basename(tempy.directory({prefix})).startsWith(prefix));
4051
});
4152

53+
test('.directory.task()', async t => {
54+
let temporaryDirectoryPath;
55+
await tempy.directory.task(async temporaryDirectory => {
56+
temporaryDirectoryPath = temporaryDirectory;
57+
});
58+
t.false(await pathExists(temporaryDirectoryPath));
59+
});
60+
4261
test('.write(string)', async t => {
4362
const filePath = await tempy.write('unicorn', {name: 'test.png'});
4463
t.is(fs.readFileSync(filePath, 'utf8'), 'unicorn');
4564
t.is(path.basename(filePath), 'test.png');
4665
});
4766

67+
test('.write.task(string)', async t => {
68+
let temporaryFilePath;
69+
await tempy.write.task('', async temporaryFile => {
70+
temporaryFilePath = temporaryFile;
71+
});
72+
t.false(await pathExists(temporaryFilePath));
73+
});
74+
4875
test('.write(buffer)', async t => {
4976
const filePath = await tempy.write(Buffer.from('unicorn'));
5077
t.is(fs.readFileSync(filePath, 'utf8'), 'unicorn');

0 commit comments

Comments
 (0)
Please sign in to comment.