simple-squiggle

A restricted subset of Squiggle
Log | Files | Refs | README

UseEffectRulePlugin.js (5306B)


      1 /*
      2 	MIT License http://www.opensource.org/licenses/mit-license.php
      3 	Author Tobias Koppers @sokra
      4 */
      5 
      6 "use strict";
      7 
      8 const util = require("util");
      9 
     10 /** @typedef {import("./RuleSetCompiler")} RuleSetCompiler */
     11 /** @typedef {import("./RuleSetCompiler").Effect} Effect */
     12 
     13 class UseEffectRulePlugin {
     14 	/**
     15 	 * @param {RuleSetCompiler} ruleSetCompiler the rule set compiler
     16 	 * @returns {void}
     17 	 */
     18 	apply(ruleSetCompiler) {
     19 		ruleSetCompiler.hooks.rule.tap(
     20 			"UseEffectRulePlugin",
     21 			(path, rule, unhandledProperties, result, references) => {
     22 				const conflictWith = (property, correctProperty) => {
     23 					if (unhandledProperties.has(property)) {
     24 						throw ruleSetCompiler.error(
     25 							`${path}.${property}`,
     26 							rule[property],
     27 							`A Rule must not have a '${property}' property when it has a '${correctProperty}' property`
     28 						);
     29 					}
     30 				};
     31 
     32 				if (unhandledProperties.has("use")) {
     33 					unhandledProperties.delete("use");
     34 					unhandledProperties.delete("enforce");
     35 
     36 					conflictWith("loader", "use");
     37 					conflictWith("options", "use");
     38 
     39 					const use = rule.use;
     40 					const enforce = rule.enforce;
     41 
     42 					const type = enforce ? `use-${enforce}` : "use";
     43 
     44 					/**
     45 					 *
     46 					 * @param {string} path options path
     47 					 * @param {string} defaultIdent default ident when none is provided
     48 					 * @param {object} item user provided use value
     49 					 * @returns {Effect|function(any): Effect[]} effect
     50 					 */
     51 					const useToEffect = (path, defaultIdent, item) => {
     52 						if (typeof item === "function") {
     53 							return data => useToEffectsWithoutIdent(path, item(data));
     54 						} else {
     55 							return useToEffectRaw(path, defaultIdent, item);
     56 						}
     57 					};
     58 
     59 					/**
     60 					 *
     61 					 * @param {string} path options path
     62 					 * @param {string} defaultIdent default ident when none is provided
     63 					 * @param {object} item user provided use value
     64 					 * @returns {Effect} effect
     65 					 */
     66 					const useToEffectRaw = (path, defaultIdent, item) => {
     67 						if (typeof item === "string") {
     68 							return {
     69 								type,
     70 								value: {
     71 									loader: item,
     72 									options: undefined,
     73 									ident: undefined
     74 								}
     75 							};
     76 						} else {
     77 							const loader = item.loader;
     78 							const options = item.options;
     79 							let ident = item.ident;
     80 							if (options && typeof options === "object") {
     81 								if (!ident) ident = defaultIdent;
     82 								references.set(ident, options);
     83 							}
     84 							if (typeof options === "string") {
     85 								util.deprecate(
     86 									() => {},
     87 									`Using a string as loader options is deprecated (${path}.options)`,
     88 									"DEP_WEBPACK_RULE_LOADER_OPTIONS_STRING"
     89 								)();
     90 							}
     91 							return {
     92 								type: enforce ? `use-${enforce}` : "use",
     93 								value: {
     94 									loader,
     95 									options,
     96 									ident
     97 								}
     98 							};
     99 						}
    100 					};
    101 
    102 					/**
    103 					 * @param {string} path options path
    104 					 * @param {any} items user provided use value
    105 					 * @returns {Effect[]} effects
    106 					 */
    107 					const useToEffectsWithoutIdent = (path, items) => {
    108 						if (Array.isArray(items)) {
    109 							return items.map((item, idx) =>
    110 								useToEffectRaw(`${path}[${idx}]`, "[[missing ident]]", item)
    111 							);
    112 						}
    113 						return [useToEffectRaw(path, "[[missing ident]]", items)];
    114 					};
    115 
    116 					/**
    117 					 * @param {string} path current path
    118 					 * @param {any} items user provided use value
    119 					 * @returns {(Effect|function(any): Effect[])[]} effects
    120 					 */
    121 					const useToEffects = (path, items) => {
    122 						if (Array.isArray(items)) {
    123 							return items.map((item, idx) => {
    124 								const subPath = `${path}[${idx}]`;
    125 								return useToEffect(subPath, subPath, item);
    126 							});
    127 						}
    128 						return [useToEffect(path, path, items)];
    129 					};
    130 
    131 					if (typeof use === "function") {
    132 						result.effects.push(data =>
    133 							useToEffectsWithoutIdent(`${path}.use`, use(data))
    134 						);
    135 					} else {
    136 						for (const effect of useToEffects(`${path}.use`, use)) {
    137 							result.effects.push(effect);
    138 						}
    139 					}
    140 				}
    141 
    142 				if (unhandledProperties.has("loader")) {
    143 					unhandledProperties.delete("loader");
    144 					unhandledProperties.delete("options");
    145 					unhandledProperties.delete("enforce");
    146 
    147 					const loader = rule.loader;
    148 					const options = rule.options;
    149 					const enforce = rule.enforce;
    150 
    151 					if (loader.includes("!")) {
    152 						throw ruleSetCompiler.error(
    153 							`${path}.loader`,
    154 							loader,
    155 							"Exclamation mark separated loader lists has been removed in favor of the 'use' property with arrays"
    156 						);
    157 					}
    158 
    159 					if (loader.includes("?")) {
    160 						throw ruleSetCompiler.error(
    161 							`${path}.loader`,
    162 							loader,
    163 							"Query arguments on 'loader' has been removed in favor of the 'options' property"
    164 						);
    165 					}
    166 
    167 					if (typeof options === "string") {
    168 						util.deprecate(
    169 							() => {},
    170 							`Using a string as loader options is deprecated (${path}.options)`,
    171 							"DEP_WEBPACK_RULE_LOADER_OPTIONS_STRING"
    172 						)();
    173 					}
    174 
    175 					const ident =
    176 						options && typeof options === "object" ? path : undefined;
    177 					references.set(ident, options);
    178 					result.effects.push({
    179 						type: enforce ? `use-${enforce}` : "use",
    180 						value: {
    181 							loader,
    182 							options,
    183 							ident
    184 						}
    185 					});
    186 				}
    187 			}
    188 		);
    189 	}
    190 
    191 	useItemToEffects(path, item) {}
    192 }
    193 
    194 module.exports = UseEffectRulePlugin;