Skip to content
Merged
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
24 changes: 17 additions & 7 deletions docs/.vitepress/config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,10 @@ export default defineConfig({
)
if (utility) {
pageData.lastUpdated = utility.lastModified.getTime()
pageData.filePath = utility.docsUrl
.replace(`https://github.com/${repository}/blob/${mainBranch}/`, '')
pageData.filePath = utility.docsUrl.replace(
`https://github.com/${repository}/blob/${mainBranch}/`,
'',
)
} else {
pageData.filePath = `docs/${pageData.relativePath}`
}
Expand Down Expand Up @@ -71,9 +73,18 @@ export default defineConfig({
text: 'Migrating',
collapsed: false,
items: [
{ text: 'from feathers-hooks-common', link: '/migrating-from-feathers-hooks-common' },
{ text: 'from @feathersjs/schema', link: '/migrating-from-feathers-schema' },
{ text: 'from feathers-fletching', link: '/migrating-from-feathers-fletching' },
{
text: 'from feathers-hooks-common',
link: '/migrating-from-feathers-hooks-common',
},
{
text: 'from @feathersjs/schema',
link: '/migrating-from-feathers-schema',
},
{
text: 'from feathers-fletching',
link: '/migrating-from-feathers-fletching',
},
],
},
{
Expand Down Expand Up @@ -118,8 +129,7 @@ export default defineConfig({
items: utilities
.filter(
(x) =>
x.category === 'resolvers' &&
x.frontmatter.kind === 'helper',
x.category === 'resolvers' && x.frontmatter.kind === 'helper',
)
.map((x) => ({
text: x.title,
Expand Down
6 changes: 6 additions & 0 deletions docs/.vitepress/plugins/utility.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ export default (utility: Utility, utilities: Utility[]) => {
}
})()

if (utility.aliases?.length) {
code.push(
`_Aliases_: ${utility.aliases.map((a: string) => `\`${a}\``).join(', ')}`,
)
}

code.push(`${utility.description}

\`\`\`ts twoslash
Expand Down
4 changes: 3 additions & 1 deletion docs/.vitepress/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export type Utility = {
predicates?: boolean
dts: string
examples?: string[]
aliases?: string[]
args?: {
name: string
type: string
Expand Down Expand Up @@ -197,7 +198,7 @@ export async function discoverUtilities() {
const fileName = path.basename(filePath, '.md')
const { data: frontmatter, content: body } = matter(content)

const { title = '', category, hook } = frontmatter
const { title = '', category, hook, aliases } = frontmatter

if (
!title ||
Expand Down Expand Up @@ -260,6 +261,7 @@ export async function discoverUtilities() {
hook,
transformers: !!frontmatter.transformers,
predicates: !!frontmatter.predicates,
aliases: aliases?.length ? aliases : undefined,
dts: dtsByMdFile[filePath] ?? undefined,
lastModified: (await fs.stat(filePath)).mtime,
examples: examples.length > 0 ? examples : undefined,
Expand Down
28 changes: 28 additions & 0 deletions docs/migrating-from-feathers-hooks-common.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,20 @@ It is now replaced by the new utilities [`getDataIsArray`](#new-util-getdataisar

Also see [#replace-items](#replace-items).

## `every`

The `every` predicate has been renamed to [`and`](/predicates/and.html). `every` is still available as an alias.

```ts
// old
import { every } from "feathers-hooks-common";

// new
import { and } from "feathers-utils/predicates";
// or use the alias
import { every } from "feathers-utils/predicates";
```

## `isNot`

The `isNot` predicate has been renamed to [`not`](/predicates/not.html).
Expand Down Expand Up @@ -294,6 +308,20 @@ The `sifter` hook has been removed. If you need it please reach out to us in thi

The `softDelete` hook has been updated to require a `deletedQuery` and `removeData` option. This change improves clarity and consistency in how soft deletion is handled in your application.

## `some`

The `some` predicate has been renamed to [`or`](/predicates/or.html). `some` is still available as an alias.

```ts
// old
import { some } from "feathers-hooks-common";

// new
import { or } from "feathers-utils/predicates";
// or use the alias
import { some } from "feathers-utils/predicates";
```

## `stashBefore`

The `stashBefore` hook has been renamed to [`stashable`](/hooks/stashable.html). Instead of eagerly fetching and storing the result directly on `context.params.before`, it now exposes a memoized function that returns a promise. The fetch starts immediately but multiple calls to `stashed()` only hit the database once.
Expand Down
24 changes: 24 additions & 0 deletions src/guards/has-query/has-query.guard.test-d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import type { Params } from '@feathersjs/feathers'
import { expectTypeOf } from 'vitest'
import { hasQuery } from './has-query.guard.js'

it('narrows query from optional to required', () => {
const params: Params = {}

if (hasQuery(params)) {
expectTypeOf(params.query).toEqualTypeOf<Record<string, any>>()
}
})

it('query is optional before guard', () => {
const params: Params = {}
expectTypeOf(params.query).toEqualTypeOf<Record<string, any> | undefined>()
})

it('preserves custom query type', () => {
const params: Params<{ name: string }> = { query: { name: 'Dave' } }

if (hasQuery(params)) {
expectTypeOf(params.query).toEqualTypeOf<{ name: string }>()
}
})
24 changes: 24 additions & 0 deletions src/guards/has-query/has-query.guard.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import type { Params } from '@feathersjs/feathers'
import { hasQuery } from './has-query.guard.js'

describe('guards/has-query', () => {
it('returns true when query is present', () => {
const params: Params = { query: { name: 'Dave' } }
expect(hasQuery(params)).toBe(true)
})

it('returns false when query is undefined', () => {
const params: Params = {}
expect(hasQuery(params)).toBe(false)
})

it('returns false when query is null', () => {
const params = { query: null } as unknown as Params
expect(hasQuery(params)).toBe(false)
})

it('returns true for empty query object', () => {
const params: Params = { query: {} }
expect(hasQuery(params)).toBe(true)
})
})
11 changes: 5 additions & 6 deletions src/hooks/check-required/check-required.hook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,11 @@ export function checkRequired<H extends HookContext = HookContext>(
) {
const fieldNamesArray = toArray(fieldNames)
return (context: H, next?: NextFunction) => {
checkContext(
context,
['before', 'around'],
['create', 'update', 'patch'],
'checkRequired',
)
checkContext(context, {
type: ['before', 'around'],
method: ['create', 'update', 'patch'],
label: 'checkRequired',
})

const { data } = getDataIsArray(context)

Expand Down
6 changes: 5 additions & 1 deletion src/hooks/create-related/create-related.hook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,11 @@ export function createRelated<H extends HookContext = HookContext>(
options: MaybeArray<CreateRelatedOptions<H>>,
) {
return async (context: H, next?: NextFunction) => {
checkContext(context, ['after', 'around'], ['create'], 'createRelated')
checkContext(context, {
type: ['after', 'around'],
method: ['create'],
label: 'createRelated',
})

if (next) {
await next()
Expand Down
6 changes: 5 additions & 1 deletion src/hooks/disable-pagination/disable-pagination.hook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,11 @@ import { checkContext } from '../../utils/index.js'
export const disablePagination =
<H extends HookContext = HookContext>() =>
(context: H, next?: NextFunction) => {
checkContext(context, ['before', 'around'], ['find'], 'disablePagination')
checkContext(context, {
type: ['before', 'around'],
method: ['find'],
label: 'disablePagination',
})
const $limit = context.params?.query?.$limit

if ($limit === '-1' || $limit === -1) {
Expand Down
12 changes: 6 additions & 6 deletions src/hooks/iff-else/iff-else.hook.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
import type { HookContext } from '@feathersjs/feathers'
import { assert } from 'vitest'
import { iffElse } from './iff-else.hook.js'
import { some } from '../../predicates/some/some.predicate.js'
import { every } from '../../predicates/every/every.predicate.js'
import { or } from '../../predicates/or/or.predicate.js'
import { and } from '../../predicates/and/and.predicate.js'
import { clone } from '../../common/index.js'

let hook: any
Expand Down Expand Up @@ -158,10 +158,10 @@ describe('services iffElse', () => {
})
})

it('every passes on correct params', () => {
it('and passes on correct params', () => {
return iffElse(
// @ts-expect-error TODO
every(predicateTrue),
and(predicateTrue),
[hookFcnSync, hookFcnAsync, hookFcn],
[],
)(hook).then(() => {
Expand All @@ -172,10 +172,10 @@ describe('services iffElse', () => {
})
})

it('some passes on correct params', () => {
it('or passes on correct params', () => {
return iffElse(
// @ts-expect-error TODO
some(predicateTrue),
or(predicateTrue),
[hookFcnSync, hookFcnAsync, hookFcn],
[],
)(hook).then(() => {
Expand Down
6 changes: 5 additions & 1 deletion src/hooks/on-delete/on-delete.hook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,11 @@ export const onDelete = <H extends HookContext = HookContext>(
const optionsMulti = Array.isArray(options) ? options : [options]

return async (context: H, next?: NextFunction) => {
checkContext(context, ['after', 'around'], 'remove', 'onDelete')
checkContext(context, {
type: ['after', 'around'],
method: 'remove',
label: 'onDelete',
})

if (next) {
await next()
Expand Down
2 changes: 1 addition & 1 deletion src/hooks/set-field/set-field.hook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export const setField =
(context: H, next?: NextFunction) => {
const { params } = context

checkContext(context, ['before', 'around'], null, 'setField')
checkContext(context, { type: ['before', 'around'], label: 'setField' })

const value = _get(context, from)

Expand Down
2 changes: 1 addition & 1 deletion src/hooks/soft-delete/soft-delete.hook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export const softDelete = <H extends HookContext = HookContext>(
}

return async (context: H, next?: NextFunction) => {
checkContext(context, ['before', 'around'], null, 'softDelete')
checkContext(context, { type: ['before', 'around'], label: 'softDelete' })

const { disableSoftDeleteKey = 'disableSoftDelete' } = options

Expand Down
11 changes: 5 additions & 6 deletions src/hooks/stashable/stashable.hook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,11 @@ export function stashable<H extends HookContext = HookContext>(
return context
}

checkContext(
context,
['before', 'around'],
['update', 'patch', 'remove'],
'stashable',
)
checkContext(context, {
type: ['before', 'around'],
method: ['update', 'patch', 'remove'],
label: 'stashable',
})

const promise = stashFunc(context).catch(() => undefined)

Expand Down
8 changes: 6 additions & 2 deletions src/hooks/transform-data/transform-data.hook.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,14 @@ it('trim', () => {
it('defaults', () => {
useHook<Ctx>(transformData((item) => defaults(item, { name: 'John' })))
useHook<Ctx>(
transformData((item) => defaults(item, { name: 'John', password: 'secret' })),
transformData((item) =>
defaults(item, { name: 'John', password: 'secret' }),
),
)
useHook<Ctx>(
transformData((item) => defaults(item, { 'address.street': '123 Main St' })),
transformData((item) =>
defaults(item, { 'address.street': '123 Main St' }),
),
)
useHook<Ctx>(transformData((item) => defaults(item, { name: () => 'John' })))

Expand Down
4 changes: 2 additions & 2 deletions src/hooks/transform-data/transform-data.hook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ type Data<H extends HookContext> = AnyFallback<
* @see https://utils.feathersjs.com/hooks/transform-data.html
*/
export const transformData =
<H extends HookContext = HookContext>(
transformer: TransformerInputFn<Data<H>, H>,
<H extends HookContext = HookContext, D = Data<H>>(
transformer: TransformerInputFn<D, H>,
) =>
async (context: H, next?: NextFunction) => {
await mutateData(context, transformer)
Expand Down
12 changes: 9 additions & 3 deletions src/hooks/transform-result/transform-result.hook.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,12 +84,18 @@ it('trim', () => {
it('defaults', () => {
useHook<Ctx>(transformResult((item) => defaults(item, { name: 'John' })))
useHook<Ctx>(
transformResult((item) => defaults(item, { name: 'John', password: 'secret' })),
transformResult((item) =>
defaults(item, { name: 'John', password: 'secret' }),
),
)
useHook<Ctx>(
transformResult((item) => defaults(item, { 'address.street': '123 Main St' })),
transformResult((item) =>
defaults(item, { 'address.street': '123 Main St' }),
),
)
useHook<Ctx>(
transformResult((item) => defaults(item, { name: () => 'John' })),
)
useHook<Ctx>(transformResult((item) => defaults(item, { name: () => 'John' })))

useHook<Ctx>(
// @ts-expect-error "nonExistent" is not a key of User
Expand Down
4 changes: 2 additions & 2 deletions src/hooks/transform-result/transform-result.hook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ export type TransformResultOptions = {
* @see https://utils.feathersjs.com/hooks/transform-result.html
*/
export const transformResult =
<H extends HookContext = HookContext>(
transformer: TransformerInputFn<Result<H>, H>,
<H extends HookContext = HookContext, R = Result<H>>(
transformer: TransformerInputFn<R, H>,
options?: TransformResultOptions,
): HookFunction<H> =>
(context: H, next?: NextFunction) =>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
---
title: some
title: and
category: predicates
aliases:
- every
see:
- hooks/iff
- hooks/iffElse
- predicates/every
- predicates/or
- predicates/not
---
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,15 @@ import type { HookContext } from '@feathersjs/feathers'
import { feathers } from '@feathersjs/feathers'
import { MemoryService } from '@feathersjs/memory'
import { iff } from '../../hooks/index.js'
import { every } from './every.predicate.js'
import { and as every } from './and.predicate.js'
import { and, every as everyAlias } from '../index.js'
import { not } from '../not/not.predicate.js'

describe('predicates/every', () => {
describe('predicates/and', () => {
it('is exported as "every" alias', () => {
expect(everyAlias).toBe(and)
})

it('returns true synchronously when empty', () => {
assert.equal(every()({} as HookContext), true)
})
Expand Down
Loading
Loading