Skip to content

Commit

Permalink
feat: namedExports works fine with any exportLocalsConvention value
Browse files Browse the repository at this point in the history
  • Loading branch information
alexander-akait committed Apr 4, 2024
1 parent 9852aa6 commit f96a110
Show file tree
Hide file tree
Showing 5 changed files with 4,279 additions and 3,992 deletions.
9 changes: 2 additions & 7 deletions README.md
Expand Up @@ -1144,7 +1144,7 @@ Enables/disables ES modules named export for locals.

> **Warning**
>
> It is not allowed to use JavaScript reserved words in css class names unless `exportLocalsConvention` is `"as-is"`.
> It is not allowed to use the `default` reserved word in css classes.
**styles.css**

Expand Down Expand Up @@ -1247,12 +1247,7 @@ Default: Depends on the value of the `modules.namedExport` option, if `true` - `
>
> Names of locals are converted to camelcase when the named export is `false`, i.e. the `exportLocalsConvention` option has
> `camelCaseOnly` value by default. You can set this back to any other valid option but selectors
> which are not valid JavaScript identifiers may run into problems which do not implement the entire
> modules specification.
> **Warning**
>
> **You need to disable `modules.namedExport` if you want to use `'camel-case'` or `'dashes'` value.**
> which are not valid JavaScript identifiers may run into problems which do not implement the entire modules specification.
Style of exported class names.

Expand Down
102 changes: 74 additions & 28 deletions src/utils.js
Expand Up @@ -550,16 +550,12 @@ function getModulesOptions(rawOptions, esModule, exportType, loaderContext) {
namedExport,
};

let exportLocalsConventionType;

if (typeof modulesOptions.exportLocalsConvention === "string") {
exportLocalsConventionType = modulesOptions.exportLocalsConvention;
// eslint-disable-next-line no-shadow
const { exportLocalsConvention } = modulesOptions;

modulesOptions.useExportsAs =
exportLocalsConventionType === "as-is" ||
exportLocalsConventionType === "asIs";
modulesOptions.exportLocalsConvention = (name) => {
switch (exportLocalsConventionType) {
switch (exportLocalsConvention) {
case "camel-case":
case "camelCase": {
return [name, camelCase(name)];
Expand Down Expand Up @@ -640,26 +636,10 @@ function getModulesOptions(rawOptions, esModule, exportType, loaderContext) {
}
}

if (modulesOptions.namedExport === true) {
if (esModule === false) {
throw new Error(
"The 'modules.namedExport' option requires the 'esModule' option to be enabled",
);
}

/* if (
typeof exportLocalsConventionType === "string" &&
exportLocalsConventionType !== "asIs" &&
exportLocalsConventionType !== "as-is" &&
exportLocalsConventionType !== "camelCaseOnly" &&
exportLocalsConventionType !== "camel-case-only" &&
exportLocalsConventionType !== "dashesOnly" &&
exportLocalsConventionType !== "dashes-only"
) {
throw new Error(
'The "modules.namedExport" option requires the "modules.exportLocalsConvention" option to be "as-is", "camel-case-only" or "dashes-only"',
);
}*/
if (modulesOptions.namedExport === true && esModule === false) {
throw new Error(
"The 'modules.namedExport' option requires the 'esModule' option to be enabled",
);
}

return modulesOptions;
Expand Down Expand Up @@ -1123,6 +1103,69 @@ function dashesCamelCase(str) {
);
}

const validIdentifier = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/u;
const keywords = new Set([
"abstract",
"boolean",
"break",
"byte",
"case",
"catch",
"char",
"class",
"const",
"continue",
"debugger",
"default",
"delete",
"do",
"double",
"else",
"enum",
"export",
"extends",
"false",
"final",
"finally",
"float",
"for",
"function",
"goto",
"if",
"implements",
"import",
"in",
"instanceof",
"int",
"interface",
"long",
"native",
"new",
"null",
"package",
"private",
"protected",
"public",
"return",
"short",
"static",
"super",
"switch",
"synchronized",
"this",
"throw",
"throws",
"transient",
"true",
"try",
"typeof",
"var",
"void",
"volatile",
"while",
"with",
]);

function getExportCode(
exports,
replacements,
Expand All @@ -1145,10 +1188,13 @@ function getExportCode(
const serializedValue = isTemplateLiteralSupported
? convertToTemplateLiteral(value)
: JSON.stringify(value);

if (options.modules.namedExport) {
if (options.modules.useExportsAs) {
if (!validIdentifier.test(name) || keywords.has(name)) {
identifierId += 1;

const id = `_${identifierId.toString(16)}`;

localsCode += `var ${id} = ${serializedValue};\n`;
localsCode += `export { ${id} as ${JSON.stringify(name)} };\n`;
} else {
Expand Down

0 comments on commit f96a110

Please sign in to comment.