/* MIT License http://www.opensource.org/licenses/mit-license.php Author Tobias Koppers @sokra */ "use strict"; const util = require("util"); /** @typedef {import("./RuleSetCompiler")} RuleSetCompiler */ /** @typedef {import("./RuleSetCompiler").Effect} Effect */ class UseEffectRulePlugin { /** * @param {RuleSetCompiler} ruleSetCompiler the rule set compiler * @returns {void} */ apply(ruleSetCompiler) { ruleSetCompiler.hooks.rule.tap( "UseEffectRulePlugin", (path, rule, unhandledProperties, result, references) => { const conflictWith = (property, correctProperty) => { if (unhandledProperties.has(property)) { throw ruleSetCompiler.error( `${path}.${property}`, rule[property], `A Rule must not have a '${property}' property when it has a '${correctProperty}' property` ); } }; if (unhandledProperties.has("use")) { unhandledProperties.delete("use"); unhandledProperties.delete("enforce"); conflictWith("loader", "use"); conflictWith("options", "use"); const use = rule.use; const enforce = rule.enforce; const type = enforce ? `use-${enforce}` : "use"; /** * * @param {string} path options path * @param {string} defaultIdent default ident when none is provided * @param {object} item user provided use value * @returns {Effect|function(any): Effect[]} effect */ const useToEffect = (path, defaultIdent, item) => { if (typeof item === "function") { return data => useToEffectsWithoutIdent(path, item(data)); } else { return useToEffectRaw(path, defaultIdent, item); } }; /** * * @param {string} path options path * @param {string} defaultIdent default ident when none is provided * @param {object} item user provided use value * @returns {Effect} effect */ const useToEffectRaw = (path, defaultIdent, item) => { if (typeof item === "string") { return { type, value: { loader: item, options: undefined, ident: undefined } }; } else { const loader = item.loader; const options = item.options; let ident = item.ident; if (options && typeof options === "object") { if (!ident) ident = defaultIdent; references.set(ident, options); } if (typeof options === "string") { util.deprecate( () => {}, `Using a string as loader options is deprecated (${path}.options)`, "DEP_WEBPACK_RULE_LOADER_OPTIONS_STRING" )(); } return { type: enforce ? `use-${enforce}` : "use", value: { loader, options, ident } }; } }; /** * @param {string} path options path * @param {any} items user provided use value * @returns {Effect[]} effects */ const useToEffectsWithoutIdent = (path, items) => { if (Array.isArray(items)) { return items.map((item, idx) => useToEffectRaw(`${path}[${idx}]`, "[[missing ident]]", item) ); } return [useToEffectRaw(path, "[[missing ident]]", items)]; }; /** * @param {string} path current path * @param {any} items user provided use value * @returns {(Effect|function(any): Effect[])[]} effects */ const useToEffects = (path, items) => { if (Array.isArray(items)) { return items.map((item, idx) => { const subPath = `${path}[${idx}]`; return useToEffect(subPath, subPath, item); }); } return [useToEffect(path, path, items)]; }; if (typeof use === "function") { result.effects.push(data => useToEffectsWithoutIdent(`${path}.use`, use(data)) ); } else { for (const effect of useToEffects(`${path}.use`, use)) { result.effects.push(effect); } } } if (unhandledProperties.has("loader")) { unhandledProperties.delete("loader"); unhandledProperties.delete("options"); unhandledProperties.delete("enforce"); const loader = rule.loader; const options = rule.options; const enforce = rule.enforce; if (loader.includes("!")) { throw ruleSetCompiler.error( `${path}.loader`, loader, "Exclamation mark separated loader lists has been removed in favor of the 'use' property with arrays" ); } if (loader.includes("?")) { throw ruleSetCompiler.error( `${path}.loader`, loader, "Query arguments on 'loader' has been removed in favor of the 'options' property" ); } if (typeof options === "string") { util.deprecate( () => {}, `Using a string as loader options is deprecated (${path}.options)`, "DEP_WEBPACK_RULE_LOADER_OPTIONS_STRING" )(); } const ident = options && typeof options === "object" ? path : undefined; references.set(ident, options); result.effects.push({ type: enforce ? `use-${enforce}` : "use", value: { loader, options, ident } }); } } ); } useItemToEffects(path, item) {} } module.exports = UseEffectRulePlugin;