New:Socket for Asana Is Now Available.Learn more
Get Started

@fastify/autoload

Package Overview
Dependencies
Maintainers
18
Versions
31
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@fastify/autoload - npm Package Compare versions

Comparing version
6.3.1
to
6.4.0
+19
.github/workflows/lock-threads.yml
name: Lock Threads
on:
schedule:
- cron: '0 0 1 * *'
workflow_dispatch:
concurrency:
group: lock
permissions:
contents: read
jobs:
lock-threads:
permissions:
issues: write
pull-requests: write
uses: fastify/workflows/.github/workflows/lock-threads.yml@v6
'use strict'
const { exec } = require('node:child_process')
const { argv } = require('node:process')
const args = [
argv[0],
'test',
'./test/typescript-esm/forceESM.ts'
]
const child = exec(args.join(' '), {
shell: true,
env: {
...process.env,
TS_NODE_COMPILER_OPTIONS: JSON.stringify({
module: 'ESNext',
target: 'ES2020',
allowJs: false,
moduleResolution: 'node',
esModuleInterop: true
})
}
})
child.stdout.pipe(process.stdout)
child.stderr.pipe(process.stderr)
child.once('close', process.exit)
'use strict'
const { exec } = require('node:child_process')
const { argv } = require('node:process')
const args = [
argv[0],
'test',
'-A',
'./test/typescript-esm/forceESM.ts'
]
const child = exec(args.join(' '), {
shell: true,
env: {
...process.env,
TS_NODE_COMPILER_OPTIONS: JSON.stringify({
module: 'ESNext',
target: 'ES2020',
allowJs: false,
moduleResolution: 'node',
esModuleInterop: true
})
}
})
child.stdout.pipe(process.stdout)
child.stderr.pipe(process.stderr)
child.once('close', process.exit)
'use strict'
module.exports = async (fastify) => {
fastify.get('/', function () {
return { foo: 'bar' }
})
}
'use strict'
module.exports = async (fastify) => {
fastify.get('/', function () {
return { hello: 'world' }
})
}
'use strict'
module.exports = async function (app) {
app.get('/alive', async function () {
return { ok: true }
})
}
'use strict'
module.exports = async function (app) {
app.setNotFoundHandler(function (req, reply) {
reply.status(404).send({ scope: 'api', url: req.url })
})
}
'use strict'
const { after, before, describe, it } = require('node:test')
const path = require('node:path')
const Fastify = require('fastify')
const autoLoad = require('../../../')
const assert = require('node:assert')
describe('Issue 326: setNotFoundHandler from autohooks must remain under prefixed scope', function () {
const app = Fastify()
before(async function () {
app.register(autoLoad, {
dir: path.join(__dirname, 'routes', 'api'),
autoHooks: true,
cascadeHooks: true,
options: { prefix: '/api' }
})
await app.ready()
})
after(async function () {
await app.close()
})
it('keeps autohooks notFound handler for prefixed paths only', async function () {
const prefixed = await app.inject({ method: 'GET', url: '/api/not-exists' })
assert.strictEqual(prefixed.statusCode, 404)
assert.deepStrictEqual(prefixed.json(), { scope: 'api', url: '/api/not-exists' })
const root = await app.inject({ method: 'GET', url: '/not-exists' })
assert.strictEqual(root.statusCode, 404)
assert.notDeepStrictEqual(root.json(), { scope: 'api', url: '/not-exists' })
assert.strictEqual(root.json().scope, undefined)
})
})
'use strict'
module.exports = async function (fastify) {
fastify.get('/', async () => ({ zone: 'private' }))
}
'use strict'
module.exports = async function (fastify) {
fastify.get('/', async () => ({ zone: 'public' }))
}
'use strict'
const { afterEach, describe, it } = require('node:test')
const assert = require('node:assert')
const path = require('node:path')
const Fastify = require('fastify')
const autoLoad = require('../../../')
describe('Issue 519: ignorePattern should match against the relative file path, not just the entry basename', function () {
let app
afterEach(async function () {
await app.close()
})
it('ignorePattern with a path-component regex skips only the matched subdirectory file', async function () {
app = Fastify()
app.register(autoLoad, {
dir: path.join(__dirname, 'routes'),
ignorePattern: /private\/plugin/,
})
await app.ready()
const pub = await app.inject({ url: '/public' })
assert.strictEqual(pub.statusCode, 200)
assert.deepStrictEqual(pub.json(), { zone: 'public' })
const priv = await app.inject({ url: '/private' })
assert.strictEqual(priv.statusCode, 404, 'private route should be excluded by ignorePattern path match')
})
})
import fastify, { FastifyInstance, FastifyPluginCallback } from 'fastify'
import { expect } from 'tstyche'
import * as fastifyAutoloadStar from '.'
import fastifyAutoloadDefault, { AutoloadPluginOptions, fastifyAutoload as fastifyAutoloadNamed } from '.'
import * as fastifyAutoloadCjsImport from '.'
const fastifyAutoloadCjs = require('..')
const app: FastifyInstance = fastify()
app.register(fastifyAutoloadNamed, { dir: 'test' })
app.register(fastifyAutoloadDefault, { dir: 'test' })
app.register(fastifyAutoloadCjs, { dir: 'test' })
app.register(fastifyAutoloadCjsImport.default, { dir: 'test' })
app.register(fastifyAutoloadCjsImport.fastifyAutoload, { dir: 'test' })
app.register(fastifyAutoloadStar.default, { dir: 'test' })
app.register(fastifyAutoloadStar.fastifyAutoload, { dir: 'test' })
expect(fastifyAutoloadNamed).type.toBe<FastifyPluginCallback<AutoloadPluginOptions>>()
expect(fastifyAutoloadDefault).type.toBe<FastifyPluginCallback<AutoloadPluginOptions>>()
expect(fastifyAutoloadCjsImport.default).type.toBe<FastifyPluginCallback<AutoloadPluginOptions>>()
expect(fastifyAutoloadCjsImport.fastifyAutoload).type.toBe<FastifyPluginCallback<AutoloadPluginOptions>>()
expect(fastifyAutoloadStar.default).type.toBe<FastifyPluginCallback<AutoloadPluginOptions>>()
expect(fastifyAutoloadStar.fastifyAutoload).type.toBe<FastifyPluginCallback<AutoloadPluginOptions>>()
expect(fastifyAutoloadCjs).type.toBe<any>()
const opt1: AutoloadPluginOptions = {
dir: 'test'
}
const opt2: AutoloadPluginOptions = {
dir: 'test',
ignorePattern: /skip/
}
const opt3: AutoloadPluginOptions = {
dir: 'test',
scriptPattern: /js/,
indexPattern: /index/,
}
const opt4: AutoloadPluginOptions = {
dir: 'test',
options: {
prefix: 'test'
}
}
const opt5: AutoloadPluginOptions = {
dir: 'test',
maxDepth: 1,
}
const opt6: AutoloadPluginOptions = {
dir: 'test',
routeParams: true,
}
const opt7: AutoloadPluginOptions = {
dir: 'test',
forceESM: true,
autoHooks: true,
autoHooksPattern: /^[_.]?auto_?hooks(?:\.ts|\.js|\.cjs|\.mjs)$/i,
cascadeHooks: true,
overwriteHooks: true,
}
const opt8: AutoloadPluginOptions = {
dir: 'test',
encapsulate: false,
}
const opt9: AutoloadPluginOptions = {
dir: 'test',
ignoreFilter: /test/,
matchFilter: /handler/
}
const opt10: AutoloadPluginOptions = {
dir: 'test',
ignoreFilter: 'test',
matchFilter: 'handler'
}
const opt11: AutoloadPluginOptions = {
dir: 'test',
ignoreFilter: (path) => path.endsWith('.spec.ts'),
matchFilter: (path) => path.split('/').at(-2) === 'handlers'
}
app.register(fastifyAutoloadDefault, opt1)
app.register(fastifyAutoloadDefault, opt2)
app.register(fastifyAutoloadDefault, opt3)
app.register(fastifyAutoloadDefault, opt4)
app.register(fastifyAutoloadDefault, opt5)
app.register(fastifyAutoloadDefault, opt6)
app.register(fastifyAutoloadDefault, opt7)
app.register(fastifyAutoloadDefault, opt8)
app.register(fastifyAutoloadDefault, opt9)
app.register(fastifyAutoloadDefault, opt10)
app.register(fastifyAutoloadDefault, opt11)
expect(app.register).type.not.toBeCallableWith(fastifyAutoloadDefault, {
dir: 'test',
invalidOption: true
})
+42
-2

