Skip to content

Commit

Permalink
Require Node.js 12.20 and move to ESM
Browse files Browse the repository at this point in the history
Fixes #23
  • Loading branch information
sindresorhus committed Aug 30, 2021
1 parent e99664d commit 9138c28
Show file tree
Hide file tree
Showing 8 changed files with 83 additions and 101 deletions.
7 changes: 2 additions & 5 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,10 @@ jobs:
fail-fast: false
matrix:
node-version:
- 14
- 12
- 10
- 8
- 16
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
- uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
- run: npm install
Expand Down
83 changes: 38 additions & 45 deletions index.d.ts
Original file line number Diff line number Diff line change
@@ -1,55 +1,48 @@
import {JsonValue} from 'type-fest';

declare namespace loadJsonFile {
type Reviver = (this: unknown, key: string, value: any) => unknown;
type BeforeParse = (data: string) => string;

interface Options {
/**
Applies a function to the JSON string before parsing.
*/
readonly beforeParse?: BeforeParse;

/**
Prescribes how the value originally produced by parsing is transformed, before being returned.
See the [`JSON.parse` docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse#Using_the_reviver_parameter) for more.
*/
readonly reviver?: Reviver;
}
}
// From https://github.com/sindresorhus/type-fest
export type JsonValue = string | number | boolean | null | {[Key in string]?: JsonValue} | JsonValue[];

export type Reviver = (this: unknown, key: string, value: unknown) => unknown;
export type BeforeParse = (data: string) => string;

export interface Options {
/**
Applies a function to the JSON string before parsing.
*/
readonly beforeParse?: BeforeParse;

declare const loadJsonFile: {
/**
Read and parse a JSON file.
Prescribes how the value originally produced by parsing is transformed, before being returned.
See the [`JSON.parse` docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse#Using_the_reviver_parameter) for more.
*/
readonly reviver?: Reviver;
}

Strips UTF-8 BOM, uses graceful-fs, and throws more helpful JSON errors.
/**
Read and parse a JSON file.
@example
```
import loadJsonFile = require('load-json-file');
It also strips UTF-8 BOM.
(async () => {
const json = await loadJsonFile('foo.json');
//=> {foo: true}
})();
```
*/
<ReturnValueType = JsonValue>(filePath: string, options?: loadJsonFile.Options): Promise<ReturnValueType>;
@example
```
import {loadJsonFile} from 'load-json-file';
/**
Read and parse a JSON file.
const json = await loadJsonFile('foo.json');
//=> {foo: true}
```
*/
export function loadJsonFile<ReturnValueType = JsonValue>(filePath: string, options?: Options): Promise<ReturnValueType>;

Strips UTF-8 BOM, uses graceful-fs, and throws more helpful JSON errors.
/**
Read and parse a JSON file.
@example
```
import loadJsonFile = require('load-json-file');
It also strips UTF-8 BOM.
const json = loadJsonFile.sync('foo.json');
//=> {foo: true}
```
*/
sync<ReturnValueType = JsonValue>(filePath: string, options?: loadJsonFile.Options): ReturnValueType;
};
@example
```
import {loadJsonFileSync} from 'load-json-file';
export = loadJsonFile;
const json = loadJsonFileSync('foo.json');
//=> {foo: true}
```
*/
export function loadJsonFileSync<ReturnValueType = JsonValue>(filePath: string, options?: Options): ReturnValueType;
30 changes: 17 additions & 13 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
'use strict';
const path = require('path');
const {promisify} = require('util');
const fs = require('graceful-fs');
const stripBom = require('strip-bom');
const parseJson = require('parse-json');
import {readFileSync} from 'node:fs';
import {readFile} from 'node:fs/promises';

