Skip to content

Commit

Permalink
Require Node.js 8
Browse files Browse the repository at this point in the history
  • Loading branch information
sindresorhus committed May 21, 2019
1 parent 73b8041 commit 0e5f6ad
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 81 deletions.
18 changes: 7 additions & 11 deletions index.d.ts
@@ -1,15 +1,14 @@
declare namespace writeJsonFile {
type Replacer = (this: unknown, key: string, value: any) => unknown;
type SortKeys = (a: string, b: string) => number;
type JSONStringifyable = string | number | boolean | null | object;

interface Options {
/**
Indentation as a string or number of spaces. Pass in null for no formatting.
Indentation as a string or number of spaces. Pass in `undefined` for no formatting.
@default '\t'
*/
readonly indent?: string | number | null;
readonly indent?: string | number | undefined;

/**
Detect indentation automatically if the file exists.
Expand All @@ -28,7 +27,7 @@ declare namespace writeJsonFile {
/**
Passed into `JSON.stringify`.
*/
readonly replacer?: Replacer | Array<number | string>;
readonly replacer?: Replacer | ReadonlyArray<number | string>;

/**
Mode used when writing the file.
Expand All @@ -55,8 +54,8 @@ declare const writeJsonFile: {
```
*/
(
filepath: string,
data: writeJsonFile.JSONStringifyable,
filePath: string,
data: unknown,
options?: writeJsonFile.Options
): Promise<void>;

Expand All @@ -73,13 +72,10 @@ declare const writeJsonFile: {
```
*/
sync(
filepath: string,
data: writeJsonFile.JSONStringifyable,
filePath: string,
data: unknown,
options?: writeJsonFile.Options
): void;

// TODO: Remove this for the next major release
default: typeof writeJsonFile;
};

export = writeJsonFile;
44 changes: 26 additions & 18 deletions index.js
@@ -1,12 +1,15 @@
'use strict';
const {promisify} = require('util');
const path = require('path');
const fs = require('graceful-fs');
const writeFileAtomic = require('write-file-atomic');
const sortKeys = require('sort-keys');
const makeDir = require('make-dir');
const pify = require('pify');
const detectIndent = require('detect-indent');

const readFile = promisify(fs.readFile);
const writeFileAtomicP = promisify(writeFileAtomic);

const init = (fn, filePath, data, options) => {
if (!filePath) {
throw new TypeError('Expected a filepath');
Expand All @@ -16,10 +19,11 @@ const init = (fn, filePath, data, options) => {
throw new TypeError('Expected data to stringify');
}

options = Object.assign({
options = {
indent: '\t',
sortKeys: false
}, options);
sortKeys: false,
...options
};

if (options.sortKeys) {
data = sortKeys(data, {
Expand All @@ -31,16 +35,23 @@ const init = (fn, filePath, data, options) => {
return fn(filePath, data, options);
};

const readFile = filePath => pify(fs.readFile)(filePath, 'utf8').catch(() => {});
const main = async (filePath, data, options) => {
let {indent} = options;

if (options.detectIndent) {
try {
const file = await readFile(filePath, 'utf8');
indent = detectIndent(file).indent;
} catch (error) {
if (error.code !== 'ENOENT') {
throw error;
}
}
}

const main = (filePath, data, options) => {
return (options.detectIndent ? readFile(filePath) : Promise.resolve())
.then(string => {
const indent = string ? detectIndent(string).indent : options.indent;
const json = JSON.stringify(data, options.replacer, indent);
const json = JSON.stringify(data, options.replacer, indent);

return pify(writeFileAtomic)(filePath, `${json}\n`, {mode: options.mode});
});
return writeFileAtomicP(filePath, `${json}\n`, {mode: options.mode});
};

const mainSync = (filePath, data, options) => {
Expand All @@ -62,14 +73,11 @@ const mainSync = (filePath, data, options) => {
return writeFileAtomic.sync(filePath, `${json}\n`, {mode: options.mode});
};

const writeJsonFile = (filePath, data, options) => {
return makeDir(path.dirname(filePath), {fs})
.then(() => init(main, filePath, data, options));
module.exports = async (filePath, data, options) => {
await makeDir(path.dirname(filePath), {fs});
return init(main, filePath, data, options);
};

module.exports = writeJsonFile;
// TODO: Remove this for the next major release
module.exports.default = writeJsonFile;
module.exports.sync = (filePath, data, options) => {
makeDir.sync(path.dirname(filePath), {fs});
init(mainSync, filePath, data, options);
Expand Down
9 changes: 1 addition & 8 deletions index.test-d.ts
@@ -1,13 +1,6 @@
import {expectType} from 'tsd';
import writeJsonFile = require('.');
import {sync, Replacer, SortKeys, JSONStringifyable} from '.';

expectType<JSONStringifyable>('🦄');
expectType<JSONStringifyable>(1);
expectType<JSONStringifyable>(true);
expectType<JSONStringifyable>(new Date());
expectType<JSONStringifyable>(['hello', 'world']);
expectType<JSONStringifyable>({unicorn: '🦄'});
import {sync, Replacer, SortKeys} from '.';

expectType<SortKeys>(() => 1);
expectType<SortKeys>((a: string) => a.length);
Expand Down
13 changes: 6 additions & 7 deletions package.json
Expand Up @@ -10,7 +10,7 @@
"url": "sindresorhus.com"
},
"engines": {
"node": ">=6"
"node": ">=8"
},
"scripts": {
"test": "xo && ava && tsd"
Expand All @@ -34,17 +34,16 @@
"atomically"
],
"dependencies": {
"detect-indent": "^5.0.0",
"detect-indent": "^6.0.0",
"graceful-fs": "^4.1.15",
"make-dir": "^2.1.0",
"pify": "^4.0.1",
"sort-keys": "^2.0.0",
"make-dir": "^3.0.0",
"sort-keys": "^3.0.0",
"write-file-atomic": "^2.4.2"
},
"devDependencies": {
"ava": "^1.4.1",
"tempfile": "^2.0.0",
"tsd": "^0.7.2",
"tempy": "^0.3.0",
"tsd": "^0.7.3",
"xo": "^0.24.0"
}
}
11 changes: 6 additions & 5 deletions readme.md
Expand Up @@ -33,15 +33,16 @@ Returns a `Promise`.

#### options

Type: `Object`
Type: `object`

##### indent

Type: `string` `number`<br>
Type: `string | number`<br>
Default: `'\t'`

Indentation as a string or number of spaces.<br>
Pass in `null` for no formatting.
Indentation as a string or number of spaces.

Pass in `undefined` for no formatting.

##### detectIndent

Expand All @@ -52,7 +53,7 @@ Detect indentation automatically if the file exists.

##### sortKeys

Type: `boolean` `Function`<br>
Type: `boolean | Function`<br>
Default: `false`

Sort the keys recursively.<br>
Expand Down
63 changes: 31 additions & 32 deletions test.js
@@ -1,61 +1,60 @@
import path from 'path';
import fs from 'fs';
import test from 'ava';
import tempfile from 'tempfile';
import m from '.';
import tempy from 'tempy';
import writeJsonFile from '.';

test('async', async t => {
const tmp = path.join(tempfile(), 'foo');
await m(tmp, {foo: true}, {indent: 2});
t.is(fs.readFileSync(tmp, 'utf8'), '{\n "foo": true\n}\n');
const tempFile = tempy.file();
await writeJsonFile(tempFile, {foo: true}, {indent: 2});
t.is(fs.readFileSync(tempFile, 'utf8'), '{\n "foo": true\n}\n');
});

test('sync', t => {
const tmp = path.join(tempfile(), 'foo');
m.sync(tmp, {foo: true}, {detectIndent: true, indent: 2});
t.is(fs.readFileSync(tmp, 'utf8'), '{\n "foo": true\n}\n');
const tempFile = tempy.file();
writeJsonFile.sync(tempFile, {foo: true}, {detectIndent: true, indent: 2});
t.is(fs.readFileSync(tempFile, 'utf8'), '{\n "foo": true\n}\n');
});

test('detect indent', async t => {
const tmp = path.join(tempfile(), 'foo');
await m(tmp, {foo: true}, {indent: 2});
await m(tmp, {foo: true, bar: true, foobar: true}, {detectIndent: true});
t.is(fs.readFileSync(tmp, 'utf8'), '{\n "foo": true,\n "bar": true,\n "foobar": true\n}\n');
const tempFile = tempy.file();
await writeJsonFile(tempFile, {foo: true}, {indent: 2});
await writeJsonFile(tempFile, {foo: true, bar: true, foobar: true}, {detectIndent: true});
t.is(fs.readFileSync(tempFile, 'utf8'), '{\n "foo": true,\n "bar": true,\n "foobar": true\n}\n');
});

test('detect indent synchronously', t => {
const tmp = path.join(tempfile(), 'foo');
m.sync(tmp, {foo: true}, {indent: 2});
m.sync(tmp, {foo: true, bar: true, foobar: true}, {detectIndent: true});
t.is(fs.readFileSync(tmp, 'utf8'), '{\n "foo": true,\n "bar": true,\n "foobar": true\n}\n');
const tempFile = tempy.file();
writeJsonFile.sync(tempFile, {foo: true}, {indent: 2});
writeJsonFile.sync(tempFile, {foo: true, bar: true, foobar: true}, {detectIndent: true});
t.is(fs.readFileSync(tempFile, 'utf8'), '{\n "foo": true,\n "bar": true,\n "foobar": true\n}\n');
});

test('fall back to default indent if file doesn\'t exist', async t => {
const tmp = path.join(tempfile(), 'foo');
await m(tmp, {foo: true, bar: true, foobar: true}, {detectIndent: true});
t.is(fs.readFileSync(tmp, 'utf8'), '{\n\t"foo": true,\n\t"bar": true,\n\t"foobar": true\n}\n');
const tempFile = tempy.file();
await writeJsonFile(tempFile, {foo: true, bar: true, foobar: true}, {detectIndent: true});
t.is(fs.readFileSync(tempFile, 'utf8'), '{\n\t"foo": true,\n\t"bar": true,\n\t"foobar": true\n}\n');
});

test('async - {sortKeys: true}', async t => {
const tmp = path.join(tempfile(), 'foo');
await m(tmp, {c: true, b: true, a: true}, {sortKeys: true});
t.is(fs.readFileSync(tmp, 'utf8'), '{\n\t"a": true,\n\t"b": true,\n\t"c": true\n}\n');
const tempFile = tempy.file();
await writeJsonFile(tempFile, {c: true, b: true, a: true}, {sortKeys: true});
t.is(fs.readFileSync(tempFile, 'utf8'), '{\n\t"a": true,\n\t"b": true,\n\t"c": true\n}\n');
});

test('async - {sortKeys: false}', async t => {
const tmp = path.join(tempfile(), 'foo');
await m(tmp, {c: true, b: true, a: true}, {sortKeys: false});
t.is(fs.readFileSync(tmp, 'utf8'), '{\n\t"c": true,\n\t"b": true,\n\t"a": true\n}\n');
const tempFile = tempy.file();
await writeJsonFile(tempFile, {c: true, b: true, a: true}, {sortKeys: false});
t.is(fs.readFileSync(tempFile, 'utf8'), '{\n\t"c": true,\n\t"b": true,\n\t"a": true\n}\n');
});

test('async - `replacer` option', async t => {
const tmp = path.join(tempfile(), 'foo');
await m(tmp, {foo: true, bar: true}, {replacer: ['foo']});
t.is(fs.readFileSync(tmp, 'utf8'), '{\n\t"foo": true\n}\n');
const tempFile = tempy.file();
await writeJsonFile(tempFile, {foo: true, bar: true}, {replacer: ['foo']});
t.is(fs.readFileSync(tempFile, 'utf8'), '{\n\t"foo": true\n}\n');
});

test('sync - `replacer` option', t => {
const tmp = path.join(tempfile(), 'foo');
m.sync(tmp, {foo: true, bar: true}, {replacer: ['foo']});
t.is(fs.readFileSync(tmp, 'utf8'), '{\n\t"foo": true\n}\n');
const tempFile = tempy.file();
writeJsonFile.sync(tempFile, {foo: true, bar: true}, {replacer: ['foo']});
t.is(fs.readFileSync(tempFile, 'utf8'), '{\n\t"foo": true\n}\n');
});

0 comments on commit 0e5f6ad

Please sign in to comment.