@@ -5,4 +5,13 @@ version: 2

directory: "/"
commit-message:
# Prefix all commit messages with "chore: "
prefix: "chore"
schedule:
interval: "monthly"
interval: "weekly"
cooldown:
default-days: 7
allow:
- dependency-name: "*"
update-types:
- "version-update:semver-major"
open-pull-requests-limit: 10

@@ -12,4 +21,35 @@

directory: "/"
commit-message:
# Prefix all commit messages with "chore: "
prefix: "chore"
schedule:
interval: "monthly"
interval: "weekly"
cooldown:
default-days: 7
versioning-strategy: "increase-if-necessary"
allow:
- dependency-name: "*"
update-types:
- "version-update:semver-major"
ignore:
# TODO: remove ignore until neostandard support ESLint 10
- dependency-name: "eslint"
- dependency-name: "neostandard"
- dependency-name: "@stylistic/*"
open-pull-requests-limit: 10
groups:
# Production dependencies with breaking changes
dependencies:
dependency-type: "production"
# ESLint related dependencies
dev-dependencies-eslint:
patterns:
- "eslint"
- "neostandard"
- "@stylistic/*"
# TypeScript related dependencies
dev-dependencies-typescript:
patterns:
- "@types/*"
- "tstyche"
- "typescript"

@@ -17,2 +17,7 @@ name: CI

# This allows a subsequently queued workflow run to interrupt previous runs
concurrency:
group: "${{ github.workflow }}-${{ github.event.pull_request.head.label || github.head_ref || github.ref }}"
cancel-in-progress: true
permissions:

@@ -22,2 +27,36 @@ contents: read

jobs:
bun:
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/checkout@v7
with:
persist-credentials: false
- name: Setup Bun
uses: oven-sh/setup-bun@3d267786b128fe76c2f16a390aa2448b815359f3
- name: Install dependencies
run: bun install
- name: Run unit tests
run: bun run typescript:bun
deno:
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/checkout@v7
with:
persist-credentials: false
- name: Setup Deno
uses: denoland/setup-deno@e95548e56dfa95d4e1a28d6f422fafe75c4c26fb
- name: Install dependencies
run: deno install
- name: Run unit tests
run: deno run typescript:deno
test:

@@ -27,5 +66,5 @@ permissions:

pull-requests: write
uses: fastify/workflows/.github/workflows/plugins-ci.yml@v5
uses: fastify/workflows/.github/workflows/plugins-ci.yml@v6
with:
license-check: true
lint: true