const parse = (data, filePath, options = {}) => {
data = stripBom(data);
const parse = (buffer, {beforeParse, reviver} = {}) => {
// Unlike `buffer.toString()` and `fs.readFile(path, 'utf8')`, `TextDecoder`` will remove BOM.
let data = new TextDecoder().decode(buffer);

if (typeof options.beforeParse === 'function') {
data = options.beforeParse(data);
if (typeof beforeParse === 'function') {
data = beforeParse(data);
}

return parseJson(data, options.reviver, path.relative(process.cwd(), filePath));
return JSON.parse(data, reviver);
};

module.exports = async (filePath, options) => parse(await promisify(fs.readFile)(filePath, 'utf8'), filePath, options);
module.exports.sync = (filePath, options) => parse(fs.readFileSync(filePath, 'utf8'), filePath, options);
export async function loadJsonFile(filePath, options) {
const buffer = await readFile(filePath);
return parse(buffer, options);
}

export function loadJsonFileSync(filePath, options) {
const buffer = readFileSync(filePath);
return parse(buffer, options);
}
13 changes: 5 additions & 8 deletions index.test-d.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
import {expectType} from 'tsd';
import {expectType, expectAssignable} from 'tsd';
import {JsonValue} from 'type-fest';
import loadJsonFile = require('.');
import {Reviver, BeforeParse} from '.';
import {loadJsonFile, loadJsonFileSync, Reviver, BeforeParse} from './index.js';

expectType<Reviver>(() => 1);
expectType<Reviver>((a: string) => a.length);
expectType<Reviver>((a: string, b: string) => a.length - b.length);
expectAssignable<Reviver>(() => 1);

expectType<BeforeParse>(data => data);
expectType<BeforeParse>(data => data); // eslint-disable-line @typescript-eslint/no-unsafe-return

expectType<Promise<JsonValue>>(loadJsonFile('unicorn.json'));

expectType<JsonValue>(loadJsonFile.sync('unicorn.json'));
expectType<JsonValue>(loadJsonFileSync('unicorn.json'));
2 changes: 1 addition & 1 deletion license
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) Sindre Sorhus <[email protected]> (sindresorhus.com)
Copyright (c) Sindre Sorhus <[email protected]> (https://sindresorhus.com)

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

Expand Down
20 changes: 8 additions & 12 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@
"description": "Read and parse a JSON file",
"license": "MIT",
"repository": "sindresorhus/load-json-file",
"funding": "https://github.com/sponsors/sindresorhus",
"author": {
"name": "Sindre Sorhus",
"email": "[email protected]",
"url": "sindresorhus.com"
"url": "https://sindresorhus.com"
},
"type": "module",
"exports": "./index.js",
"engines": {
"node": ">=8"
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"scripts": {
"test": "xo && ava && tsd"
Expand All @@ -25,18 +28,11 @@
"parse",
"file",
"fs",
"graceful",
"load"
],
"dependencies": {
"graceful-fs": "^4.1.15",
"parse-json": "^5.0.0",
"strip-bom": "^4.0.0",
"type-fest": "^0.6.0"
},
"devDependencies": {
"ava": "^2.1.0",
"tsd": "^0.7.3",
"xo": "^0.24.0"
"ava": "^3.15.0",
"tsd": "^0.17.0",
"xo": "^0.44.0"
}
}
17 changes: 5 additions & 12 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,30 @@

> Read and parse a JSON file
[Strips UTF-8 BOM](https://github.com/sindresorhus/strip-bom), uses [`graceful-fs`](https://github.com/isaacs/node-graceful-fs), and throws more [helpful JSON errors](https://github.com/sindresorhus/parse-json).

It also [strips UTF-8 BOM](https://github.com/sindresorhus/strip-bom).

## Install

```
$ npm install load-json-file
```


## Usage

```js
const loadJsonFile = require('load-json-file');
import {loadJsonFile} from 'load-json-file';

(async () => {
console.log(await loadJsonFile('foo.json'));
//=> {foo: true}
})();
console.log(await loadJsonFile('foo.json'));
//=> {foo: true}
```


## API

### loadJsonFile(filePath, options?)

Returns a `Promise<unknown>` with the parsed JSON.

### loadJsonFile.sync(filepath, options?)
### loadJsonFileSync(filepath, options?)

Returns the parsed JSON.

Expand All @@ -50,14 +45,12 @@ Type: `Function`

Prescribes how the value originally produced by parsing is transformed, before being returned. See the [`JSON.parse` docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse#Using_the_reviver_parameter) for more.


## load-json-file for enterprise

Available as part of the Tidelift Subscription.

The maintainers of load-json-file and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. [Learn more.](https://tidelift.com/subscription/pkg/npm-load-json-file?utm_source=npm-load-json-file&utm_medium=referral&utm_campaign=enterprise&utm_term=repo)


## Related

- [write-json-file](https://github.com/sindresorhus/write-json-file) - Stringify and write JSON to a file atomically
12 changes: 7 additions & 5 deletions test.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import path from 'path';
import path from 'node:path';
import {fileURLToPath} from 'node:url';
import test from 'ava';
import loadJsonFile from '.';
import {loadJsonFile, loadJsonFileSync} from './index.js';

const __dirname = path.dirname(fileURLToPath(import.meta.url));
const fixture = path.join(__dirname, 'package.json');

test('async', async t => {
Expand All @@ -10,19 +12,19 @@ test('async', async t => {
});

test('sync', t => {
t.is(loadJsonFile.sync(fixture).name, 'load-json-file');
t.is(loadJsonFileSync(fixture).name, 'load-json-file');
});

test('beforeParse option', async t => {
const data = await loadJsonFile(fixture, {
beforeParse: string => string.replace('"name": "load-json-file"', '"name": "foo"')
beforeParse: string => string.replace('"name": "load-json-file"', '"name": "foo"'),
});
t.is(data.name, 'foo');
});

test('reviver option', async t => {
const data = await loadJsonFile(fixture, {
reviver: (key, value) => key === 'name' ? 'foo' : value
reviver: (key, value) => key === 'name' ? 'foo' : value,
});
t.is(data.name, 'foo');
});

0 comments on commit 9138c28

Please sign in to comment.