Skip to content

Commit ad9896f

Browse files
authored
feat: second generic for resolvers/transformer hooks for explicit type (#26)
* feat: second generic for resolvers/transformer hooks for explicit type * feat: checkContext with options object
1 parent e41a5f5 commit ad9896f

File tree

50 files changed

+667
-314
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+667
-314
lines changed

docs/.vitepress/config.mts

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,10 @@ export default defineConfig({
4141
)
4242
if (utility) {
4343
pageData.lastUpdated = utility.lastModified.getTime()
44-
pageData.filePath = utility.docsUrl
45-
.replace(`https://github.com/${repository}/blob/${mainBranch}/`, '')
44+
pageData.filePath = utility.docsUrl.replace(
45+
`https://github.com/${repository}/blob/${mainBranch}/`,
46+
'',
47+
)
4648
} else {
4749
pageData.filePath = `docs/${pageData.relativePath}`
4850
}
@@ -71,9 +73,18 @@ export default defineConfig({
7173
text: 'Migrating',
7274
collapsed: false,
7375
items: [
74-
{ text: 'from feathers-hooks-common', link: '/migrating-from-feathers-hooks-common' },
75-
{ text: 'from @feathersjs/schema', link: '/migrating-from-feathers-schema' },
76-
{ text: 'from feathers-fletching', link: '/migrating-from-feathers-fletching' },
76+
{
77+
text: 'from feathers-hooks-common',
78+
link: '/migrating-from-feathers-hooks-common',
79+
},
80+
{
81+
text: 'from @feathersjs/schema',
82+
link: '/migrating-from-feathers-schema',
83+
},
84+
{
85+
text: 'from feathers-fletching',
86+
link: '/migrating-from-feathers-fletching',
87+
},
7788
],
7889
},
7990
{
@@ -118,8 +129,7 @@ export default defineConfig({
118129
items: utilities
119130
.filter(
120131
(x) =>
121-
x.category === 'resolvers' &&
122-
x.frontmatter.kind === 'helper',
132+
x.category === 'resolvers' && x.frontmatter.kind === 'helper',
123133
)
124134
.map((x) => ({
125135
text: x.title,

docs/.vitepress/plugins/utility.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,12 @@ export default (utility: Utility, utilities: Utility[]) => {
4040
}
4141
})()
4242

43+
if (utility.aliases?.length) {
44+
code.push(
45+
`_Aliases_: ${utility.aliases.map((a: string) => `\`${a}\``).join(', ')}`,
46+
)
47+
}
48+
4349
code.push(`${utility.description}
4450
4551
\`\`\`ts twoslash

docs/.vitepress/utilities.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ export type Utility = {
3838
predicates?: boolean
3939
dts: string
4040
examples?: string[]
41+
aliases?: string[]
4142
args?: {
4243
name: string
4344
type: string
@@ -197,7 +198,7 @@ export async function discoverUtilities() {
197198
const fileName = path.basename(filePath, '.md')
198199
const { data: frontmatter, content: body } = matter(content)
199200

200-
const { title = '', category, hook } = frontmatter
201+
const { title = '', category, hook, aliases } = frontmatter
201202

202203
if (
203204
!title ||
@@ -260,6 +261,7 @@ export async function discoverUtilities() {
260261
hook,
261262
transformers: !!frontmatter.transformers,
262263
predicates: !!frontmatter.predicates,
264+
aliases: aliases?.length ? aliases : undefined,
263265
dts: dtsByMdFile[filePath] ?? undefined,
264266
lastModified: (await fs.stat(filePath)).mtime,
265267
examples: examples.length > 0 ? examples : undefined,

docs/migrating-from-feathers-hooks-common.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,20 @@ It is now replaced by the new utilities [`getDataIsArray`](#new-util-getdataisar
139139

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

142+
## `every`
143+
144+
The `every` predicate has been renamed to [`and`](/predicates/and.html). `every` is still available as an alias.
145+
146+
```ts
147+
// old
148+
import { every } from "feathers-hooks-common";
149+
150+
// new
151+
import { and } from "feathers-utils/predicates";
152+
// or use the alias
153+
import { every } from "feathers-utils/predicates";
154+
```
155+
142156
## `isNot`
143157

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

295309
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.
296310

311+
## `some`
312+
313+
The `some` predicate has been renamed to [`or`](/predicates/or.html). `some` is still available as an alias.
314+
315+
```ts
316+
// old
317+
import { some } from "feathers-hooks-common";
318+
319+
// new
320+
import { or } from "feathers-utils/predicates";
321+
// or use the alias
322+
import { some } from "feathers-utils/predicates";
323+
```
324+
297325
## `stashBefore`
298326

299327
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.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import type { Params } from '@feathersjs/feathers'
2+
import { expectTypeOf } from 'vitest'
3+
import { hasQuery } from './has-query.guard.js'
4+
5+
it('narrows query from optional to required', () => {
6+
const params: Params = {}
7+
8+
if (hasQuery(params)) {
9+
expectTypeOf(params.query).toEqualTypeOf<Record<string, any>>()
10+
}
11+
})
12+
13+
it('query is optional before guard', () => {
14+
const params: Params = {}
15+
expectTypeOf(params.query).toEqualTypeOf<Record<string, any> | undefined>()
16+
})
17+
18+
it('preserves custom query type', () => {
19+
const params: Params<{ name: string }> = { query: { name: 'Dave' } }
20+
21+
if (hasQuery(params)) {
22+
expectTypeOf(params.query).toEqualTypeOf<{ name: string }>()
23+
}
24+
})
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import type { Params } from '@feathersjs/feathers'
2+
import { hasQuery } from './has-query.guard.js'
3+
4+
describe('guards/has-query', () => {
5+
it('returns true when query is present', () => {
6+
const params: Params = { query: { name: 'Dave' } }
7+
expect(hasQuery(params)).toBe(true)
8+
})
9+
10+
it('returns false when query is undefined', () => {
11+
const params: Params = {}
12+
expect(hasQuery(params)).toBe(false)
13+
})
14+
15+
it('returns false when query is null', () => {
16+
const params = { query: null } as unknown as Params
17+
expect(hasQuery(params)).toBe(false)
18+
})
19+
20+
it('returns true for empty query object', () => {
21+
const params: Params = { query: {} }
22+
expect(hasQuery(params)).toBe(true)
23+
})
24+
})

src/hooks/check-required/check-required.hook.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,11 @@ export function checkRequired<H extends HookContext = HookContext>(
2828
) {
2929
const fieldNamesArray = toArray(fieldNames)
3030
return (context: H, next?: NextFunction) => {
31-
checkContext(
32-
context,
33-
['before', 'around'],
34-
['create', 'update', 'patch'],
35-
'checkRequired',
36-
)
31+
checkContext(context, {
32+
type: ['before', 'around'],
33+
method: ['create', 'update', 'patch'],
34+
label: 'checkRequired',
35+
})
3736

3837
const { data } = getDataIsArray(context)
3938

src/hooks/create-related/create-related.hook.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,11 @@ export function createRelated<H extends HookContext = HookContext>(
5555
options: MaybeArray<CreateRelatedOptions<H>>,
5656
) {
5757
return async (context: H, next?: NextFunction) => {
58-
checkContext(context, ['after', 'around'], ['create'], 'createRelated')
58+
checkContext(context, {
59+
type: ['after', 'around'],
60+
method: ['create'],
61+
label: 'createRelated',
62+
})
5963

6064
if (next) {
6165
await next()

src/hooks/disable-pagination/disable-pagination.hook.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,11 @@ import { checkContext } from '../../utils/index.js'
2121
export const disablePagination =
2222
<H extends HookContext = HookContext>() =>
2323
(context: H, next?: NextFunction) => {
24-
checkContext(context, ['before', 'around'], ['find'], 'disablePagination')
24+
checkContext(context, {
25+
type: ['before', 'around'],
26+
method: ['find'],
27+
label: 'disablePagination',
28+
})
2529
const $limit = context.params?.query?.$limit
2630

2731
if ($limit === '-1' || $limit === -1) {

src/hooks/iff-else/iff-else.hook.test.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
import type { HookContext } from '@feathersjs/feathers'
33
import { assert } from 'vitest'
44
import { iffElse } from './iff-else.hook.js'
5-
import { some } from '../../predicates/some/some.predicate.js'
6-
import { every } from '../../predicates/every/every.predicate.js'
5+
import { or } from '../../predicates/or/or.predicate.js'
6+
import { and } from '../../predicates/and/and.predicate.js'
77
import { clone } from '../../common/index.js'
88

99
let hook: any
@@ -158,10 +158,10 @@ describe('services iffElse', () => {
158158
})
159159
})
160160

161-
it('every passes on correct params', () => {
161+
it('and passes on correct params', () => {
162162
return iffElse(
163163
// @ts-expect-error TODO
164-
every(predicateTrue),
164+
and(predicateTrue),
165165
[hookFcnSync, hookFcnAsync, hookFcn],
166166
[],
167167
)(hook).then(() => {
@@ -172,10 +172,10 @@ describe('services iffElse', () => {
172172
})
173173
})
174174

175-
it('some passes on correct params', () => {
175+
it('or passes on correct params', () => {
176176
return iffElse(
177177
// @ts-expect-error TODO
178-
some(predicateTrue),
178+
or(predicateTrue),
179179
[hookFcnSync, hookFcnAsync, hookFcn],
180180
[],
181181
)(hook).then(() => {

0 commit comments

Comments
 (0)