Skip to content

Commit

Permalink
Require Node.js 18
Browse files Browse the repository at this point in the history
  • Loading branch information
sindresorhus committed May 5, 2024
1 parent b48757a commit 7d8564f
Show file tree
Hide file tree
Showing 18 changed files with 66 additions and 111 deletions.
4 changes: 0 additions & 4 deletions .github/funding.yml

This file was deleted.

9 changes: 4 additions & 5 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,16 @@ jobs:
fail-fast: false
matrix:
node-version:
- 22
- 18
- 16
- 14
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: npm install --force
- run: npm test
- uses: codecov/codecov-action@v3
if: matrix.node-version == 16
if: matrix.node-version == 18
with:
fail_ci_if_error: true
46 changes: 23 additions & 23 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@
},
"sideEffects": false,
"engines": {
"node": ">=14.16"
"node": ">=18"
},
"scripts": {
"test": "xo && c8 ava",
"test": "xo && NODE_OPTIONS='--import=tsx/esm' c8 ava",
"docs": "typedoc source/index.ts",
"build": "del-cli dist && tsc",
"prepare": "npm run build",
Expand Down Expand Up @@ -58,25 +58,25 @@
"object"
],
"dependencies": {
"@sindresorhus/is": "^5.3.0",
"callsites": "^4.0.0",
"dot-prop": "^7.2.0",
"fast-equals": "^5.0.0",
"vali-date": "^1.0.0"
"@sindresorhus/is": "^6.3.0",
"callsites": "^4.1.0",
"dot-prop": "^8.0.2",
"environment": "^1.0.0",
"fast-equals": "^5.0.1",
"is-identifier": "^1.0.0"
},
"devDependencies": {
"@sindresorhus/tsconfig": "^3.0.1",
"@types/node": "^18.8.0",
"@types/vali-date": "^1.0.0",
"ava": "^4.3.3",
"c8": "^7.12.0",
"del-cli": "^5.0.0",
"expect-type": "^0.14.2",
"gh-pages": "^4.0.0",
"ts-node": "^10.9.1",
"typedoc": "^0.23.15",
"typescript": "^4.8.4",
"xo": "^0.52.3"
"@sindresorhus/tsconfig": "^5.0.0",
"@types/node": "^20.12.8",
"ava": "^6.1.2",
"c8": "^9.1.0",
"del-cli": "^5.1.0",
"expect-type": "^0.19.0",
"gh-pages": "^6.1.1",
"tsx": "^4.9.1",
"typedoc": "^0.25.13",
"typescript": "^5.4.5",
"xo": "^0.58.0"
},
"browser": {
"./dist/utils/infer-label.js": "./dist/utils/infer-label.browser.js"
Expand All @@ -93,7 +93,9 @@
"@typescript-eslint/ban-types": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-empty-function": "off",
"@typescript-eslint/restrict-template-expressions": "off"
"@typescript-eslint/restrict-template-expressions": "off",
"@typescript-eslint/no-unsafe-return": "off",
"@typescript-eslint/no-unsafe-argument": "off"
}
},
"ava": {
Expand All @@ -104,9 +106,7 @@
"extensions": {
"ts": "module"
},
"nodeArguments": [
"--loader=ts-node/esm"
]
"workerThreads": false
},
"c8": {
"reporter": [
Expand Down
8 changes: 0 additions & 8 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -307,14 +307,6 @@ const userPredicate = ow.object.exactShape({
type User = Infer<typeof userPredicate>;
```

## Maintainers

- [Sindre Sorhus](https://github.com/sindresorhus)

**Former:**

- [Sam Verschueren](https://github.com/SamVerschueren)

## Related

- [@sindresorhus/is](https://github.com/sindresorhus/is) - Type check values
Expand Down
2 changes: 1 addition & 1 deletion source/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export type ReusableValidator<T> = {
@param value - Value to test.
@param label - Override the label which should be used in error messages.
*/
// eslint-disable-next-line @typescript-eslint/prefer-function-type, @typescript-eslint/no-redundant-type-constituents
// eslint-disable-next-line @typescript-eslint/prefer-function-type
(value: unknown | T, label?: string): void;
};

Expand Down
7 changes: 3 additions & 4 deletions source/operators/not.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import randomId from '../utils/random-id.js';
import {validatorSymbol} from '../predicates/predicate.js';
import type {Predicate, Validator} from '../predicates/predicate.js';
import {validatorSymbol, type Predicate, type Validator} from '../predicates/predicate.js';

/**
Operator which inverts the following validation.
Expand All @@ -13,7 +12,7 @@ export const not = (predicate: Predicate): Predicate => {
const originalAddValidator = predicate.addValidator;

predicate.addValidator = (validator: Validator<unknown>): Predicate => {
const {validator: fn, message, negatedMessage} = validator;
const {validator: function_, message, negatedMessage} = validator;
const placeholder = randomId();

validator.message = (value: unknown, label: string): string => (
Expand All @@ -22,7 +21,7 @@ export const not = (predicate: Predicate): Predicate => {
: message(value, placeholder).replace(/ to /, '$&not ').replace(placeholder, label)
);

validator.validator = (value: unknown): unknown => !fn(value);
validator.validator = (value: unknown): unknown => !function_(value);

predicate[validatorSymbol].push(validator);

Expand Down
7 changes: 3 additions & 4 deletions source/predicates/array.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ export class ArrayPredicate<T = unknown> extends Predicate<T[]> {
*/
endsWith(searchElement: T): this {
return this.addValidator({
message: (value, label) => `Expected ${label} to end with \`${searchElement}\`, got \`${value[value.length - 1]}\``,
validator: value => value[value.length - 1] === searchElement,
message: (value, label) => `Expected ${label} to end with \`${searchElement}\`, got \`${value.at(-1)}\``,
validator: value => value.at(-1) === searchElement,
});
}

Expand Down Expand Up @@ -142,8 +142,7 @@ export class ArrayPredicate<T = unknown> extends Predicate<T[]> {
```
*/
ofType<U extends T>(predicate: BasePredicate<U>): ArrayPredicate<U> {
// TODO [typescript@>=5] If higher-kinded types are supported natively by typescript, refactor `addValidator` to use them to avoid the usage of `any`. Otherwise, bump or remove this TODO.
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
// TODO [typescript@>=6] If higher-kinded types are supported natively by typescript, refactor `addValidator` to use them to avoid the usage of `any`. Otherwise, bump or remove this TODO.
return this.addValidator({
message: (_, label, error) => `(${label}) ${error}`,
validator: value => ofType(value, 'values', predicate),
Expand Down
2 changes: 1 addition & 1 deletion source/predicates/error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export class ErrorPredicate extends Predicate<Error> {
hasKeys(...keys: readonly string[]): this {
return this.addValidator({
message: (_, label) => `Expected ${label} message to have keys \`${keys.join('`, `')}\``,
validator: error => keys.every(key => Object.prototype.hasOwnProperty.call(error, key)),
validator: error => keys.every(key => Object.hasOwn(error, key)),
});
}

