UNPKG

@thisismissem/adonisjs-respond-with

Version:

A small plugin for Adonis.js to make responding with different content-types easier.

96 lines (95 loc) 3.61 kB
import * as mime from 'mime-types'; import app from '@adonisjs/core/services/app'; export class AcceptNegotiator { config; logger; cache; handlerTypes; constructor(config, logger) { this.config = config; this.logger = logger; this.config = config; this.cache = new WeakMap(); this.handlerTypes = new Map(); // This allows users to define custom named content-types. // // `turbo() => turbo.append()` but the turbo type isn't known to mime-types, // so we need to create a mapping for from `text/vnd.turbo-stream.html` to `turbo` for (const [contentType, handlerName] of Object.entries(this.config.mappings)) { const handlerTypes = this.handlerTypes.get(handlerName); if (handlerTypes === undefined) { this.handlerTypes.set(handlerName, [contentType]); } else { this.handlerTypes.set(handlerName, handlerTypes.concat(contentType)); } } // We don't want to assert code coverage on debugging code: /* c8 ignore start */ if (logger.isLevelEnabled('trace')) { logger.trace({ respondWith: { handlerTypes: Array.from(this.handlerTypes.keys()), }, }, 'Initialized respond with'); } /* c8 ignore end */ } get defaultHandler() { return this.config.defaultHandler; } processMatchers(matchers) { // Don't cache the matchers in dev, as this will cause issues if they're changed: if (!app.inDev) { const cached = this.cache.get(matchers); if (cached) { return cached; } } const uncached = this.process(matchers); if (!app.inDev) { this.cache.set(matchers, uncached); } return uncached; } process(matchers) { const names = Object.keys(matchers); const unknownTypes = new Set(); const acceptedTypes = new Set(); const handlers = new Map(); for (const name of names) { const knownTypes = this.handlerTypes.get(name); if (knownTypes) { knownTypes.forEach((knownType) => { if (!handlers.has(knownType)) { acceptedTypes.add(knownType); handlers.set(knownType, matchers[name]); } }); } else { unknownTypes.add(name); } } for (const name of names) { const mimeType = mime.lookup(name); if (mimeType) { acceptedTypes.add(mimeType); unknownTypes.delete(name); if (handlers.has(mimeType)) { if (handlers.get(mimeType) !== matchers[name]) { this.logger.error({ mimeType, handler: name, originalHandler: handlers.get(mimeType).name }, 'Duplicate handler found for mime-type'); } continue; } handlers.set(mimeType, matchers[name]); } } if (unknownTypes.size > 0) { this.logger.warn({ handlers: Array.from(unknownTypes.values()), }, 'Failed to detect mime-types for handlers, make sure you add custom handler types via the respondWith configuration'); } return { acceptedTypes: Array.from(acceptedTypes.values()).concat('*/*'), handlers }; } }