| 1 | /*
|
|---|
| 2 | MIT License http://www.opensource.org/licenses/mit-license.php
|
|---|
| 3 | Author Gengkun He @ahabhgk
|
|---|
| 4 | */
|
|---|
| 5 |
|
|---|
| 6 | "use strict";
|
|---|
| 7 |
|
|---|
| 8 | /** @typedef {import("../../declarations/WebpackOptions").CssGeneratorExportsConvention} CssGeneratorExportsConvention */
|
|---|
| 9 | // Copy from css-loader
|
|---|
| 10 | /**
|
|---|
| 11 | * Preserve camel case.
|
|---|
| 12 | * @param {string} string string
|
|---|
| 13 | * @returns {string} result
|
|---|
| 14 | */
|
|---|
| 15 | const preserveCamelCase = (string) => {
|
|---|
| 16 | let result = string;
|
|---|
| 17 | let isLastCharLower = false;
|
|---|
| 18 | let isLastCharUpper = false;
|
|---|
| 19 | let isLastLastCharUpper = false;
|
|---|
| 20 |
|
|---|
| 21 | for (let i = 0; i < result.length; i++) {
|
|---|
| 22 | const character = result[i];
|
|---|
| 23 |
|
|---|
| 24 | if (isLastCharLower && /\p{Lu}/u.test(character)) {
|
|---|
| 25 | result = `${result.slice(0, i)}-${result.slice(i)}`;
|
|---|
| 26 | isLastCharLower = false;
|
|---|
| 27 | isLastLastCharUpper = isLastCharUpper;
|
|---|
| 28 | isLastCharUpper = true;
|
|---|
| 29 | i += 1;
|
|---|
| 30 | } else if (
|
|---|
| 31 | isLastCharUpper &&
|
|---|
| 32 | isLastLastCharUpper &&
|
|---|
| 33 | /\p{Ll}/u.test(character)
|
|---|
| 34 | ) {
|
|---|
| 35 | result = `${result.slice(0, i - 1)}-${result.slice(i - 1)}`;
|
|---|
| 36 | isLastLastCharUpper = isLastCharUpper;
|
|---|
| 37 | isLastCharUpper = false;
|
|---|
| 38 | isLastCharLower = true;
|
|---|
| 39 | } else {
|
|---|
| 40 | isLastCharLower =
|
|---|
| 41 | character.toLowerCase() === character &&
|
|---|
| 42 | character.toUpperCase() !== character;
|
|---|
| 43 | isLastLastCharUpper = isLastCharUpper;
|
|---|
| 44 | isLastCharUpper =
|
|---|
| 45 | character.toUpperCase() === character &&
|
|---|
| 46 | character.toLowerCase() !== character;
|
|---|
| 47 | }
|
|---|
| 48 | }
|
|---|
| 49 |
|
|---|
| 50 | return result;
|
|---|
| 51 | };
|
|---|
| 52 |
|
|---|
| 53 | // Copy from css-loader
|
|---|
| 54 | /**
|
|---|
| 55 | * Returns result.
|
|---|
| 56 | * @param {string} input input
|
|---|
| 57 | * @returns {string} result
|
|---|
| 58 | */
|
|---|
| 59 | module.exports.camelCase = (input) => {
|
|---|
| 60 | let result = input.trim();
|
|---|
| 61 |
|
|---|
| 62 | if (result.length === 0) {
|
|---|
| 63 | return "";
|
|---|
| 64 | }
|
|---|
| 65 |
|
|---|
| 66 | if (result.length === 1) {
|
|---|
| 67 | return result.toLowerCase();
|
|---|
| 68 | }
|
|---|
| 69 |
|
|---|
| 70 | const hasUpperCase = result !== result.toLowerCase();
|
|---|
| 71 |
|
|---|
| 72 | if (hasUpperCase) {
|
|---|
| 73 | result = preserveCamelCase(result);
|
|---|
| 74 | }
|
|---|
| 75 |
|
|---|
| 76 | return result
|
|---|
| 77 | .replace(/^[_.\- ]+/, "")
|
|---|
| 78 | .toLowerCase()
|
|---|
| 79 | .replace(/[_.\- ]+([\p{Alpha}\p{N}_]|$)/gu, (_, p1) => p1.toUpperCase())
|
|---|
| 80 | .replace(/\d+([\p{Alpha}\p{N}_]|$)/gu, (m) => m.toUpperCase());
|
|---|
| 81 | };
|
|---|
| 82 |
|
|---|
| 83 | /**
|
|---|
| 84 | * Safely stringify an arbitrary value for an error message — falls back to
|
|---|
| 85 | * `String(...)` when JSON.stringify would throw (BigInt, circular, etc.).
|
|---|
| 86 | * @param {EXPECTED_ANY} value value to stringify
|
|---|
| 87 | * @returns {string} stringified value
|
|---|
| 88 | */
|
|---|
| 89 | const safeStringify = (value) => {
|
|---|
| 90 | try {
|
|---|
| 91 | const json = JSON.stringify(value);
|
|---|
| 92 | if (json !== undefined) return json;
|
|---|
| 93 | } catch (_err) {
|
|---|
| 94 | // fall through to String fallback
|
|---|
| 95 | }
|
|---|
| 96 | try {
|
|---|
| 97 | return String(value);
|
|---|
| 98 | } catch (_err) {
|
|---|
| 99 | return "[value cannot be converted to string]";
|
|---|
| 100 | }
|
|---|
| 101 | };
|
|---|
| 102 |
|
|---|
| 103 | /**
|
|---|
| 104 | * Returns results.
|
|---|
| 105 | * @param {string} input input
|
|---|
| 106 | * @param {CssGeneratorExportsConvention | undefined} convention convention
|
|---|
| 107 | * @returns {string[]} results
|
|---|
| 108 | */
|
|---|
| 109 | module.exports.cssExportConvention = (input, convention) => {
|
|---|
| 110 | /** @type {Set<string>} */
|
|---|
| 111 | const set = new Set();
|
|---|
| 112 | if (typeof convention === "function") {
|
|---|
| 113 | const result = convention(input);
|
|---|
| 114 | const validate = (/** @type {string} */ name) => {
|
|---|
| 115 | if (typeof name !== "string" || name.length === 0) {
|
|---|
| 116 | throw new Error(
|
|---|
| 117 | `exportsConvention function must return a non-empty string or an array of non-empty strings, got ${safeStringify(result)}`
|
|---|
| 118 | );
|
|---|
| 119 | }
|
|---|
| 120 | };
|
|---|
| 121 | if (Array.isArray(result)) {
|
|---|
| 122 | if (result.length === 0) {
|
|---|
| 123 | throw new Error(
|
|---|
| 124 | "exportsConvention function returned an empty array; it must return at least one name"
|
|---|
| 125 | );
|
|---|
| 126 | }
|
|---|
| 127 | for (const name of result) {
|
|---|
| 128 | validate(name);
|
|---|
| 129 | set.add(name);
|
|---|
| 130 | }
|
|---|
| 131 | } else {
|
|---|
| 132 | validate(result);
|
|---|
| 133 | set.add(result);
|
|---|
| 134 | }
|
|---|
| 135 | } else {
|
|---|
| 136 | switch (convention) {
|
|---|
| 137 | case "camel-case": {
|
|---|
| 138 | set.add(input);
|
|---|
| 139 | set.add(module.exports.camelCase(input));
|
|---|
| 140 | break;
|
|---|
| 141 | }
|
|---|
| 142 | case "camel-case-only": {
|
|---|
| 143 | set.add(module.exports.camelCase(input));
|
|---|
| 144 | break;
|
|---|
| 145 | }
|
|---|
| 146 | case "dashes": {
|
|---|
| 147 | set.add(input);
|
|---|
| 148 | set.add(module.exports.dashesCamelCase(input));
|
|---|
| 149 | break;
|
|---|
| 150 | }
|
|---|
| 151 | case "dashes-only": {
|
|---|
| 152 | set.add(module.exports.dashesCamelCase(input));
|
|---|
| 153 | break;
|
|---|
| 154 | }
|
|---|
| 155 | case "as-is": {
|
|---|
| 156 | set.add(input);
|
|---|
| 157 | break;
|
|---|
| 158 | }
|
|---|
| 159 | }
|
|---|
| 160 | }
|
|---|
| 161 | return [...set];
|
|---|
| 162 | };
|
|---|
| 163 |
|
|---|
| 164 | // Copy from css-loader
|
|---|
| 165 | /**
|
|---|
| 166 | * Returns result.
|
|---|
| 167 | * @param {string} input input
|
|---|
| 168 | * @returns {string} result
|
|---|
| 169 | */
|
|---|
| 170 | module.exports.dashesCamelCase = (input) =>
|
|---|
| 171 | input.replace(/-+(\w)/g, (match, firstLetter) => firstLetter.toUpperCase());
|
|---|