@@ -138,2 +138,6 @@ 'use strict'

} else {
const hooksPrefix = findCommonHooksPrefix(node)
const scopedPluginsMeta = hooksPrefix ? buildScopedPluginsMeta(node.pluginsMeta, hooksPrefix) : node.pluginsMeta
const scopedNode = hooksPrefix ? { ...node, pluginsMeta: scopedPluginsMeta } : node
const composedPlugin = async function (app) {

@@ -147,8 +151,66 @@ // find hook functions for this prefix

registerAllPlugins(app, node)
registerAllPlugins(app, scopedNode)
}
fastify.register(composedPlugin)
if (hooksPrefix) {
fastify.register(composedPlugin, { prefix: hooksPrefix })
} else {
fastify.register(composedPlugin)
}
}
}
function findCommonHooksPrefix (node) {
const prefixes = Object.values(node.pluginsMeta)
.map((meta) => meta?.options?.prefix)
.filter((prefix) => typeof prefix === 'string' && prefix.length > 0)
if (prefixes.length === 0) {
return
}
const [first] = prefixes
if (prefixes.every((prefix) => prefix === first)) {
return first
}
}
function buildScopedPluginsMeta (pluginsMeta, hooksPrefix) {
const scopedPluginsMeta = {}
for (const [name, meta] of Object.entries(pluginsMeta)) {
const options = meta?.options
if (typeof options?.prefix === 'string') {
const strippedPrefix = stripPrefix(options.prefix, hooksPrefix)
scopedPluginsMeta[name] = {
...meta,
options: {
...options,
/* c8 ignore next */
...(strippedPrefix ? { prefix: strippedPrefix } : { prefix: undefined })
},
registered: false
}
} else {
scopedPluginsMeta[name] = {
...meta,
registered: false
}
}
}
return scopedPluginsMeta
}
function stripPrefix (prefix, parentPrefix) {
/* c8 ignore next 3 */
if (!prefix.startsWith(parentPrefix)) {
return prefix
}
const stripped = prefix.slice(parentPrefix.length)
/* c8 ignore next */
return stripped === '' ? undefined : stripped
}
function registerAllPlugins (app, node) {

@@ -155,0 +217,0 @@ const metas = Object.values(node.pluginsMeta)

+5
-2

@@ -90,4 +90,7 @@ 'use strict'

for (const dirEntry of dirEntries) {
if (opts.ignorePattern && RegExp(opts.ignorePattern).test(dirEntry.name)) {
continue
if (opts.ignorePattern) {
const entryRelPath = relative(opts.dir, join(dir, dirEntry.name)).replace(/\\/gu, '/')
if (RegExp(opts.ignorePattern).test(entryRelPath)) {
continue
}
}

@@ -94,0 +97,0 @@

@@ -39,2 +39,14 @@ 'use strict'

Object.defineProperties(runtime, {
bun: {
get () {
cache.bun ??= 'Bun' in globalThis
return cache.bun
}
},
deno: {
get () {
cache.deno ??= 'Deno' in globalThis
return cache.deno
}
},
tsNode: {

@@ -102,8 +114,2 @@ get () {

},
tsimp: {
get () {
cache.tsimp ??= checkProcessArgv('tsimp/import')
return cache.tsimp
}
},
supportTypeScript: {

@@ -113,2 +119,4 @@ get () {

checkEnvVariable('FASTIFY_AUTOLOAD_TYPESCRIPT') ||
runtime.bun ||
runtime.deno ||
runtime.tsNode ||

@@ -122,3 +130,2 @@ runtime.vitest ||

runtime.esbuild ||
runtime.tsimp ||
runtime.supportNativeTypeScript

@@ -125,0 +132,0 @@ )

MIT License
Copyright (c) 2018 Fastify
Copyright (c) 2018-present The Fastify team <https://github.com/fastify/fastify#team>

@@ -5,0 +5,0 @@ Permission is hereby granted, free of charge, to any person obtaining a copy

{
"name": "@fastify/autoload",
"version": "6.3.1",
"version": "6.4.0",
"description": "Require all plugins in a directory",

@@ -12,3 +12,5 @@ "main": "index.js",

"test": "npm run typescript && npm run typescript:native && npm run typescript:jest && npm run typescript:swc-node-register && npm run typescript:tsm && npm run typescript:tsx && npm run typescript:vitest && npm run typescript:esbuild && npm run unit",
"typescript": "tsd",
"typescript": "tstyche",
"typescript:bun": "bun scripts/unit-typescript-bun-esm.js",
"typescript:deno": "deno -A scripts/unit-typescript-deno-esm.js",
"typescript:jest": "jest",

@@ -19,3 +21,2 @@ "typescript:esm": "node scripts/unit-typescript-esm.js",

"typescript:tsx": "node scripts/unit-typescript-tsx.js",
"typescript:tsimp": "node scripts/unit-typescript-tsimp.js",
"typescript:esbuild": "node scripts/unit-typescript-esbuild.js",

@@ -46,3 +47,3 @@ "typescript:native": "node scripts/unit-typescript-native-type-stripping.js",

"name": "Tomas Della Vedova",
"url": "http://delved.org"
"url": "https://delvedor.dev"
},

@@ -79,27 +80,25 @@ {

"devDependencies": {
"@fastify/pre-commit": "^2.1.0",
"@fastify/url-data": "^6.0.0",
"@jsumners/line-reporter": "^1.0.1",
"@swc-node/register": "^1.9.1",
"@swc/core": "^1.5.25",
"@types/jest": "^29.5.12",
"@types/node": "^22.0.0",
"borp": "^0.20.0",
"esbuild": "^0.25.0",
"@swc-node/register": "1.11.1",
"@swc/core": "1.15.40",
"@types/jest": "^30.0.0",
"@types/node": "^26.0.0",
"borp": "^1.0.0",
"esbuild": "^0.28.0",
"esbuild-register": "^3.5.0",
"eslint": "^9.17.0",
"fastify": "^5.0.0",
"fastify-plugin": "^5.0.0",
"jest": "^29.7.0",
"neostandard": "^0.12.0",
"ts-jest": "^29.1.4",
"fastify-plugin": "^6.0.0",
"jest": "^30.0.3",
"neostandard": "^0.13.0",
"ts-jest": "^29.4.9",
"ts-node": "^10.9.2",
"ts-node-dev": "^2.0.0",
"tsd": "^0.32.0",
"tsimp": "^2.0.11",
"tstyche": "^7.0.0",
"tsm": "^2.3.0",
"tsx": "^4.15.7",
"typescript": "5.5",
"vite": "^6.0.2",
"vitest": "^3.0.4"
"tsx": "^4.21.0",
"typescript": "~6.0.2",
"vite": "^8.0.3",
"vitest": "^4.0.6"
},

@@ -114,3 +113,14 @@ "jest": {

"transform": {
"^.+\\.(ts|tsx)$": "ts-jest"
"^.+\\.(ts|tsx)$": [
"ts-jest",
{
"tsconfig": {
"esModuleInterop": true,
"types": [
"jest",
"node"
]
}
}
]
}

@@ -120,7 +130,3 @@ },

"access": "public"
},
"pre-commit": [
"lint",
"test"
]
}
}
+396
-357

@@ -93,231 +93,259 @@ # @fastify/autoload

- `dir` (required) - Base directory containing plugins to be loaded
### `dir` (required)
Each script file within a directory is treated as a plugin unless the directory contains an index file (e.g. `index.js`). In which case, only the index file (and the potential sub-directories) will be loaded.
Base directory containing plugins to be loaded.
The following script types are supported:
Each script file within a directory is treated as a plugin unless the directory contains an index file (e.g. `index.js`). In which case, only the index file (and the potential sub-directories) will be loaded.
- `.js ` (CommonJS or ES modules depending on `type` field of parent `package.json`)
- `.cjs` (CommonJS)
- `.mjs` (ES modules)
- `.ts` (TypeScript)
The following script types are supported:
- `dirNameRoutePrefix` (optional) - Default: true. Determines whether routes will be automatically prefixed with the subdirectory name in an autoloaded directory. It can be a sync function that must return a string that will be used as prefix, or it must return `false` to skip the prefix for the directory.
- `.js ` (CommonJS or ES modules depending on `type` field of parent `package.json`)
- `.cjs` (CommonJS)
- `.mjs` (ES modules)
- `.ts` (TypeScript)
```js
fastify.register(autoLoad, {
dir: path.join(__dirname, 'routes'),
dirNameRoutePrefix: false // lack of prefix will mean no prefix, instead of directory name
})
### `dirNameRoutePrefix` (optional) - Default: `true`
fastify.register(autoLoad, {
dir: path.join(__dirname, 'routes'),
dirNameRoutePrefix: function rewrite (folderParent, folderName) {
if (folderName === 'YELLOW') {
return 'yellow-submarine'
}
if (folderName === 'FoOoO-BaAaR') {
return false
}
return folderName
Determines whether routes will be automatically prefixed with the subdirectory name in an autoloaded directory. It can be a sync function that must return a string that will be used as prefix, or it must return `false` to skip the prefix for the directory.
```js
fastify.register(autoLoad, {
dir: path.join(__dirname, 'routes'),
dirNameRoutePrefix: false // lack of prefix will mean no prefix, instead of directory name
})
fastify.register(autoLoad, {
dir: path.join(__dirname, 'routes'),
dirNameRoutePrefix: function rewrite (folderParent, folderName) {
if (folderName === 'YELLOW') {
return 'yellow-submarine'
}
})
```
if (folderName === 'FoOoO-BaAaR') {
return false
}
return folderName
}
})
```
- `matchFilter` (optional) - Filter matching any path that should be loaded. Can be a RegExp, a string, or a function returning a boolean.
### `matchFilter` (optional)
```js
fastify.register(autoLoad, {
dir: path.join(__dirname, 'plugins'),
matchFilter: (path) => path.split("/").at(-2) === "handlers"
})
```
Filter matching any path that should be loaded. Can be a RegExp, a string, or a function returning a boolean.
```js
fastify.register(autoLoad, {
dir: path.join(__dirname, 'plugins'),
matchFilter: (path) => path.split("/").at(-2) === "handlers"
})
```
- `ignoreFilter` (optional) - Filter matching any path that should not be loaded. Can be a RegExp, a string ,or a function returning a boolean.
```js
fastify.register(autoLoad, {
dir: path.join(__dirname, 'plugins'),
ignoreFilter: (path) => path.endsWith('.spec.js')
})
```
### `ignoreFilter` (optional)
Filter matching any path that should not be loaded. Can be a RegExp, a string ,or a function returning a boolean.
- `ignorePattern` (optional) - RegExp matching any file or folder that should not be loaded.
```js
fastify.register(autoLoad, {
dir: path.join(__dirname, 'plugins'),
ignoreFilter: (path) => path.endsWith('.spec.js')
})
```
```js
fastify.register(autoLoad, {
dir: path.join(__dirname, 'plugins'),
ignorePattern: /^.*(?:test|spec).js$/
})
```
### `ignorePattern` (optional)
RegExp matching any file or folder that should not be loaded.
- `scriptPattern` (optional) - Regex to override the script files accepted by default. You should only use this option
with a [customization hooks](https://nodejs.org/docs/latest/api/module.html#customization-hooks)
provider, such as `ts-node`. Otherwise, widening the acceptance extension here will result in an error.
```js
fastify.register(autoLoad, {
dir: path.join(__dirname, 'plugins'),
ignorePattern: /^.*(?:test|spec).js$/
})
```
### `scriptPattern` (optional)
```js
fastify.register(autoLoad, {
dir: path.join(__dirname, 'plugins'),
scriptPattern: /(?<!\.d)\.(ts|tsx)$/
})
```
Regex to override the script files accepted by default. You should only use this option with a [customization hooks](https://nodejs.org/docs/latest/api/module.html#customization-hooks)provider, such as `ts-node`. Otherwise, widening the acceptance extension here will result in an error.
- `indexPattern` (optional) - Regex to override the `index.js` naming convention
```js
fastify.register(autoLoad, {
dir: path.join(__dirname, 'plugins'),
indexPattern: /^.*routes(?:\.ts|\.js|\.cjs|\.mjs)$/
})
```
```js
fastify.register(autoLoad, {
dir: path.join(__dirname, 'plugins'),
scriptPattern: /(?<!\.d)\.(ts|tsx)$/
})
```
- `maxDepth` (optional) - Limits the depth at which nested plugins are loaded
### `indexPattern` (optional)
```js
fastify.register(autoLoad, {
dir: path.join(__dirname, 'plugins'),
maxDepth: 2 // files in `opts.dir` nested more than 2 directories deep will be ignored.
})
```
Regex to override the `index.js` naming convention.
- `forceESM` (optional) - If set to 'true' it always use `await import` to load plugins or hooks.
```js
fastify.register(autoLoad, {
dir: path.join(__dirname, 'plugins'),
indexPattern: /^.*routes(?:\.ts|\.js|\.cjs|\.mjs)$/
})
```
```js
fastify.register(autoLoad, {
dir: path.join(__dirname, 'plugins'),
forceESM: true
})
```
- `encapsulate` (optional) - Defaults to 'true', if set to 'false' each plugin loaded is wrapped with [fastify-plugin](https://github.com/fastify/fastify-plugin). This allows you to share contexts between plugins and the parent context if needed. For example, if you need to share decorators. Read [this](https://github.com/fastify/fastify/blob/main/docs/Reference/Encapsulation.md#sharing-between-contexts) for more details.
### `maxDepth` (optional)
```js
fastify.register(autoLoad, {
dir: path.join(__dirname, 'plugins'),
encapsulate: false
})
```
Limits the depth at which nested plugins are loaded.
- `options` (optional) - Global options object used for all registered plugins
```js
fastify.register(autoLoad, {
dir: path.join(__dirname, 'plugins'),
maxDepth: 2 // files in `opts.dir` nested more than 2 directories deep will be ignored.
})
```
Any option specified here will override `plugin.autoConfig` options specified in the plugin itself.
### `forceESM` (optional)
When setting both `options.prefix` and `plugin.autoPrefix` they will be concatenated.
If set to 'true' it always use `await import` to load plugins or hooks.
```js
// index.js
fastify.register(autoLoad, {
dir: path.join(__dirname, 'plugins'),
options: { prefix: '/defaultPrefix' }
})
```js
fastify.register(autoLoad, {
dir: path.join(__dirname, 'plugins'),
forceESM: true
})
```
// /plugins/something.js
module.exports = function (fastify, opts, next) {
// your plugin
}
### `encapsulate` (optional) - Default: `true`
module.exports.autoPrefix = '/something'
If set to `false` each plugin loaded is wrapped with [fastify-plugin](https://github.com/fastify/fastify-plugin). This allows you to share contexts between plugins and the parent context if needed. For example, if you need to share decorators. Read [this](https://github.com/fastify/fastify/blob/main/docs/Reference/Encapsulation.md#sharing-between-contexts) for more details.
// /plugins/something.mjs
export default function (f, opts, next) {
f.get('/', (request, reply) => {
reply.send({ something: 'else' })
})
```js
fastify.register(autoLoad, {
dir: path.join(__dirname, 'plugins'),
encapsulate: false
})
```
next()
}
### `options` (optional)
export const autoPrefix = '/prefixed'
Global options object used for all registered plugins.
// routes can now be added to /defaultPrefix/something
```
Any option specified here will override `plugin.autoConfig` options specified in the plugin itself.
- `autoHooks` (optional) - Apply hooks from `autohooks.js` file(s) to plugins found in folder
When setting both `options.prefix` and `plugin.autoPrefix` they will be concatenated.
Automatic hooks from `autohooks` files will be encapsulated with plugins. If `false`, all `autohooks.js` files will be ignored.
```js
// index.js
fastify.register(autoLoad, {
dir: path.join(__dirname, 'plugins'),
options: { prefix: '/defaultPrefix' }
})
```js
fastify.register(autoLoad, {
dir: path.join(__dirname, 'plugins'),
autoHooks: true // apply hooks to routes in this level
// /plugins/something.js
module.exports = function (fastify, opts, next) {
// your plugin
}
module.exports.autoPrefix = '/something'
// /plugins/something.mjs
export default function (f, opts, next) {
f.get('/', (request, reply) => {
reply.send({ something: 'else' })
})
```
If `autoHooks` is set, all plugins in the folder will be [encapsulated](https://github.com/fastify/fastify/blob/main/docs/Reference/Encapsulation.md)
and decorated values _will not be exported_ outside the folder.
next()
}
- `autoHooksPattern` (optional) - Regex to override the `autohooks` naming convention
export const autoPrefix = '/prefixed'
```js
fastify.register(autoLoad, {
dir: path.join(__dirname, 'plugins'),
autoHooks: true,
autoHooksPattern: /^[_.]?auto_?hooks(?:\.js|\.cjs|\.mjs)$/i
})
```
// routes can now be added to /defaultPrefix/something
```
- `cascadeHooks` (optional) - If using `autoHooks`, cascade hooks to all children. Ignored if `autoHooks` is `false`.
### `autoHooks` (optional)
Default behavior of `autoHooks` is to apply hooks only to the level on which the `autohooks.js` file is found. Setting `cascadeHooks: true` will continue applying the hooks to any children.
Apply hooks from `autohooks.js` file(s) to plugins found in folder.
```js
fastify.register(autoLoad, {
dir: path.join(__dirname, 'plugins'),
autoHooks: true, // apply hooks to routes in this level,
cascadeHooks: true // continue applying hooks to children, starting at this level
})
```
Automatic hooks from `autohooks` files will be encapsulated with plugins. If `false`, all `autohooks.js` files will be ignored.
- `overwriteHooks` (optional) - If using `cascadeHooks`, cascade will be reset when a new `autohooks.js` file is encountered. Ignored if `autoHooks` is `false`.
```js
fastify.register(autoLoad, {
dir: path.join(__dirname, 'plugins'),
autoHooks: true // apply hooks to routes in this level
})
```
Default behavior of `cascadeHooks` is to accumulate hooks as new `autohooks.js` files are discovered and cascade to children. Setting `overwriteHooks: true` will start a new hook cascade when new `autohooks.js` files are encountered.
If `autoHooks` is set, all plugins in the folder will be [encapsulated](https://github.com/fastify/fastify/blob/main/docs/Reference/Encapsulation.md)
and decorated values _will not be exported_ outside the folder.
```js
fastify.register(autoLoad, {
dir: path.join(__dirname, 'plugins'),
autoHooks: true, // apply hooks to routes in this level,
cascadeHooks: true, // continue applying hooks to children, starting at this level,
overwriteHooks: true // re-start hook cascade when a new `autohooks.js` file is found
})
```
### `autoHooksPattern` (optional)
- `routeParams` (optional) - Folders prefixed with `_` will be turned into route parameters.
Regex to override the `autohooks` naming convention.
If you want to use mixed route parameters use a double underscore `__`.
```js
fastify.register(autoLoad, {
dir: path.join(__dirname, 'plugins'),
autoHooks: true,
autoHooksPattern: /^[_.]?auto_?hooks(?:\.js|\.cjs|\.mjs)$/i
})
```
```js
/*
├── routes
├── __country-__language
│   │ └── actions.js
│ └── users
│ ├── _id
│ │ └── actions.js
│ ├── __country-__language
│ │ └── actions.js
│ └── index.js
└── app.js
*/
### `cascadeHooks` (optional)
fastify.register(autoLoad, {
dir: path.join(__dirname, 'routes'),
routeParams: true
// routes/users/_id/actions.js will be loaded with prefix /users/:id
// routes/__country-__language/actions.js will be loaded with prefix /:country-:language
})
If using `autoHooks`, cascade hooks to all children. Ignored if `autoHooks` is `false`.
// curl http://localhost:3000/users/index
// { userIndex: [ { id: 7, username: 'example' } ] }
Default behavior of `autoHooks` is to apply hooks only to the level on which the `autohooks.js` file is found. Setting `cascadeHooks: true` will continue applying the hooks to any children.
// curl http://localhost:3000/users/7/details
// { user: { id: 7, username: 'example' } }
```js
fastify.register(autoLoad, {
dir: path.join(__dirname, 'plugins'),
autoHooks: true, // apply hooks to routes in this level,
cascadeHooks: true // continue applying hooks to children, starting at this level
})
```
// curl http://localhost:3000/be-nl
// { country: 'be', language: 'nl' }
```
### `overwriteHooks` (optional)
If using `cascadeHooks`, cascade will be reset when a new `autohooks.js` file is encountered. Ignored if `autoHooks` is `false`.
Default behavior of `cascadeHooks` is to accumulate hooks as new `autohooks.js` files are discovered and cascade to children. Setting `overwriteHooks: true` will start a new hook cascade when new `autohooks.js` files are encountered.
```js
fastify.register(autoLoad, {
dir: path.join(__dirname, 'plugins'),
autoHooks: true, // apply hooks to routes in this level,
cascadeHooks: true, // continue applying hooks to children, starting at this level,
overwriteHooks: true // re-start hook cascade when a new `autohooks.js` file is found
})
```
### `routeParams` (optional)
Folders prefixed with `_` will be turned into dynamic route parameters. If you want to use mixed route parameters use a double underscore `__`.
```js
/*
├── routes
├── __country-__language
│   │ └── actions.js
│ └── users
│ ├── _id
│ │ └── actions.js
│ ├── __country-__language
│ │ └── actions.js
│ └── index.js
└── app.js
*/
fastify.register(autoLoad, {
dir: path.join(__dirname, 'routes'),
routeParams: true
// routes/users/_id/actions.js will be loaded with prefix /users/:id
// routes/__country-__language/actions.js will be loaded with prefix /:country-:language
})
// curl http://localhost:3000/users/index
// { userIndex: [ { id: 7, username: 'example' } ] }
// curl http://localhost:3000/users/7/details
// { user: { id: 7, username: 'example' } }
// curl http://localhost:3000/be-nl
// { country: 'be', language: 'nl' }
```
## Override TypeScript detection using an environment variable
This plugin uses [native type stripping](https://nodejs.org/docs/latest-v23.x/api/typescript.html#modules-typescript) with Node 23 and later.

@@ -339,259 +367,270 @@

- `plugin.autoConfig` - Specifies the options to be used as the `opts` parameter.
### `plugin.autoConfig`
```js
module.exports = function (fastify, opts, next) {
console.log(opts.foo) // 'bar'
next()
}
Specifies the options to be used as the `opts` parameter.
module.exports.autoConfig = { foo: 'bar' }
```
```js
module.exports = function (fastify, opts, next) {
console.log(opts.foo) // 'bar'
next()
}
Or with ESM syntax:
module.exports.autoConfig = { foo: 'bar' }
```
```js
import plugin from '../lib-plugin.js'
Or with ESM syntax:
export default async function myPlugin (app, options) {
app.get('/', async (request, reply) => {
return { hello: options.name }
})
}
export const autoConfig = { name: 'y' }
```
```js
import plugin from '../lib-plugin.js'
You can also use a callback function if you need to access the parent instance:
```js
export const autoConfig = (fastify) => {
return { name: 'y ' + fastify.rootName }
}
```
export default async function myPlugin (app, options) {
app.get('/', async (request, reply) => {
return { hello: options.name }
})
}
export const autoConfig = { name: 'y' }
```
However, note that the `prefix` option should be set directly on `autoConfig` for autoloading to work as expected:
```js
export const autoConfig = (fastify) => {
return { name: 'y ' + fastify.rootName }
}
You can also use a callback function if you need to access the parent instance:
```js
export const autoConfig = (fastify) => {
return { name: 'y ' + fastify.rootName }
}
```
autoConfig.prefix = '/hello'
```
However, note that the `prefix` option should be set directly on `autoConfig` for autoloading to work as expected:
```js
export const autoConfig = (fastify) => {
return { name: 'y ' + fastify.rootName }
}
- `plugin.autoPrefix` - Set routing prefix for plugin
autoConfig.prefix = '/hello'
```
```js
module.exports = function (fastify, opts, next) {
fastify.get('/', (request, reply) => {
reply.send({ hello: 'world' })
})
### `plugin.autoPrefix`
next()
}
Set routing prefix for plugin.
module.exports.autoPrefix = '/something'
```js
module.exports = function (fastify, opts, next) {
fastify.get('/', (request, reply) => {
reply.send({ hello: 'world' })
})
// when loaded with autoload, this will be exposed as /something
```
next()
}
Or with ESM syntax:
module.exports.autoPrefix = '/something'
```js
export default async function (app, opts) {
app.get('/', (request, reply) => {
return { something: 'else' }
})
}
// when loaded with autoload, this will be exposed as /something
```
export const autoPrefix = '/prefixed'
```
Or with ESM syntax:
```js
export default async function (app, opts) {
app.get('/', (request, reply) => {
return { something: 'else' }
})
}
- `plugin.prefixOverride` - Override all other prefix options
export const autoPrefix = '/prefixed'
```
```js
// index.js
fastify.register(autoLoad, {
dir: path.join(__dirname, 'plugins'),
options: { prefix: '/defaultPrefix' }
})
### `plugin.prefixOverride`
// /foo/something.js
module.exports = function (fastify, opts, next) {
// your plugin
}
Override all other prefix options.
module.exports.prefixOverride = '/overriddenPrefix'
```js
// index.js
fastify.register(autoLoad, {
dir: path.join(__dirname, 'plugins'),
options: { prefix: '/defaultPrefix' }
})
// this will be exposed as /overriddenPrefix
```
// /foo/something.js
module.exports = function (fastify, opts, next) {
// your plugin
}
Or with ESM syntax:
module.exports.prefixOverride = '/overriddenPrefix'
```js
export default async function (app, opts) {
// your plugin
}
// this will be exposed as /overriddenPrefix
```
export const prefixOverride = '/overriddenPrefix'
```
Or with ESM syntax:
If you have a plugin in the folder you do not want any prefix applied to, you can set `prefixOverride = ''`:
```js
export default async function (app, opts) {
// your plugin
}
```js
// index.js
fastify.register(autoLoad, {
dir: path.join(__dirname, 'plugins'),
options: { prefix: '/defaultPrefix' }
})
export const prefixOverride = '/overriddenPrefix'
```
// /foo/something.js
module.exports = function (fastify, opts, next) {
// your plugin
}
If you have a plugin in the folder you do not want any prefix applied to, you can set `prefixOverride = ''`:
// optional
module.exports.prefixOverride = ''
```js
// index.js
fastify.register(autoLoad, {
dir: path.join(__dirname, 'plugins'),
options: { prefix: '/defaultPrefix' }
})
// routes can now be added without a prefix
```
// /foo/something.js
module.exports = function (fastify, opts, next) {
// your plugin
}
- `plugin.autoload` - Toggle whether the plugin should be loaded
// optional
module.exports.prefixOverride = ''
Example:
// routes can now be added without a prefix
```
```js
module.exports = function (fastify, opts, next) {
// your plugin
}
### `plugin.autoload`
// optional
module.exports.autoload = false
```
Toggle whether the plugin should be loaded.
- `opts.name` - Set name of plugin so that it can be referenced as a dependency
Example:
- `opts.dependencies` - Set plugin dependencies to ensure correct load order
```js
module.exports = function (fastify, opts, next) {
// your plugin
}
Example:
// optional
module.exports.autoload = false
```
```js
// plugins/plugin-a.js
const fp = require('fastify-plugin')
### `opts.name`
function plugin (fastify, opts, next) {
// plugin a
}
Set name of plugin so that it can be referenced as a dependency.
module.exports = fp(plugin, {
name: 'plugin-a',
dependencies: ['plugin-b']
})
### `opts.dependencies`
// plugins/plugin-b.js
function plugin (fastify, opts, next) {
// plugin b
}
Set plugin dependencies to ensure correct load order.
module.exports = fp(plugin, {
name: 'plugin-b'
})
```
Example:
## Autohooks:
```js
// plugins/plugin-a.js
const fp = require('fastify-plugin')
The autohooks functionality provides several options for automatically adding hooks, decorators, etc. to your routes. CJS and ESM `autohook` formats are supported.
function plugin (fastify, opts, next) {
// plugin a
}
The default behavior of `autoHooks: true` is to encapsulate the `autohooks.js` plugin with the contents of the folder containing the file. The `cascadeHooks: true` option encapsulates the hooks with the current folder contents and all subsequent children, with any additional `autohooks.js` files being applied cumulatively. The `overwriteHooks: true` option will restart the cascade any time an `autohooks.js` file is encountered.
module.exports = fp(plugin, {
name: 'plugin-a',
dependencies: ['plugin-b']
})
Plugins and hooks are encapsulated together by folder and registered on the `fastify` instance that loaded the `@fastify/autoload` plugin. For more information on how encapsulation works in Fastify, see: https://fastify.dev/docs/latest/Reference/Encapsulation/#encapsulation
// plugins/plugin-b.js
function plugin (fastify, opts, next) {
// plugin b
}
### Example:
module.exports = fp(plugin, {
name: 'plugin-b'
})
```
```
├── plugins
│ ├── hooked-plugin
│ │ ├── autohooks.js // req.hookOne = 'yes' # CJS syntax
│ │ ├── routes.js
│ │ └── children
│ │ ├── old-routes.js
│ │ ├── new-routes.js
│ │ └── grandchildren
│ │ ├── autohooks.mjs // req.hookTwo = 'yes' # ESM syntax
│ │ └── routes.mjs
│ └── standard-plugin
│ └── routes.js
└── app.js
```
## Autohooks:
```js
// hooked-plugin/autohooks.js
The autohooks functionality provides several options for automatically adding hooks, decorators, etc. to your routes. CJS and ESM `autohook` formats are supported.
module.exports = async function (app, opts) {
app.addHook('onRequest', async (req, reply) => {
req.hookOne = yes;
});
}
The default behavior of `autoHooks: true` is to encapsulate the `autohooks.js` plugin with the contents of the folder containing the file. The `cascadeHooks: true` option encapsulates the hooks with the current folder contents and all subsequent children, with any additional `autohooks.js` files being applied cumulatively. The `overwriteHooks: true` option will restart the cascade any time an `autohooks.js` file is encountered.
// hooked-plugin/children/grandchildren/autohooks.mjs
Plugins and hooks are encapsulated together by folder and registered on the `fastify` instance that loaded the `@fastify/autoload` plugin. For more information on how encapsulation works in Fastify, see: https://fastify.dev/docs/latest/Reference/Encapsulation/#encapsulation
export default async function (app, opts) {
app.addHook('onRequest', async (req, reply) => {
req.hookTwo = yes
})
}
```
### Example:
```bash
# app.js { autoHooks: true }
```
├── plugins
│ ├── hooked-plugin
│ │ ├── autohooks.js // req.hookOne = 'yes' # CJS syntax
│ │ ├── routes.js
│ │ └── children
│ │ ├── old-routes.js
│ │ ├── new-routes.js
│ │ └── grandchildren
│ │ ├── autohooks.mjs // req.hookTwo = 'yes' # ESM syntax
│ │ └── routes.mjs
│ └── standard-plugin
│ └── routes.js
└── app.js
```
$ curl http://localhost:3000/standard-plugin/
{} # no hooks in this folder, so behavior is unchanged
```js
// hooked-plugin/autohooks.js
$ curl http://localhost:3000/hooked-plugin/
{ hookOne: 'yes' }
module.exports = async function (app, opts) {
app.addHook('onRequest', async (req, reply) => {
req.hookOne = yes;
});
}
$ curl http://localhost:3000/hooked-plugin/children/old
{}
// hooked-plugin/children/grandchildren/autohooks.mjs
$ curl http://localhost:3000/hooked-plugin/children/new
{}
export default async function (app, opts) {
app.addHook('onRequest', async (req, reply) => {
req.hookTwo = yes
})
}
```
$ curl http://localhost:3000/hooked-plugin/children/grandchildren/
{ hookTwo: 'yes' }
```
```bash
# app.js { autoHooks: true }
```bash
# app.js { autoHooks: true, cascadeHooks: true }
$ curl http://localhost:3000/standard-plugin/
{} # no hooks in this folder, so behavior is unchanged
$ curl http://localhost:3000/hooked-plugin/
{ hookOne: 'yes' }
$ curl http://localhost:3000/hooked-plugin/
{ hookOne: 'yes' }
$ curl http://localhost:3000/hooked-plugin/children/old
{ hookOne: 'yes' }
$ curl http://localhost:3000/hooked-plugin/children/old
{}
$ curl http://localhost:3000/hooked-plugin/children/new
{ hookOne: 'yes' }
$ curl http://localhost:3000/hooked-plugin/children/new
{}
$ curl http://localhost:3000/hooked-plugin/children/grandchildren/
{ hookOne: 'yes', hookTwo: 'yes' } # hooks are accumulated and applied in ascending order
```
$ curl http://localhost:3000/hooked-plugin/children/grandchildren/
{ hookTwo: 'yes' }
```
```bash
# app.js { autoHooks: true, cascadeHooks: true, overwriteHooks: true }
```bash
# app.js { autoHooks: true, cascadeHooks: true }
$ curl http://localhost:3000/hooked-plugin/
{ hookOne: 'yes' }
$ curl http://localhost:3000/hooked-plugin/
{ hookOne: 'yes' }
$ curl http://localhost:3000/hooked-plugin/children/old
{ hookOne: 'yes' }
$ curl http://localhost:3000/hooked-plugin/children/old
{ hookOne: 'yes' }
$ curl http://localhost:3000/hooked-plugin/children/new
{ hookOne: 'yes' }
$ curl http://localhost:3000/hooked-plugin/children/new
{ hookOne: 'yes' }
$ curl http://localhost:3000/hooked-plugin/children/grandchildren/
{ hookTwo: 'yes' } # new autohooks.js takes over
```
$ curl http://localhost:3000/hooked-plugin/children/grandchildren/
{ hookOne: 'yes', hookTwo: 'yes' } # hooks are accumulated and applied in ascending order
```
```bash
# app.js { autoHooks: true, cascadeHooks: true, overwriteHooks: true }
$ curl http://localhost:3000/hooked-plugin/
{ hookOne: 'yes' }
$ curl http://localhost:3000/hooked-plugin/children/old
{ hookOne: 'yes' }
$ curl http://localhost:3000/hooked-plugin/children/new
{ hookOne: 'yes' }
$ curl http://localhost:3000/hooked-plugin/children/grandchildren/
{ hookTwo: 'yes' } # new autohooks.js takes over
```
## License
Licensed under [MIT](./LICENSE).

@@ -7,3 +7,4 @@ 'use strict'

'node',
'--require=@swc-node/register',
'-r',
'@swc-node/register',
'test/typescript/basic.ts'

@@ -10,0 +11,0 @@ ]

@@ -1,40 +0,33 @@

'use script'
'use strict'
const { test: t } = require('node:test')
const { test: testRunner } = require('node:test')
const assert = require('node:assert/strict')
const fastify = require('fastify')
const basicApp = require('./basic/app.ts')
t.plan(5)
testRunner('integration test with fastify autoload', async (t: any) => {
const app = fastify()
app.register(basicApp)
const app = fastify()
await app.ready()
app.register(basicApp)
app.ready(async function (err) {
t.error(err)
await app
.inject({
await t.test('should return javascript data', async () => {
const res = await app.inject({
url: '/javascript',
})
.then(function (res: any) {
t.equal(res.statusCode, 200)
t.same(JSON.parse(res.payload), { script: 'java' })
})
.catch((err) => {
t.error(err)
})
await app
.inject({
assert.strictEqual(res.statusCode, 200)
assert.deepStrictEqual(res.json(), { script: 'java' })
})
await t.test('should return typescript data', async () => {
const res = await app.inject({
url: '/typescript',
})
.then(function (res: any) {
t.equal(res.statusCode, 200)
t.same(JSON.parse(res.payload), { script: 'type' })
})
.catch((err) => {
t.error(err)
})
assert.strictEqual(res.statusCode, 200)
assert.deepStrictEqual(res.json(), { script: 'type' })
})
await app.close()
})

@@ -1,2 +0,2 @@

import test, { describe, before, after } from 'node:test'
import { describe, test } from 'node:test'
import assert from 'node:assert'

@@ -13,16 +13,13 @@ import fastify from 'fastify'

const app = fastify()
before(async function () {
test('should load routes and respond correctly', async function () {
app.register(fastifyAutoLoad, { dir: resolve(__dirname, 'app'), forceESM: true })
await app.ready()
})
after(async function () {
await app.close()
})
test('should load routes and respond correctly', async function () {
const res = await app.inject({ url: '/installed' })
assert.strictEqual(res.statusCode, 200)
assert.deepStrictEqual(JSON.parse(res.payload), { result: 'ok' })
await app.close()
})
})

@@ -10,5 +10,7 @@ import fastify from 'fastify'

}, function (err) {
if (err) process.stderr.write('failed')
if (err) {
process.stderr.write('failed')
}
process.stdout.write('success')
app.close()
})
import { exec } from 'node:child_process'
import { join } from 'node:path'
describe('integration test', function () {
const isWindows = process.platform === 'win32'
test.concurrent.each(['ts-node', 'ts-node-dev'])(

@@ -8,3 +11,24 @@ 'integration with %s',

await new Promise(function (resolve) {
const child = exec(`${instance} "${process.cwd()}/test/typescript-jest/integration/instance.ts"`)
const compilerOpts = JSON.stringify({
module: 'commonjs',
moduleResolution: 'node',
esModuleInterop: true
})
const optionsArg = isWindows
? `"${compilerOpts.replace(/"/g, '\\"')}"`
: `'${compilerOpts}'`
const filePath = join(
process.cwd(),
'test',
'typescript-jest',
'integration',
'instance.ts'
)
const child = exec(
`npx ${instance} --compiler-options ${optionsArg} "${filePath}"`
)
let stderr = ''

@@ -18,2 +42,3 @@ child.stderr?.on('data', function (b) {

})
child.once('close', function () {

@@ -26,4 +51,4 @@ expect(stderr.includes('failed')).toStrictEqual(false)

},
30000
isWindows ? 60000 : 30000
)
})
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 15
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 7
# Issues with these labels will never be considered stale
exemptLabels:
- "discussion"
- "feature request"
- "bug"
- "help wanted"
- "plugin suggestion"
- "good first issue"
# Label to use when marking an issue as stale
staleLabel: stale
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false
'use strict'
const { exec } = require('node:child_process')
const args = [
'TSIMP_PROJECT=tsconfig.tsimp.json',
'node',
'--import=tsimp/import',
'test/typescript/basic.ts'
]
const child = exec(args.join(' '), {
shell: true
})
child.stdout.pipe(process.stdout)
child.stderr.pipe(process.stderr)
child.once('close', process.exit)
module.exports = async (fastify) => {
fastify.get('/', function () {
return { foo: 'bar' }
})
}
module.exports = async (fastify) => {
fastify.get('/', function () {
return { hello: 'world' }
})
}
import fastify, { FastifyInstance, FastifyPluginCallback } from 'fastify'
import { expectType } from 'tsd'
import * as fastifyAutoloadStar from '..'
import fastifyAutoloadDefault, { AutoloadPluginOptions, fastifyAutoload as fastifyAutoloadNamed } from '..'
import fastifyAutoloadCjsImport = require('..')
const fastifyAutoloadCjs = require('..')
const app: FastifyInstance = fastify()
app.register(fastifyAutoloadNamed, { dir: 'test' })
app.register(fastifyAutoloadDefault, { dir: 'test' })
app.register(fastifyAutoloadCjs, { dir: 'test' })
app.register(fastifyAutoloadCjsImport.default, { dir: 'test' })
app.register(fastifyAutoloadCjsImport.fastifyAutoload, { dir: 'test' })
app.register(fastifyAutoloadStar.default, { dir: 'test' })
app.register(fastifyAutoloadStar.fastifyAutoload, { dir: 'test' })
expectType<FastifyPluginCallback<AutoloadPluginOptions>>(fastifyAutoloadNamed)
expectType<FastifyPluginCallback<AutoloadPluginOptions>>(fastifyAutoloadDefault)
expectType<FastifyPluginCallback<AutoloadPluginOptions>>(fastifyAutoloadCjsImport.default)
expectType<FastifyPluginCallback<AutoloadPluginOptions>>(fastifyAutoloadCjsImport.fastifyAutoload)
expectType<FastifyPluginCallback<AutoloadPluginOptions>>(fastifyAutoloadStar.default)
expectType<FastifyPluginCallback<AutoloadPluginOptions>>(fastifyAutoloadStar.fastifyAutoload)
expectType<any>(fastifyAutoloadCjs)
const opt1: AutoloadPluginOptions = {
dir: 'test'
}
const opt2: AutoloadPluginOptions = {
dir: 'test',
ignorePattern: /skip/
}
const opt3: AutoloadPluginOptions = {
dir: 'test',
scriptPattern: /js/,
indexPattern: /index/,
}
const opt4: AutoloadPluginOptions = {
dir: 'test',
options: {
prefix: 'test'
}
}
const opt5: AutoloadPluginOptions = {
dir: 'test',
maxDepth: 1,
}
const opt6: AutoloadPluginOptions = {
dir: 'test',
routeParams: true,
}
const opt7: AutoloadPluginOptions = {
dir: 'test',
forceESM: true,
autoHooks: true,
autoHooksPattern: /^[_.]?auto_?hooks(?:\.ts|\.js|\.cjs|\.mjs)$/i,
cascadeHooks: true,
overwriteHooks: true,
}
const opt8: AutoloadPluginOptions = {
dir: 'test',
encapsulate: false,
}
const opt9: AutoloadPluginOptions = {
dir: 'test',
ignoreFilter: /test/,
matchFilter: /handler/
}
const opt10: AutoloadPluginOptions = {
dir: 'test',
ignoreFilter: 'test',
matchFilter: 'handler'
}
const opt11: AutoloadPluginOptions = {
dir: 'test',
ignoreFilter: (path) => path.endsWith('.spec.ts'),
matchFilter: (path) => path.split('/').at(-2) === 'handlers'
}
app.register(fastifyAutoloadDefault, opt1)
app.register(fastifyAutoloadDefault, opt2)
app.register(fastifyAutoloadDefault, opt3)
app.register(fastifyAutoloadDefault, opt4)
app.register(fastifyAutoloadDefault, opt5)
app.register(fastifyAutoloadDefault, opt6)
app.register(fastifyAutoloadDefault, opt7)
app.register(fastifyAutoloadDefault, opt8)
app.register(fastifyAutoloadDefault, opt9)
app.register(fastifyAutoloadDefault, opt10)
app.register(fastifyAutoloadDefault, opt11)