From dfebf30c811ec32a488badc670311f7a69ea7db8 Mon Sep 17 00:00:00 2001 From: Nicolas Morel Date: Fri, 4 Aug 2023 15:38:27 +0200 Subject: [PATCH] fix: correct exported types (#217) Ported from #214. Fixes #216. Co-authored-by: Danilo Alonso --- API.md | 85 +++++++ lib/index.d.ts | 459 ++++++++++++++++++++--------------- test/index.ts | 8 +- test/types-with-overrides.ts | 118 +++++++++ 4 files changed, 471 insertions(+), 199 deletions(-) create mode 100644 test/types-with-overrides.ts diff --git a/API.md b/API.md index ecd03af..5ddac56 100755 --- a/API.md +++ b/API.md @@ -795,3 +795,88 @@ Returns the closest [Views manager](#views-manager) to your `realm` (either on y ``` + + +## Typescript + +If you'd like to type out the way Vision is used, you can do so with the following interfaces: + +```typescript +declare module '@hapi/vision' { + + // User defined + type CustomTemplates = ( + 'test' | 'hello' | 'temp1' + ); + + // User defined + type CustomLayout = ( + 'auth' | 'unauth' | 'admin' + ) + + interface ViewTypes { + template: CustomTemplates + layout: CustomLayout + } +} +``` + +You should now get typings on your response handler (only), and anywhere where layouts is an option + +```ts + +const route = { + ... + handler: { + view: { + template: 'test', // should autocomplete + options: { layout: 'auth' } // should autocomplete + } + } +} +``` + +If you'd like to also type check the decorated handlers, you can augment the following interfaces: + +```typescript +declare module '@hapi/vision' { + + // User defined + type CustomTemplates = ( + 'test' | 'hello' | 'temp1' + ); + + // User defined + type CustomLayout = ( + 'auth' | 'unauth' | 'admin' + ) + + // server.render(...) + interface RenderMethod { + (template: CustomTemplates, context?: string): Promise + } + + // { handler: (req) => req.render(...) } + interface RequestRenderMethod { + (template: CustomTemplates, context?: string): Promise + } + + // { handler: (req, h) => h.view(...) } + interface ToolkitRenderMethod { + (template: CustomTemplates, context?: string): ResponseObject + } + +} +``` + +This is useful for when you may want to make strict checks against template / context combinations: + +```typescript + + // { handler: (req, h) => h.view(...) } + interface ToolkitRenderMethod { + (template: 'test', context: { apples: 5 }): ResponseObject + (template: 'hello', context: { oranges: true }): ResponseObject + (template: 'temp1', context: { bananas: 'green' }): ResponseObject + } +``` diff --git a/lib/index.d.ts b/lib/index.d.ts index 4cfd4ad..4bbbf26 100644 --- a/lib/index.d.ts +++ b/lib/index.d.ts @@ -1,10 +1,11 @@ -// Type definitions for @hapi/vision 5.5 +// Type definitions for @hapi/vision 7 // Project: https://github.com/hapijs/vision // Definitions by: Jason Swearingen // Alexander James Phillips // Silas Rech -// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped -// TypeScript Version: 2.8 +// Danilo Alonso +// TypeScript Version: 5 + import { Plugin, @@ -12,188 +13,280 @@ import { ResponseObject, } from '@hapi/hapi'; -declare namespace vision { - interface EnginesConfiguration { - /** - * Required object where each key is a file extension (e.g. 'html', 'hbr'), mapped to the npm module used for rendering the templates. - * Alternatively, the extension can be mapped to an object - */ - engines: {[fileExtension: string]: NpmModule} | ServerViewsEnginesOptions; - /** defines the default filename extension to append to template names when multiple engines are configured and no explicit extension is provided for a given template. No default value. */ - defaultExtension?: string | undefined; - } - +interface EnginesConfiguration { /** - * Includes `module` and any of the views options listed below (@see ServerViewsAdditionalOptions) (except defaultExtension) to override the defaults for a specific engine. + * Required object where each key is a file extension (e.g. 'html', 'hbr'), mapped to the npm module used for rendering the templates. + * Alternatively, the extension can be mapped to an object */ - interface ServerViewsEnginesOptions extends ServerViewsConfiguration { - /** - * The npm module used for rendering the templates. The module object must contain the compile() function - * @see {@link https://github.com/hapijs/vision/blob/master/API.md#serverviewsoptions} > options > engines > module - */ - module: NpmModule; - } - interface ServerViewsConfiguration extends ViewHandlerOrReplyOptions, EnginesConfiguration { - /** - * The root file path, or array of file paths, where partials are located. - * Partials are small segments of template code that can be nested and reused throughout other templates. - * Defaults to no partials support (empty path). - */ - partialsPath?: string | string[] | undefined; - /** - * The directory path, or array of directory paths, where helpers are located. - * Helpers are functions used within templates to perform transformations and other data manipulations using the template context or other inputs. - * Each '.js' file in the helpers directory is loaded and the file name is used as the helper name. - * The files must export a single method with the signature function(context) and return a string. - * Sub-folders are not supported and are ignored. Defaults to no helpers support (empty path). - * Note that jade does not support loading helpers this way. - */ - helpersPath?: string | string[] | undefined; - /** if set to false, templates will not be cached (thus will be read from file on every use). Defaults to true. */ - isCached?: boolean | undefined; - } + engines: {[fileExtension: string]: NpmModule} | ServerViewsEnginesOptions; + /** defines the default filename extension to append to template names when multiple engines are configured and no explicit extension is provided for a given template. No default value. */ + defaultExtension?: string; +} +/** + * Includes `module` and any of the views options listed below (@see ServerViewsAdditionalOptions) (except defaultExtension) to override the defaults for a specific engine. + */ +interface ServerViewsEnginesOptions extends ServerViewsConfiguration { /** - * - * @see {@link https://github.com/hapijs/vision/blob/master/API.md#the-view-handler} > options for the list of attributes it can not have (isCached, partialsPath, helpersPath) + * The npm module used for rendering the templates. The module object must contain the compile() function + * @see {@link https://github.com/hapijs/vision/blob/master/API.md#serverviewsoptions} > options > engines > module */ - interface ViewHandlerOrReplyOptions { - /** the root file path, or array of file paths, used to resolve and load the templates identified when calling reply.view(). Defaults to current working directory. */ - path?: string | string[] | undefined; - /** - * a base path used as prefix for path and partialsPath. No default. - */ - relativeTo?: string | undefined; - /** - * If set to true or a layout filename, layout support is enabled. - * A layout is a single template file used as the parent template for other view templates in the same engine. - * If true, the layout template name must be 'layout.ext' where 'ext' is the engine's extension. - * Otherwise, the provided filename is suffixed with the engine's extension and loaded. - * Disable layout when using Jade as it will handle including any layout files independently. - * Defaults to false. - */ - layout?: boolean | string | undefined; - /** the root file path, or array of file paths, where layout templates are located (using the relativeTo prefix if present). Defaults to path. */ - layoutPath?: string | string[] | undefined; - /** the key used by the template engine to denote where primary template content should go. Defaults to 'content'. */ - layoutKeyword?: string | undefined; - /** the text encoding used by the templates when reading the files and outputting the result. Defaults to 'utf8'. */ - encoding?: string | undefined; - /** if set to true, allows absolute template paths passed to reply.view(). Defaults to false. */ - allowAbsolutePaths?: boolean | undefined; - /** if set to true, allows template paths passed to reply.view() to contain '../'. Defaults to false. */ - allowInsecureAccess?: boolean | undefined; - /** options object passed to the engine's compile function. Defaults to empty options {}. */ - compileOptions?: CompileOptions | undefined; - /** options object passed to the returned function from the compile operation. Defaults to empty options {}. */ - runtimeOptions?: RuntimeOptions | undefined; - /** the content type of the engine results. Defaults to 'text/html'. */ - contentType?: string | undefined; - /** specify whether the engine compile() method is 'sync' or 'async'. Defaults to 'sync'. */ - compileMode?: 'sync' | 'async' | undefined; - /** - * A global context used with all templates. - * The global context option can be either an object or a function that takes the request as its only argument and returns a context object. - * The request object is only provided when using the view handler or reply.view(). - * When using server.render() or request.render(), the request argument will be null. - * When rendering views, the global context will be merged with any context object specified on the handler or using reply.view(). - * When multiple context objects are used, values from the global context always have lowest precedence. - */ - context?: object | ((request: Request) => object) | undefined; - } + module: NpmModule; +} +interface ServerViewsConfiguration extends ViewHandlerOrReplyOptions, EnginesConfiguration { /** - * Options passed to module when compiling template. - * Cast your options to this interface or extend it with: - * declare module '@hapi/hapi' { - * interface CompileOptions { - * noEscape: boolean; - * } - * } + * The root file path, or array of file paths, where partials are located. + * Partials are small segments of template code that can be nested and reused throughout other templates. + * Defaults to no partials support (empty path). */ - type CompileOptions = object; - type RuntimeOptions = object; + partialsPath?: string | string[]; + /** + * The directory path, or array of directory paths, where helpers are located. + * Helpers are functions used within templates to perform transformations and other data manipulations using the template context or other inputs. + * Each '.js' file in the helpers directory is loaded and the file name is used as the helper name. + * The files must export a single method with the signature function(context) and return a string. + * Sub-folders are not supported and are ignored. Defaults to no helpers support (empty path). + * Note that jade does not support loading helpers this way. + */ + helpersPath?: string | string[]; + /** if set to false, templates will not be cached (thus will be read from file on every use). Defaults to true. */ + isCached?: boolean; +} +/** + * + * @see {@link https://github.com/hapijs/vision/blob/master/API.md#the-view-handler} > options for the list of attributes it can not have (isCached, partialsPath, helpersPath) + */ +interface ViewHandlerOrReplyOptions { + /** the root file path, or array of file paths, used to resolve and load the templates identified when calling reply.view(). Defaults to current working directory. */ + path?: string | string[]; /** - * The rendering function. The required function signature depends on the compileMode settings (see below). - * - * If compileMode is 'sync', the signature is compile(template, options), - * the return value is a function with signature function(context, options) (the compiled sync template), - * and the method is allowed to throw errors. - * - * If compileMode is 'async', - * the signature is compile(template, options, next) where next has the signature function(err, compiled), - * compiled is a function with signature function(context, options, callback) (the compiled async template) - * and callback has the signature function(err, rendered). + * a base path used as prefix for path and partialsPath. No default. */ - type ServerViewCompileSync = (template: string, options: any) => (context: any, options: any) => void; - type ServerViewCompileAsync = (template: string, options: any, next: ServerViewCompileNext) => void; + relativeTo?: string; + /** + * If set to true or a layout filename, layout support is enabled. + * A layout is a single template file used as the parent template for other view templates in the same engine. + * If true, the layout template name must be 'layout.ext' where 'ext' is the engine's extension. + * Otherwise, the provided filename is suffixed with the engine's extension and loaded. + * Disable layout when using Jade as it will handle including any layout files independently. + * Defaults to false. + */ + layout?: boolean | InViewTypesOr<'layout', string>; + /** the root file path, or array of file paths, where layout templates are located (using the relativeTo prefix if present). Defaults to path. */ + layoutPath?: string | string[]; + /** the key used by the template engine to denote where primary template content should go. Defaults to 'content'. */ + layoutKeyword?: string; + /** the text encoding used by the templates when reading the files and outputting the result. Defaults to 'utf8'. */ + encoding?: string; + /** if set to true, allows absolute template paths passed to reply.view(). Defaults to false. */ + allowAbsolutePaths?: boolean; + /** if set to true, allows template paths passed to reply.view() to contain '../'. Defaults to false. */ + allowInsecureAccess?: boolean; + /** options object passed to the engine's compile function. Defaults to empty options {}. */ + compileOptions?: CompileOptions; + /** options object passed to the returned function from the compile operation. Defaults to empty options {}. */ + runtimeOptions?: RuntimeOptions; + /** the content type of the engine results. Defaults to 'text/html'. */ + contentType?: string; + /** specify whether the engine compile() method is 'sync' or 'async'. Defaults to 'sync'. */ + compileMode?: 'sync' | 'async'; + /** + * A global context used with all templates. + * The global context option can be either an object or a function that takes the request as its only argument and returns a context object. + * The request object is only provided when using the view handler or reply.view(). + * When using server.render() or request.render(), the request argument will be null. + * When rendering views, the global context will be merged with any context object specified on the handler or using reply.view(). + * When multiple context objects are used, values from the global context always have lowest precedence. + */ + context?: object | ((request: Request) => object); +} - type ServerViewCompile = ServerViewCompileSync | ServerViewCompileAsync; +/** + * Options passed to module when compiling template. + * Cast your options to this interface or extend it with: + * declare module '@hapi/hapi' { + * interface CompileOptions { + * noEscape: boolean; + * } + * } + */ +type CompileOptions = object; +type RuntimeOptions = object; - type ServerViewCompileNext = (err: Error | null, compiled: (context: any, options: any, callback: (err: null | Error, rendered: string | null) => void) => void) => void; +/** + * The rendering function. The required function signature depends on the compileMode settings (see below). + * + * If compileMode is 'sync', the signature is compile(template, options), + * the return value is a function with signature function(context, options) (the compiled sync template), + * and the method is allowed to throw errors. + * + * If compileMode is 'async', + * the signature is compile(template, options, next) where next has the signature function(err, compiled), + * compiled is a function with signature function(context, options, callback) (the compiled async template) + * and callback has the signature function(err, rendered). + */ +type ServerViewCompileSync = (template: string, options: any) => (context: any, options: any) => void; +type ServerViewCompileAsync = (template: string, options: any, next: ServerViewCompileNext) => void; +type ServerViewCompile = ServerViewCompileSync | ServerViewCompileAsync; + +type ServerViewCompileNext = (err: Error | null, compiled: (context: any, options: any, callback: (err: null | Error, rendered: string | null) => void) => void) => void; + +/** + * The npm module used for rendering the templates. The module object must contain the compile() function + * @see {@link https://github.com/hapijs/vision/blob/master/API.md#serverviewsoptions} > options > engines > module + */ +interface NpmModule { /** - * The npm module used for rendering the templates. The module object must contain the compile() function - * @see {@link https://github.com/hapijs/vision/blob/master/API.md#serverviewsoptions} > options > engines > module + * The rendering function. The required function signature depends on the compileMode settings */ - interface NpmModule { - /** - * The rendering function. The required function signature depends on the compileMode settings - */ - compile: ServerViewCompile; - /** - * Initializes additional engine state.The config object is the engine configuration object allowing updates to be made. - * This is useful for engines like Nunjucks that rely on additional state for rendering. next has the signature function(err). - */ - prepare?(config: EngineConfigurationObject, next: (err?: Error) => void): void; - /** - * Registers a partial for use during template rendering. - * The name is the partial path that templates should use to reference the partial and src is the uncompiled template string for the partial. - */ - registerPartial?(name: string, src: string): void; - /** - * Registers a helper for use during template rendering. - * The name is the name that templates should use to reference the helper and helper is the function that will be invoked when the helper is called. - */ - registerHelper?(name: string, helper: (...args: any[]) => any): void; - } + compile: ServerViewCompile; + /** + * Initializes additional engine state.The config object is the engine configuration object allowing updates to be made. + * This is useful for engines like Nunjucks that rely on additional state for rendering. next has the signature function(err). + */ + prepare?(config: EngineConfigurationObject, next: (err?: Error) => void): void; + /** + * Registers a partial for use during template rendering. + * The name is the partial path that templates should use to reference the partial and src is the uncompiled template string for the partial. + */ + registerPartial?(name: string, src: string): void; + /** + * Registers a helper for use during template rendering. + * The name is the name that templates should use to reference the helper and helper is the function that will be invoked when the helper is called. + */ + registerHelper?(name: string, helper: (...args: any[]) => any): void; +} - type EngineConfigurationObject = object; +type EngineConfigurationObject = object; +/** + * View Manager + * @see {@link https://github.com/hapijs/vision/blob/master/API.md#view-manager} + */ +interface ViewManager { /** - * Renders a template - * @param template - the template filename and path, relative to the views manager templates path (path or relativeTo). - * @param context - optional object used by the template to render context-specific result. Defaults to no context ({}). - * @param options - optional object used to override the views manager configuration. + * Registers a helper, on all configured engines that have a registerHelper() method, for use during template rendering. + * Engines without a registerHelper() method will be skipped. + * The name is the name that templates should use to reference the helper and helper is the function that will be invoked when the helper is called. + * @param name + * @param helper + * @see {@link https://github.com/hapijs/vision/blob/master/API.md#managerregisterhelpername-helper} */ - type RenderMethod = (template: string, context?: any, options?: ServerViewsConfiguration) => Promise; - + registerHelper(name: string, helper: (...args: any[]) => any): void; /** - * View Manager - * @see {@link https://github.com/hapijs/vision/blob/master/API.md#view-manager} + * Renders a template. This is typically not needed and it is usually more convenient to use server.render(). + * @see {@link https://github.com/hapijs/vision/blob/master/API.md#managerrendertemplate-context-options-callback} */ - interface ViewManager { - /** - * Registers a helper, on all configured engines that have a registerHelper() method, for use during template rendering. - * Engines without a registerHelper() method will be skipped. - * The name is the name that templates should use to reference the helper and helper is the function that will be invoked when the helper is called. - * @param name - * @param helper - * @see {@link https://github.com/hapijs/vision/blob/master/API.md#managerregisterhelpername-helper} - */ - registerHelper(name: string, helper: (...args: any[]) => any): void; - /** - * Renders a template. This is typically not needed and it is usually more convenient to use server.render(). - * @see {@link https://github.com/hapijs/vision/blob/master/API.md#managerrendertemplate-context-options-callback} - */ - render: RenderMethod; - } + render: RenderMethod; +} + +type InViewTypesOr = Key extends keyof ViewTypes ? ViewTypes[Key] : Else; + + +/** + * Overridable interface for defining custom layouts and templates + * explicitly looks for the keywords `template` and `layout` + * + * @example + * + * type CustomTemplates = ( + * 'test' | 'hello' | 'temp1' + * ); + * + * type CustomLayout = ( + * 'auth' | 'unauth' | 'admin' + * ) + * + * declare module '..' { + * + * interface RenderMethod { + * (template: CustomTemplates, context?: string, options?: ServerViewsConfiguration): Promise + * } + * + * interface DecoratedRenderMethod { + * (template: CustomTemplates, context?: string, options?: ViewHandlerOrReplyOptions): Promise + * } + * + * interface ViewTypes { + * template: CustomTemplates + * layout: CustomLayout + * } + * } + * + * server.render('test') + * + * const route = { + * ... + * handler(_, h) { + * + * return h.view('test', null, { layout: 'auth' }); + * } + * } + * + * const route = { + * ... + * handler: { + * view: { + * template: 'hello', + * options: { layout: 'admin' } + * } + * } + * } + */ +export interface ViewTypes {} + +/** + * Renders a template + * @param template - the template filename and path, relative to the views manager templates path (path or relativeTo). + * @param context - optional object used by the template to render context-specific result. Defaults to no context ({}). + * @param options - optional object used to override the views manager configuration. + */ +export interface RenderMethod { + (template: string, context?: any, options?: ServerViewsConfiguration): Promise +} + +/** + * Renders a template + * @param template - the template filename and path, relative to the views manager templates path (path or relativeTo). + * @param context - optional object used by the template to render context-specific result. Defaults to no context ({}). + * @param options - optional object used to override the views manager configuration. + */ +export interface RequestRenderMethod { + (template: string, context?: any, options?: ViewHandlerOrReplyOptions): Promise +} + +/** + * Concludes the handler activity by returning control over to the router with a templatized view response + * Returns a response object. The generated response will have the variety property set to view. + * The response flow control rules apply. + * @param template the template filename and path, relative to the templates path configured via the server views manager. + * @param context optional object used by the template to render context-specific result. Defaults to no context {}. + * @param options optional object used to override the server's views manager configuration for this response. + * Cannot override isCached, partialsPath, or helpersPath which are only loaded at initialization. + * @see {@link https://github.com/hapijs/vision/blob/master/API.md#replyviewtemplate-context-options} + */ +export interface ToolkitRenderMethod { + (templatePath: string, context?: any, options?: ViewHandlerOrReplyOptions): ResponseObject; } -declare const vision: Plugin; -export = vision; +interface ViewHandler { + + /** the template filename and path, relative to the templates path configured via the server views manager. */ + template: InViewTypesOr<'template', string>; + /** optional object used by the template to render context-specific result. Defaults to no context {}. */ + context?: any; + /** + * optional object used to override the server's views manager configuration for this response. + * Cannot override isCached, partialsPath, or helpersPath which are only loaded at initialization. + * TODO check if it can have `defaultExtension`. + */ + options?: ViewHandlerOrReplyOptions; +} + declare module '@hapi/hapi' { interface Server { @@ -201,22 +294,20 @@ declare module '@hapi/hapi' { * Initializes the server views manager * @see {@link https://github.com/hapijs/vision/blob/master/API.md#serverviewsoptions} */ - views(options: vision.ServerViewsConfiguration): vision.ViewManager; + views(options: ServerViewsConfiguration): ViewManager; /** * Utilizes the server views manager to render a template * @see {@link https://github.com/hapijs/vision/blob/master/API.md#serverrendertemplate-context-options-callback} */ - render: vision.RenderMethod; + render: RenderMethod; /** * Returns the closest views manager to your realm (either on your realm or inherited from an ancestor realm) * * @see {@link https://github.com/hapijs/vision/blob/master/API.md#servergetviewsmanager} */ - getViewsManager(): vision.ViewManager; + getViewsManager(): ViewManager; } -} -declare module '@hapi/hapi' { interface Request { /** * request.render() works the same way as server.render() but is for use inside of request handlers. @@ -227,39 +318,25 @@ declare module '@hapi/hapi' { * lifecycle and the request.render() method will produce the same limited results server.render() can. * @see {@link https://github.com/hapijs/vision/blob/master/API.md#requestrendertemplate-context-options-callback} */ - render: vision.RenderMethod; + render: RequestRenderMethod; /** * Returns the closest views manager to your realm (either on your realm or inherited from an ancestor realm) * * @see {@link https://github.com/hapijs/vision/blob/master/API.md#requestgetviewsmanager} */ - getViewsManager(): vision.ViewManager; + getViewsManager(): ViewManager; } -} -declare module '@hapi/hapi' { interface ResponseToolkit { - /** - * Concludes the handler activity by returning control over to the router with a templatized view response - * Returns a response object. The generated response will have the variety property set to view. - * The response flow control rules apply. - * @param template the template filename and path, relative to the templates path configured via the server views manager. - * @param context optional object used by the template to render context-specific result. Defaults to no context {}. - * @param options optional object used to override the server's views manager configuration for this response. - * Cannot override isCached, partialsPath, or helpersPath which are only loaded at initialization. - * @see {@link https://github.com/hapijs/vision/blob/master/API.md#replyviewtemplate-context-options} - */ - view(templatePath: string, context?: any, options?: vision.ViewHandlerOrReplyOptions): ResponseObject; + view: ToolkitRenderMethod /** * Returns the closest views manager to your realm (either on your realm or inherited from an ancestor realm) * * @see {@link https://github.com/hapijs/vision/blob/master/API.md#hgetviewsmanager} */ - getViewsManager(): vision.ViewManager; + getViewsManager(): ViewManager; } -} -declare module '@hapi/hapi' { interface HandlerDecorations { /** * The view handler can be used with routes registered in the same realm as the view manager. @@ -270,17 +347,9 @@ declare module '@hapi/hapi' { * (these can be overriden by values explicitly set via the options). * @see {@link https://github.com/hapijs/vision/blob/master/API.md#the-view-handler} */ - view?: string | { - /** the template filename and path, relative to the templates path configured via the server views manager. */ - template: string; - /** optional object used by the template to render context-specific result. Defaults to no context {}. */ - context?: object | undefined; - /** - * optional object used to override the server's views manager configuration for this response. - * Cannot override isCached, partialsPath, or helpersPath which are only loaded at initialization. - * TODO check if it can have `defaultExtension`. - */ - options?: vision.ViewHandlerOrReplyOptions | undefined; - } | undefined; + view?: string | ViewHandler } } + + +export declare const plugin: Plugin; diff --git a/test/index.ts b/test/index.ts index 477d290..2e96098 100644 --- a/test/index.ts +++ b/test/index.ts @@ -3,7 +3,7 @@ import { Request, ResponseToolkit, } from '@hapi/hapi'; -import { types } from '@hapi/lab' +import { types } from '@hapi/lab'; import * as Vision from '..'; import * as Handlebars from 'handlebars'; @@ -16,7 +16,7 @@ const server = new Server({ const provision = async () => { await server.register({ - plugin: Vision, + plugin: Vision.plugin, options: { engines: { hbs: Handlebars }, path: __dirname + '/templates', @@ -30,7 +30,7 @@ const provision = async () => { types.expect.type(viewManager); const manager = server.getViewsManager(); - types.expect.type(manager) + types.expect.type(manager); manager.registerHelper('test', () => 'test'); @@ -39,7 +39,7 @@ const provision = async () => { message: 'Hello, World', }; - console.log(await server.render('hello', context)); + await server.render('hello', context); server.route({ method: 'GET', diff --git a/test/types-with-overrides.ts b/test/types-with-overrides.ts new file mode 100644 index 0000000..703a2b8 --- /dev/null +++ b/test/types-with-overrides.ts @@ -0,0 +1,118 @@ +import { + Server, + Request, + ResponseToolkit, + ResponseObject, +} from '@hapi/hapi'; +import { types } from '@hapi/lab'; + +import * as Vision from '..'; +import * as Handlebars from 'handlebars'; + +import type { ViewManager } from '..'; + +const server = new Server({ + port: 80, +}); + +type CustomTemplates = ( + 'test' | 'hello' | 'temp1' + ); + +type CustomLayout = ( + 'auth' | 'unauth' | 'admin' + ) + +declare module '..' { + + interface RenderMethod { + (template: CustomTemplates, context?: string, options?: ServerViewsConfiguration): Promise + } + + interface ToolkitRenderMethod { + (template: CustomTemplates, context?: string, options?: ViewHandlerOrReplyOptions): ResponseObject + } + + interface ViewTypes { + template: CustomTemplates + layout: CustomLayout + } +} + + +const provision = async () => { + await server.register({ + plugin: Vision.plugin, + options: { + engines: { hbs: Handlebars }, + path: __dirname + '/templates', + } + }); + + const viewManager = server.views({ + engines: { hbs: Handlebars }, + path: __dirname + '/templates', + }); + types.expect.type(viewManager); + + const manager = server.getViewsManager(); + types.expect.type(manager); + + manager.registerHelper('test', () => 'test'); + + const context = { + title: 'Views Example', + message: 'Hello, World', + }; + + await server.render('hello', context); + + server.route({ + method: 'GET', + path: '/view', + handler: async (request: Request, h: ResponseToolkit) => { + types.expect.type(h.view); + return request.render('test', { message: 'hello' }, { layout: 'admin' }); + }, + }); + + server.route({ + method: 'GET', + path: '/', + handler: { + view: { + template: 'hello', + context: { + title: 'Views Example', + message: 'Hello, World', + }, + }, + }, + }); + + const handler = (request: Request, h: ResponseToolkit) => { + const context = { + title: 'Views Example', + message: 'Hello, World', + }; + return h.view('hello', context); + }; + + server.route({ method: 'GET', path: '/', handler }); + + server.route({ + method: 'GET', + path: '/temp1', + handler: { + view: { + template: 'temp1', + options: { + compileOptions: { + noEscape: true, + }, + layout: 'admin' + }, + }, + }, + }); +};