Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement context and contextSync #15

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
node_modules
yarn.lock
wallaby.js
coverage
.nyc_output
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
language: node_js
node_js:
- '12'
- '10'
- '8'
63 changes: 62 additions & 1 deletion index.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {MergeExclusive} from 'type-fest';
import {MergeExclusive, Merge} from 'type-fest';
import {Options as DelOptions} from 'del';

declare namespace tempy {
type Options = MergeExclusive<
Expand All @@ -19,6 +20,28 @@ declare namespace tempy {
readonly name?: string;
}
>;
type ContextOptions = Merge<
/**
ContextOptions
*/
{
/**
keep temp directory after leaving context
@default false
*/
keepDir?: boolean;
},
{
/**
* context call will pass `delOptions` opts key to del package when called
* like this:
* "tempy.context({ delOptions: { force: false, dryrun: true ... } }, directory => { ... })
* @default "{ force: true }"
* default will force del to delete tempy context unless you pass different opts to it
*/
readonly delOptions?: DelOptions;
}
>
}

declare const tempy: {
Expand Down Expand Up @@ -58,6 +81,44 @@ declare const tempy: {
directory(): string;

/**
*
* @param options
* @returns tempy context dirname
*/

contextSync(options?: tempy.ContextOptions): string;
/**
*
* @param options
* @param callback
*/

contextSync(options?: tempy.ContextOptions, callback?: Function): void;
/**
*
* @param callback
*/

contextSync(callback?: Function): void;


/**
*
* @param options
* @see tempy.ContextOptions
* @returns a temp dir location and a function to call when you need to clean it up
*/

context(options?: tempy.ContextOptions): Promise<[string, Function]>;
/**
*
* @param options
* @returns a temp dir location and a function to call when you need to clean it up
*/

context(): Promise<[string, Function]>;

/**
Get the root temporary directory path. For example: `/private/var/folders/3x/jf5977fn79jbglr7rk0tq4d00000gn/T`.
*/
readonly root: string;
Expand Down
37 changes: 37 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ const fs = require('fs');
const path = require('path');
const uniqueString = require('unique-string');
const tempDir = require('temp-dir');
const del = require('del');
const once = require('once');

const getPath = () => path.join(tempDir, uniqueString());

Expand All @@ -29,6 +31,41 @@ module.exports.directory = () => {
return directory;
};

module.exports.contextSync = (opts, callback) => {
const defaultDelOpts = {force: true};
let _cb = callback;
let _opts = opts;

if (typeof opts === 'function') {
_cb = opts;
_opts = {keepDir: false, delOpts: defaultDelOpts};
}

const directory = module.exports.directory();
if (!_cb) {
return directory;
}

_cb(directory);

if (_opts.keepDir !== true) {
del.sync(directory, _opts.delOpts || defaultDelOpts);
}
};

module.exports.context = async (opts = {keepDir: false, delOpts: {force: true}}) => {
const directory = module.exports.directory();
return [directory, once(done)];

function done() {
if (opts.keepDir !== true) {
return del(directory, opts.delOpts || {force: true});
}

return Promise.resolve([]);
}
};

Object.defineProperty(module.exports, 'root', {
get() {
return tempDir;
Expand Down
11 changes: 11 additions & 0 deletions index.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,14 @@ expectType<string>(tempy.file({extension: 'png'}));
expectType<string>(tempy.file({name: 'afile.txt'}));
expectError(tempy.file({extension: 'png', name: 'afile.txt'}));
expectType<string>(tempy.root);

expectType<string>(tempy.contextSync());
expectType<void>(tempy.contextSync((dir: string) => {
expectType<string>(dir);
}));
expectType<void>(tempy.contextSync({}, (dir: string) => {
expectType<string>(dir);
}));

expectType<Promise<[string, Function]>>(tempy.context());
expectType<Promise<[string, Function]>>(tempy.context({ keepDir: true }));
8 changes: 6 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@
"author": {
"name": "Sindre Sorhus",
"email": "sindresorhus@gmail.com",
"url": "sindresorhus.com"
"url": "https://sindresorhus.com"
},
"engines": {
"node": ">=8"
},
"scripts": {
"test": "xo && ava && tsd"
"test": "xo && ava && tsd",
"coverage": "nyc ava && nyc report --reporter=html"
},
"files": [
"index.js",
Expand All @@ -35,12 +36,15 @@
"uniq"
],
"dependencies": {
"del": "^5.1.0",
"once": "^1.4.0",
"temp-dir": "^1.0.0",
"type-fest": "^0.3.1",
"unique-string": "^1.0.0"
},
"devDependencies": {
"ava": "^1.4.1",
"nyc": "^14.1.1",
"tsd": "^0.7.2",
"xo": "^0.24.0"
}
Expand Down
65 changes: 62 additions & 3 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,71 @@ Get a temporary directory path. The directory is created for you.

Get the root temporary directory path. For example: `/private/var/folders/3x/jf5977fn79jbglr7rk0tq4d00000gn/T`

### tempy.contextSync(cb)

## FAQ
Get the sync context

```js
tempy.contextSync((directoryPath) => {
// do something with temp directory
})
// directory is then deleted here
```

you can also preserve the dir after the context by explicitly setting `keepDir` to `true`:
```js
const directory = tempy.contextSync({ keepDir: true })
// it's basically equivalent to // tempy.directory()

// or

tempy.contextSync({ keepDir: true }, directory => {
// directory is preserved here
})
// AND also here

```

Context: Promise version

```js
let myDir
let onDone

tempy.context()
.then(([tempDirectory, done]) => {
// assign to local vars, we need it for later
myDir = tempDirectory
onDone = done
})
.then(() => {
// a long task using myDir...
})
.then(() => {
// another long task using myDir...
})
.then(() => {
// call done when you are done with it!
onDone()
})
.then(() => {
// myDir is deleted now
})
```

Context: Using async/await api

```js

const [tempDir, cleanUp] = await tempy.context()
// do something with tempDir here
await cleanUp()
// call cleanUp and tempDir is gone forever

```

### Why doesn't it have a cleanup method?

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 [`rimraf`](https://github.com/isaacs/rimraf) for cleanup.
Note: deletion is made with [del](https://github.com/sindresorhus/del)


## Related
Expand Down
81 changes: 81 additions & 0 deletions test.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import {existsSync, rmdirSync} from 'fs';
import path from 'path';
import {tmpdir} from 'os';
import test from 'ava';
Expand All @@ -9,6 +10,11 @@ test('.file()', t => {
t.true(tempy.file({extension: '.png'}).endsWith('.png'));
t.false(tempy.file({extension: '.png'}).endsWith('..png'));
t.true(tempy.file({name: 'custom-name.md'}).endsWith('custom-name.md'));
t.throws(
() => tempy.file({name: 'fiat', extension: 'lux'}),
/The `name` and `extension` options are mutually exclusive/,
'expect error message match on mutually exclusive opts'
);
});

test('.directory()', t => {
Expand All @@ -22,3 +28,78 @@ test('.root', t => {
tempy.root = 'foo';
});
});

test('.contextSync()', t => {
t.plan(2);
const directory = tempy.contextSync();
t.true(existsSync(directory));

rmdirSync(directory);
t.false(existsSync(directory), 'expected test cleanup');
});

test('.contextSync((opts, (directory) => ...))', t => {
t.plan(2);
let tmp;
tempy.contextSync({keepDir: false}, directory => {
// Do something with tmp directory
tmp = directory;
t.true(existsSync(tmp));
});
t.false(existsSync(tmp));
});

test('.contextSync((directory) => ...)', t => {
t.plan(2);
let tmp;
tempy.contextSync(directory => {
// Do something with tmp directory
tmp = directory;
t.true(existsSync(tmp));
});
t.false(existsSync(tmp));
});

test('.contextSync(({ keepDir = "true" }, (directory) => ...))', t => {
t.plan(3);
let tmp;
tempy.contextSync({keepDir: true}, directory => {
// Do something with tmp directory
tmp = directory;
t.true(existsSync(tmp));
});
t.true(existsSync(tmp));

rmdirSync(tmp);
t.false(existsSync(tmp), 'expected test cleanup');
});

test('.context().then((dir, done) => ...)', async t => {
t.plan(3);
const [dir, done] = await tempy.context();
t.true(existsSync(dir));
const deleted = await done();
t.false(existsSync(dir));
t.deepEqual(dir, deleted[0]);
});

test('.context({}).then((dir, done) => ...)', async t => {
t.plan(3);
const [dir, done] = await tempy.context({});
t.true(existsSync(dir));
const deleted = await done();
t.false(existsSync(dir));
t.deepEqual(dir, deleted[0]);
});

test('.context({ keepDir: "true" }).then((dir, done) => ...', async t => {
t.plan(4);
const [dir, done] = await tempy.context({keepDir: true});
t.true(existsSync(dir));
const deleted = await done();
t.true(existsSync(dir));
t.deepEqual(deleted, []);

rmdirSync(dir);
t.false(existsSync(dir), 'expected test cleanup');
});