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

Add parsePackage method, bump dependencies, target Node 16 #29

Merged
merged 13 commits into from
Apr 7, 2023
6 changes: 4 additions & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ jobs:
fail-fast: false
matrix:
node-version:
- 19
- 18
- 16
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- run: npm install
Expand Down
26 changes: 18 additions & 8 deletions index.d.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import * as typeFest from 'type-fest';
import * as normalize from 'normalize-package-data';
/* eslint-disable @typescript-eslint/no-redundant-type-constituents */
import type {PackageJson as typeFestPackageJson} from 'type-fest';
import type {Package as normalizePackage} from 'normalize-package-data';

export interface Options {
export type Options = {
/**
Current working directory.

Expand All @@ -15,14 +16,20 @@ export interface Options {
@default true
*/
readonly normalize?: boolean;
}
};

export interface NormalizeOptions extends Options {
// eslint-disable-next-line @typescript-eslint/naming-convention
type _NormalizeOptions = {
readonly normalize?: true;
}
};

export type NormalizedPackageJson = PackageJson & normalize.Package;
export type PackageJson = typeFest.PackageJson;
export type NormalizeOptions = _NormalizeOptions & Options;

export type ParseOptions = Omit<Options, 'cwd'>;
export type NormalizeParseOptions = _NormalizeOptions & ParseOptions;

export type NormalizedPackageJson = PackageJson & normalizePackage;
export type PackageJson = typeFestPackageJson;

/**
@returns The parsed JSON.
Expand Down Expand Up @@ -57,3 +64,6 @@ console.log(readPackageSync({cwd: 'some-other-directory'});
*/
export function readPackageSync(options?: NormalizeOptions): NormalizedPackageJson;
export function readPackageSync(options: Options): PackageJson;

export function parsePackage(packageFile: PackageJson | string, options?: NormalizeParseOptions): NormalizedPackageJson;
export function parsePackage(packageFile: PackageJson | string, options: ParseOptions): PackageJson;
31 changes: 19 additions & 12 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,33 @@ import normalizePackageData from 'normalize-package-data';

const toPath = urlOrPath => urlOrPath instanceof URL ? fileURLToPath(urlOrPath) : urlOrPath;

