From a524e8f24e905d5e51fedd50d33a41328a9b87eb Mon Sep 17 00:00:00 2001 From: Stafford Brunk Date: Fri, 11 Jan 2019 01:57:50 -0700 Subject: [PATCH] feat: Add typings to package.json See #1132 --- index.js | 26 +++-- lib/hooks.js | 22 +--- lib/html-tags.js | 4 +- package.json | 3 + typings.d.ts | 285 +++++++++++++++++++++++++++++++++-------------- 5 files changed, 223 insertions(+), 117 deletions(-) diff --git a/index.js b/index.js index e197e8ba..9e91832a 100644 --- a/index.js +++ b/index.js @@ -1,8 +1,9 @@ // @ts-check // Import types -/* eslint-disable */ -/// -/* eslint-enable */ +/** @typedef {import("./typings").HtmlTagObject} HtmlTagObject */ +/** @typedef {import("./typings").Options} HtmlWebpackOptions */ +/** @typedef {import("./typings").ProcessedOptions} ProcessedHtmlWebpackOptions */ +/** @typedef {import("./typings").TemplateParameter} TemplateParameter */ /** @typedef {import("webpack/lib/Compiler.js")} WebpackCompiler */ /** @typedef {import("webpack/lib/Compilation.js")} WebpackCompilation */ 'use strict'; @@ -28,14 +29,14 @@ const fsReadFileAsync = promisify(fs.readFile); class HtmlWebpackPlugin { /** - * @param {Partial} [options] + * @param {HtmlWebpackOptions} [options] */ constructor (options) { - /** @type {Partial} */ + /** @type {HtmlWebpackOptions} */ const userOptions = options || {}; // Default options - /** @type {HtmlWebpackPluginOptions} */ + /** @type {ProcessedHtmlWebpackOptions} */ const defaultOptions = { template: path.join(__dirname, 'default_index.ejs'), templateContent: false, @@ -56,7 +57,7 @@ class HtmlWebpackPlugin { xhtml: false }; - /** @type {HtmlWebpackPluginOptions} */ + /** @type {ProcessedHtmlWebpackOptions} */ this.options = Object.assign(defaultOptions, userOptions); // Default metaOptions if no template is provided @@ -112,6 +113,7 @@ class HtmlWebpackPlugin { const minify = this.options.minify; if (minify === true || (minify === undefined && isProductionLikeMode)) { + /** @type { import('html-minifier').Options } */ this.options.minify = { // https://github.com/kangax/html-minifier#options-quick-reference collapseWhitespace: true, @@ -381,7 +383,7 @@ class HtmlWebpackPlugin { /** * This function renders the actual html by executing the template function * - * @param {(templatePArameters) => string | Promise} templateFunction + * @param {(templateParameters) => string | Promise} templateFunction * @param {{ publicPath: string, js: Array, @@ -628,7 +630,7 @@ class HtmlWebpackPlugin { * * @param {string|false} faviconFilePath * @param {WebpackCompilation} compilation - * @parma {string} publicPath + * @param {string} publicPath * @returns {Promise} */ getFaviconPublicPath (faviconFilePath, compilation, publicPath) { @@ -877,7 +879,7 @@ class HtmlWebpackPlugin { /** * Helper to return the absolute template path with a fallback loader * @param {string} template - * The path to the tempalate e.g. './index.html' + * The path to the template e.g. './index.html' * @param {string} context * The webpack base resolution path for relative paths e.g. process.cwd() */ @@ -920,8 +922,8 @@ class HtmlWebpackPlugin { headTags: HtmlTagObject[], bodyTags: HtmlTagObject[] }} assetTags - * @param {HtmlWebpackPluginOptions} options - * @returns {HtmlWebpackPluginTemplateParameter} + * @param {ProcessedHtmlWebpackOptions} options + * @returns {TemplateParameter} */ function templateParametersGenerator (compilation, assets, assetTags, options) { const xhtml = options.xhtml; diff --git a/lib/hooks.js b/lib/hooks.js index a3c5c837..cf6ce139 100644 --- a/lib/hooks.js +++ b/lib/hooks.js @@ -1,7 +1,5 @@ // @ts-check -/* eslint-disable */ -/// -/* eslint-enable */ +/** @typedef {import("../typings").Hooks} HtmlWebpackPluginHooks */ 'use strict'; /** * This file provides access to all public htmlWebpackPlugin hooks @@ -12,10 +10,9 @@ const AsyncSeriesWaterfallHook = require('tapable').AsyncSeriesWaterfallHook; -// The following typedef holds the API definition for all available hooks -// to allow easier access when using ts-check or typescript inside plugins -/** @typedef {{ - +// The following is the API definition for all available hooks +// For the TypeScript definition, see the Hooks type in typings.d.ts +/** beforeAssetTagGeneration: AsyncSeriesWaterfallHook<{ assets: { @@ -28,7 +25,6 @@ const AsyncSeriesWaterfallHook = require('tapable').AsyncSeriesWaterfallHook; outputName: string, plugin: HtmlWebpackPlugin }>, - alterAssetTags: AsyncSeriesWaterfallHook<{ assetTags: { @@ -39,7 +35,6 @@ const AsyncSeriesWaterfallHook = require('tapable').AsyncSeriesWaterfallHook; outputName: string, plugin: HtmlWebpackPlugin }>, - alterAssetTagGroups: AsyncSeriesWaterfallHook<{ headTags: Array, @@ -47,7 +42,6 @@ const AsyncSeriesWaterfallHook = require('tapable').AsyncSeriesWaterfallHook; outputName: string, plugin: HtmlWebpackPlugin }>, - afterTemplateExecution: AsyncSeriesWaterfallHook<{ html: string, @@ -56,22 +50,18 @@ const AsyncSeriesWaterfallHook = require('tapable').AsyncSeriesWaterfallHook; outputName: string, plugin: HtmlWebpackPlugin, }>, - beforeEmit: AsyncSeriesWaterfallHook<{ html: string, outputName: string, plugin: HtmlWebpackPlugin, }>, - afterEmit: AsyncSeriesWaterfallHook<{ outputName: string, plugin: HtmlWebpackPlugin - }>, - - }} HtmlWebpackPluginHooks - */ + }> +*/ /** * @type {WeakMap}} diff --git a/lib/html-tags.js b/lib/html-tags.js index cdad0d4a..4f331245 100644 --- a/lib/html-tags.js +++ b/lib/html-tags.js @@ -1,7 +1,5 @@ // @ts-check -/* eslint-disable */ -/// -/* eslint-enable */ +/** @typedef {import("../typings").HtmlTagObject} HtmlTagObject */ /** * @file * This file provides to helper to create html as a object repesentation as diff --git a/package.json b/package.json index 967f0721..df5fa638 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "description": "Simplifies creation of HTML files to serve your webpack bundles", "author": "Jan Nicklas (https://github.com/jantimon)", "main": "index.js", + "types": "typings.d.ts", "files": [ "lib/", "index.js", @@ -27,9 +28,11 @@ ] }, "devDependencies": { + "@types/html-minifier": "^3.5.2", "@types/loader-utils": "1.1.3", "@types/node": "10.11.4", "@types/tapable": "1.0.4", + "@types/webpack": "^4.0.0", "appcache-webpack-plugin": "^1.4.0", "commitizen": "3.0.2", "css-loader": "^1.0.0", diff --git a/typings.d.ts b/typings.d.ts index e5fcef72..ed32509c 100644 --- a/typings.d.ts +++ b/typings.d.ts @@ -1,139 +1,252 @@ +import { Plugin } from "webpack"; +import { AsyncSeriesWaterfallHook } from "tapable"; +import { Options as HtmlMinifierOptions } from "html-minifier"; -/** - * The plugin options - */ -interface HtmlWebpackPluginOptions { +// https://github.com/Microsoft/TypeScript/issues/15012#issuecomment-365453623 +type Required = T extends object + ? { [P in keyof T]-?: NonNullable } + : T; +// https://stackoverflow.com/questions/48215950/exclude-property-from-type +type Omit = Pick>; + +export = HtmlWebpackPlugin; + +declare class HtmlWebpackPlugin extends Plugin { + constructor(options?: HtmlWebpackPlugin.Options); +} + +declare namespace HtmlWebpackPlugin { + type MinifyOptions = HtmlMinifierOptions; + + /** + * The plugin options + */ + interface Options { /** - * The title to use for the generated HTML document + * Emit the file only if it was changed. + * Default: `true`. */ - title: string, + cache?: boolean; /** - * The `webpack` require path to the template. - * @see https://github.com/jantimon/html-webpack-plugin/blob/master/docs/template-option.md + * List all entries which should be injected */ - template: string, + chunks?: "all" | string[]; /** - * Allow to use a html string instead of reading from a file + * Allows to control how chunks should be sorted before they are included to the html. + * Default: `'auto'`. */ - templateContent: - false // Use the template option instead to load a file - | string - | Promise, + chunksSortMode?: + | "auto" + | "manual" + | (((entryNameA: string, entryNameB: string) => number)); /** - * Allows to overwrite the parameters used in the template + * List all entries which should not be injeccted */ - templateParameters: - false // Pass an empty object to the template function - | ((compilation: any, assets, assetTags: { headTags: Array, bodyTags: Array }, options: HtmlWebpackPluginOptions) => {[option: string]: any}) - | ((compilation: any, assets, assetTags: { headTags: Array, bodyTags: Array }, options: HtmlWebpackPluginOptions) => Promise<{[option: string]: any}>) - | {[option: string]: any} + excludeChunks?: string[]; + /** + * Path to the favicon icon + */ + favicon?: false | string; /** * The file to write the HTML to. * Defaults to `index.html`. * Supports subdirectories eg: `assets/admin.html` */ - filename: string, + filename?: string; /** * If `true` then append a unique `webpack` compilation hash to all included scripts and CSS files. * This is useful for cache busting */ - hash: boolean, + hash?: boolean; /** * Inject all assets into the given `template` or `templateContent`. */ - inject: false // Don't inject scripts - | true // Inject scripts into body - | 'body' // Inject scripts into body - | 'head' // Inject scripts into head + inject?: + | false // Don't inject scripts + | true // Inject scripts into body + | "body" // Inject scripts into body + | "head"; // Inject scripts into head /** - * Path to the favicon icon + * Inject meta tags */ - favicon: false | string, + meta?: + | false // Disable injection + | { + [name: string]: + | string + | false // name content pair e.g. {viewport: 'width=device-width, initial-scale=1, shrink-to-fit=no'}` + | { [attributeName: string]: string | boolean }; // custom properties e.g. { name:"viewport" content:"width=500, initial-scale=1" } + }; /** * HTML Minification options * @https://github.com/kangax/html-minifier#options-quick-reference */ - minify?: boolean | {}, - cache: boolean, + minify?: boolean | MinifyOptions; /** * Render errors into the HTML page */ - showErrors: boolean, + showErrors?: boolean; /** - * List all entries which should be injected + * The `webpack` require path to the template. + * @see https://github.com/jantimon/html-webpack-plugin/blob/master/docs/template-option.md */ - chunks: 'all' | string[], + template?: string; /** - * List all entries which should not be injeccted + * Allow to use a html string instead of reading from a file */ - excludeChunks: string[], - chunksSortMode: 'auto' | 'manual' | (((entryNameA: string, entryNameB: string) => number)), + templateContent?: + | false // Use the template option instead to load a file + | string + | Promise; /** - * Inject meta tags + * Allows to overwrite the parameters used in the template */ - meta: false // Disable injection - | { - [name: string]: string|false // name content pair e.g. {viewport: 'width=device-width, initial-scale=1, shrink-to-fit=no'}` - | {[attributeName: string]: string|boolean} // custom properties e.g. { name:"viewport" content:"width=500, initial-scale=1" } - }, + templateParameters?: + | false // Pass an empty object to the template function + | (( + compilation: any, + assets, + assetTags: { + headTags: HtmlTagObject[]; + bodyTags: HtmlTagObject[]; + }, + options: Options + ) => { [option: string]: any }) + | (( + compilation: any, + assets, + assetTags: { + headTags: HtmlTagObject[]; + bodyTags: HtmlTagObject[]; + }, + options: Options + ) => Promise<{ [option: string]: any }>) + | { [option: string]: any }; + /** + * The title to use for the generated HTML document + */ + title?: string; /** * Enforce self closing tags e.g. */ - xhtml: boolean - + xhtml?: boolean; /** * In addition to the options actually used by this plugin, you can use this hash to pass arbitrary data through * to your template. */ [option: string]: any; -} + } -/** - * A tag element according to the htmlWebpackPlugin object notation - */ -interface HtmlTagObject { /** - * Attributes of the html tag - * E.g. `{'disabled': true, 'value': 'demo'}` + * Options interface that matches the expectations of the index.js API: + * - All fields are required + * - The minify property matches what html-minifier expects (eg either a MinifyOptions or undefined). + * html-minifier does not accept a boolean value. As TypeScript does not allow a property to be redefined + * in an extended interface we need to omit it and then define it properly + * + * The Required and Omit types are defined at the top of the file */ - attributes: { - [attributeName: string]: string|boolean - }, - /** - * Wether this html must not contain innerHTML - * @see https://www.w3.org/TR/html5/syntax.html#void-elements - */ - voidTag: boolean, + interface ProcessedOptions extends Required> { + minify: MinifyOptions | undefined; + } + /** - * The tag name e.g. `'div'` + * The values which are available during template execution + * + * Please keep in mind that the `templateParameter` options allows to change them */ - tagName: string, + interface TemplateParameter { + compilation: any; + htmlWebpackPlugin: { + tags: { + headTags: HtmlTagObject[]; + bodyTags: HtmlTagObject[]; + }; + files: { + publicPath: string; + js: Array; + css: Array; + manifest?: string; + favicon?: string; + }; + options: Options; + }; + webpackConfig: any; + } + + interface Hooks { + alterAssetTags: AsyncSeriesWaterfallHook<{ + assetTags: { + scripts: HtmlTagObject[]; + styles: HtmlTagObject[]; + meta: HtmlTagObject[]; + }; + outputName: string; + plugin: HtmlWebpackPlugin; + }>; + + alterAssetTagGroups: AsyncSeriesWaterfallHook<{ + headTags: HtmlTagObject[]; + bodyTags: HtmlTagObject[]; + outputName: string; + plugin: HtmlWebpackPlugin; + }>; + + afterTemplateExecution: AsyncSeriesWaterfallHook<{ + html: string; + headTags: HtmlTagObject[]; + bodyTags: HtmlTagObject[]; + outputName: string; + plugin: HtmlWebpackPlugin; + }>; + + beforeAssetTagGeneration: AsyncSeriesWaterfallHook<{ + assets: { + publicPath: string; + js: Array; + css: Array; + favicon?: string | undefined; + manifest?: string | undefined; + }; + outputName: string; + plugin: HtmlWebpackPlugin; + }>; + + beforeEmit: AsyncSeriesWaterfallHook<{ + html: string; + outputName: string; + plugin: HtmlWebpackPlugin; + }>; + + afterEmit: AsyncSeriesWaterfallHook<{ + outputName: string; + plugin: HtmlWebpackPlugin; + }>; + } + /** - * Inner HTML The + * A tag element according to the htmlWebpackPlugin object notation */ - innerHTML?: string -} - -/** - * The values which are available during template execution - * - * Please keep in mind that the `templateParameter` options allows to change them - */ -interface HtmlWebpackPluginTemplateParameter { - compilation: any, - webpackConfig: any - htmlWebpackPlugin: { - tags: { - headTags: HtmlTagObject[], - bodyTags: HtmlTagObject[] - }, - files: { - publicPath: string, - js: Array, - css: Array, - manifest?: string, - favicon?: string - }, - options: HtmlWebpackPluginOptions + interface HtmlTagObject { + /** + * Attributes of the html tag + * E.g. `{'disabled': true, 'value': 'demo'}` + */ + attributes: { + [attributeName: string]: string | boolean; + }; + /** + * The tag name e.g. `'div'` + */ + tagName: string; + /** + * The inner HTML + */ + innerHTML?: string; + /** + * Whether this html must not contain innerHTML + * @see https://www.w3.org/TR/html5/syntax.html#void-elements + */ + voidTag: boolean; } }