Expand Down
10 changes: 7 additions & 3 deletions source/predicates/object.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ import {deepEqual} from 'fast-equals';
import hasItems from '../utils/has-items.js';
import ofType from '../utils/of-type.js';
import ofTypeDeep from '../utils/of-type-deep.js';
import {partial, exact, type Shape, type TypeOfShape} from '../utils/match-shape.js';
import {
partial,
exact,
type Shape,
type TypeOfShape,
} from '../utils/match-shape.js';
import {Predicate, type PredicateOptions} from './predicate.js';
import type {BasePredicate} from './base-predicate.js';

Expand Down Expand Up @@ -178,8 +183,7 @@ export class ObjectPredicate<T extends object = object> extends Predicate<T> {
```
*/
exactShape<S extends Shape = Shape>(shape: S): ObjectPredicate<TypeOfShape<S>> {
// TODO [typescript@>=5] If higher-kinded types are supported natively by typescript, refactor `addValidator` to use them to avoid the usage of `any`. Otherwise, bump or remove this TODO.
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
// TODO [typescript@>=6] If higher-kinded types are supported natively by typescript, refactor `addValidator` to use them to avoid the usage of `any`. Otherwise, bump or remove this TODO.
return this.addValidator({
// TODO: Improve this when message handling becomes smarter
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
Expand Down
5 changes: 2 additions & 3 deletions source/predicates/predicate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ export class Predicate<T = unknown> implements BasePredicate<T> {
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
return `Expected ${label_ || 'argument'} to be of type \`${this.type}\` but received type \`${Number.isNaN(value) ? 'NaN' : is(value)}\``;
},
// eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-call
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
validator: value => (is as any)[typeString](value),
});
}
Expand Down Expand Up @@ -174,7 +174,6 @@ export class Predicate<T = unknown> implements BasePredicate<T> {
*/
validate(customValidator: CustomValidator<T>): this {
return this.addValidator({
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
message: (_, label, error) => typeof error === 'string'
? `(${label}) ${error}`
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
Expand Down Expand Up @@ -226,7 +225,7 @@ export class Predicate<T = unknown> implements BasePredicate<T> {
message(newMessage: string | ValidatorMessageBuilder<T>): this {
const {validators} = this.context;

validators[validators.length - 1]!.message = (value, label): string => {
validators.at(-1)!.message = (value, label): string => {
if (typeof newMessage === 'function') {
return newMessage(value, label);
}
Expand Down
15 changes: 7 additions & 8 deletions source/predicates/string.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import is from '@sindresorhus/is';
import valiDate from 'vali-date';
import {Predicate, type PredicateOptions} from './predicate.js';

export class StringPredicate extends Predicate<string> {
Expand Down Expand Up @@ -136,12 +135,12 @@ export class StringPredicate extends Predicate<string> {
// Unicode's formal substitute characters can be barely legible and may not be easily recognized.
// Hence this alternative substitution scheme.
const madeVisible = value
.replace(/ /g, '·')
.replace(/\f/g, '\\f')
.replace(/\n/g, '\\n')
.replace(/\r/g, '\\r')
.replace(/\t/g, '\\t')
.replace(/\v/g, '\\v');
.replaceAll(' ', '·')
.replaceAll('\f', '\\f')
.replaceAll('\n', '\\n')
.replaceAll('\r', '\\r')
.replaceAll('\t', '\\t')
.replaceAll('\v', '\\v');
return `Expected ${label} to not be only whitespace, got \`${madeVisible}\``;
},
validator: value => value.trim() !== '',
Expand Down Expand Up @@ -206,7 +205,7 @@ export class StringPredicate extends Predicate<string> {
get date(): this {
return this.addValidator({
message: (value, label) => `Expected ${label} to be a date, got \`${value}\``,
validator: valiDate,
validator: value => is.validDate(new Date(value)),
});
}

Expand Down
7 changes: 4 additions & 3 deletions source/utils/infer-label.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import fs from 'node:fs';
import type {CallSite} from 'callsites';
import isValidIdentifier from './is-valid-identifier.js';
import isNode from './node/is-node.js';
import {isNode} from 'environment';
import isIdentifier from 'is-identifier';

// Regex to extract the label out of the `ow` function call
const labelRegex = /^.*?\((?<label>.*?)[,)]/;
Expand Down Expand Up @@ -58,7 +58,8 @@ export const inferLabel = (callsites: readonly CallSite[]): void | string => {
return;
}

if (isValidIdentifier(token) || isValidIdentifier(token.split('.').pop() ?? '')) {
// @ts-expect-error - Doesn't seem like something I can work around.
if (isIdentifier(token) || isIdentifier(token.split('.').pop() ?? '')) { // eslint-disable-line @typescript-eslint/no-unsafe-call
return token;
}

Expand Down
21 changes: 0 additions & 21 deletions source/utils/is-valid-identifier.ts

This file was deleted.

12 changes: 4 additions & 8 deletions source/utils/match-shape.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,9 @@ type X = TypeOfShape<typeof myShape> // {foo: string; bar: {baz: boolean}}
This is used in the `ow.object.partialShape(…)` and `ow.object.exactShape(…)` functions.
*/
export type TypeOfShape<S extends BasePredicate | Shape> =
S extends BasePredicate<infer X>
? X
: S extends Shape
? {
[K in keyof S]: TypeOfShape<S[K]>
}
: never;
S extends BasePredicate<infer X> ? X extends object ? X : never :
S extends Shape ? {[K in keyof S]: TypeOfShape<S[K]>} extends object ? {[K in keyof S]: TypeOfShape<S[K]>} : never :
never;

/**
Test if the `object` matches the `shape` partially.
Expand Down Expand Up @@ -85,7 +81,7 @@ export function exact(object: Record<string, any>, shape: Shape, parent?: string
if (isPredicate(shape[key])) {
test(object[key], label, shape[key] as BasePredicate);
} else if (is.plainObject(shape[key])) {
if (!Object.prototype.hasOwnProperty.call(object, key)) {
if (!Object.hasOwn(object, key)) {
return `Expected \`${label}\` to exist`;
}

Expand Down
2 changes: 0 additions & 2 deletions source/utils/node/is-node.ts

This file was deleted.

8 changes: 4 additions & 4 deletions test/bigint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ test('bigint', t => {
ow(BigInt(9_007_199_254_740_991), ow.bigint);
});

// TODO: Enable when targeting Node.js 14.
// t.notThrows(() => {
// ow(9007199254740991n, ow.bigint);
// });
t.notThrows(() => {
// eslint-disable-next-line unicorn/numeric-separators-style
ow(9007199254740991n, ow.bigint);
});

t.throws(() => {
ow(10, ow.bigint);
Expand Down
7 changes: 3 additions & 4 deletions test/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,16 @@ import type {Buffer} from 'node:buffer';
import test from 'ava';
import {expectTypeOf, type ExpectTypeOf} from 'expect-type';
import type {TypedArray} from '../source/typed-array.js';
import type {BasePredicate, Infer} from '../source/index.js';
import ow from '../source/index.js';
import ow, {type BasePredicate, type Infer} from '../source/index.js';

test('type-level tests', t => {
t.is(typeof typeTests, 'function');
});

type AssertionProps = Exclude<keyof typeof ow, 'any' | 'isValid' | 'create' | 'optional'>;
type AssertionProperties = Exclude<keyof typeof ow, 'any' | 'isValid' | 'create' | 'optional'>;

type Tests = {
[K in AssertionProps]:
[K in AssertionProperties]:
typeof ow[K] extends BasePredicate<infer T>
? (type: ExpectTypeOf<T, true>) => void
: never
Expand Down
5 changes: 0 additions & 5 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,6 @@
"include": [
"source"
],
"ts-node": {
"transpileOnly": true,
"files": true,
"experimentalResolver": true
},
"typedocOptions": {
"out": "docs",
"excludePrivate": true,
Expand Down

0 comments on commit 7d8564f

Please sign in to comment.