export async function readPackage({cwd, normalize = true} = {}) {
cwd = toPath(cwd) || process.cwd();
const filePath = path.resolve(cwd, 'package.json');
const json = parseJson(await fsPromises.readFile(filePath, 'utf8'));
const getPackagePath = cwd => {
const packageDir = toPath(cwd) || process.cwd();
return path.resolve(packageDir, 'package.json');
};

const _readPackage = (file, normalize) => {
const json = typeof file === 'string'
? parseJson(file)
: file; // TODO: ensure `file` is an object here
tommy-mitchell marked this conversation as resolved.
Show resolved Hide resolved

if (normalize) {
normalizePackageData(json);
}

return json;
};

export async function readPackage({cwd, normalize = true} = {}) {
const packageFile = await fsPromises.readFile(getPackagePath(cwd), 'utf8');
return _readPackage(packageFile, normalize);
}

export function readPackageSync({cwd, normalize = true} = {}) {
cwd = toPath(cwd) || process.cwd();
const filePath = path.resolve(cwd, 'package.json');
const json = parseJson(fs.readFileSync(filePath, 'utf8'));

if (normalize) {
normalizePackageData(json);
}
const packageFile = fs.readFileSync(getPackagePath(cwd), 'utf8');
return _readPackage(packageFile, normalize);
}

return json;
export function parsePackage(packageFile, {normalize = true} = {}) {
return _readPackage(packageFile, normalize);
}
17 changes: 16 additions & 1 deletion index.test-d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import {expectType, expectError, expectAssignable} from 'tsd';
import {readPackage, readPackageSync, NormalizedPackageJson, PackageJson} from './index.js';
import {
readPackage,
readPackageSync,
parsePackage,
type NormalizedPackageJson,
type PackageJson,
} from './index.js';

expectError<NormalizedPackageJson>({});
expectAssignable<PackageJson>({});
Expand All @@ -19,3 +25,12 @@ expectType<PackageJson>(readPackageSync({normalize: false}));
expectError<NormalizedPackageJson>(readPackageSync({normalize: false}));
expectType<NormalizedPackageJson>(readPackageSync({cwd: '.'}));
expectType<NormalizedPackageJson>(readPackageSync({cwd: new URL('file:///path/to/cwd/')}));

expectType<NormalizedPackageJson>(parsePackage(''));
expectType<NormalizedPackageJson>(parsePackage({name: 'unicorn'}));
expectType<NormalizedPackageJson>(parsePackage('', {normalize: true}));
expectType<PackageJson>(parsePackage('', {normalize: false}));
expectType<PackageJson>(parsePackage({name: 'unicorn'}, {normalize: false}));
expectError(parsePackage());
expectError<NormalizedPackageJson>(parsePackage('', {normalize: false}));
expectError(parsePackage('', {cwd: '.'}));
16 changes: 8 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@
"type": "module",
"exports": "./index.js",
"engines": {
"node": ">=12.20"
"node": ">=16"
},
"scripts": {
"test": "xo && ava && tsd"
"test": "xo && tsd && cd test && ava"
},
"files": [
"index.js",
Expand All @@ -35,14 +35,14 @@
],
"dependencies": {
"@types/normalize-package-data": "^2.4.1",
"normalize-package-data": "^3.0.2",
"parse-json": "^5.2.0",
"type-fest": "^2.0.0"
"normalize-package-data": "^5.0.0",
"parse-json": "^6.0.2",
"type-fest": "^3.8.0"
},
"devDependencies": {
"ava": "^3.15.0",
"tsd": "^0.17.0",
"xo": "^0.44.0"
"ava": "^5.2.0",
"tsd": "^0.28.1",
"xo": "^0.54.0"
},
"xo": {
"ignores": [
tommy-mitchell marked this conversation as resolved.
Show resolved Hide resolved
Expand Down
21 changes: 21 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,27 @@ Default: `true`

[Normalize](https://github.com/npm/normalize-package-data#what-normalization-currently-entails) the package data.

### parsePackage(packageFile, options?)

Parses an object or string into JSON.

#### packageFile

Type: `object | string`\

An object or a stringified object to be parsed as package.json.
tommy-mitchell marked this conversation as resolved.
Show resolved Hide resolved

#### options

Type: `object`

##### normalize

Type: `boolean`\
Default: `true`

[Normalize](https://github.com/npm/normalize-package-data#what-normalization-currently-entails) the package data.

## Related

- [read-pkg-up](https://github.com/sindresorhus/read-pkg-up) - Read the closest package.json file
Expand Down
2 changes: 1 addition & 1 deletion test/package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "unicorn",
"name": "unicorn ",
"version": "1.0.0",
"type": "module"
}
52 changes: 47 additions & 5 deletions test/test.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import {fileURLToPath, pathToFileURL} from 'url';
import path from 'path';
import {fileURLToPath, pathToFileURL} from 'node:url';
import path from 'node:path';
import test from 'ava';
import {readPackage, readPackageSync} from '../index.js';
import {readPackage, readPackageSync, parsePackage} from '../index.js';

const dirname = path.dirname(fileURLToPath(import.meta.url));
process.chdir(dirname);
const dirname = path.dirname(fileURLToPath(test.meta.file));
const rootCwd = path.join(dirname, '..');

test('async', async t => {
Expand All @@ -22,6 +21,11 @@ test('async - cwd option', async t => {
);
});

test('async - normalize option', async t => {
const package_ = await readPackage({normalize: false});
t.is(package_.name, 'unicorn ');
});

test('sync', t => {
const package_ = readPackageSync();
t.is(package_.name, 'unicorn');
Expand All @@ -36,3 +40,41 @@ test('sync - cwd option', t => {
package_,
);
});

test('sync - normalize option', async t => {
const package_ = readPackageSync({normalize: false});
t.is(package_.name, 'unicorn ');
});

const pkgJson = {
name: 'unicorn ',
version: '1.0.0',
type: 'module',
};

test('parsePackage - json input', t => {
const package_ = parsePackage({...pkgJson});
tommy-mitchell marked this conversation as resolved.
Show resolved Hide resolved
t.is(package_.name, 'unicorn');
t.deepEqual(
readPackageSync(),
package_,
);
});

test('parsePackage - string input', t => {
const package_ = parsePackage(JSON.stringify(pkgJson));
t.is(package_.name, 'unicorn');
t.deepEqual(
readPackageSync(),
package_,
);
});

test('parsePackage - normalize option', t => {
const package_ = parsePackage({...pkgJson}, {normalize: false});
t.is(package_.name, 'unicorn ');
t.deepEqual(
readPackageSync({normalize: false}),
package_,
);
});