Skip to content

feat: add an option to disable locals export #24

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ module.exports = {
| **[`formatter`](#formatter)** | `{String}` | Formats the generated `*.d.ts` file with specified formatter, eg. `prettier` |
| **[`eol`](#eol)** | `{String}` | Newline character to be used in generated `*.d.ts` files |
| **[`verifyOnly`](#verifyOnly)** | `{Boolean}` | Validate generated `*.d.ts` files and fail if an update is needed (useful in CI) |
| **[`disableLocalsExport`](#disableLocalsExport)** | `{Boolean}` | Disable the use of locals export. |

### `banner`

Expand Down Expand Up @@ -159,6 +160,35 @@ module.exports = {
};
```

### `disableLocalsExport`

Disable the use of locals export. Defaults to `false`.

```js
module.exports = {
module: {
rules: [
{
test: /\.css$/i,
use: [
{
loader: "@teamsupercell/typings-for-css-modules-loader",
options: {
disableLocalsExport: true
}
},
{
loader: "css-loader",
options: { modules: true }
}
]
}
]
}
};
```


## Example

Imagine you have a file `~/my-project/src/component/MyComponent/myComponent.scss` in your project with the following content:
Expand Down
8 changes: 7 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ const schema = {
"Possible options: none and prettier (requires prettier package installed). Defaults to prettier if `prettier` module can be resolved",
enum: ["prettier", "none"]
},
disableLocalsExport: {
description:
"Disable the use of locals export. Defaults to `false`",
type: "boolean"
},
verifyOnly: {
description:
"Validate generated `*.d.ts` files and fail if an update is needed (useful in CI). Defaults to `false`",
Expand Down Expand Up @@ -75,7 +80,8 @@ module.exports = function(content, ...args) {
const cssModuleInterfaceFilename = filenameToTypingsFilename(filename);
const cssModuleDefinition = generateGenericExportInterface(
cssModuleKeys,
filenameToPascalCase(filename)
filenameToPascalCase(filename),
options.disableLocalsExport
);

applyFormattingAndOptions(cssModuleDefinition, options)
Expand Down
12 changes: 7 additions & 5 deletions src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,16 @@ const filenameToTypingsFilename = filename => {
* @param {string[]} cssModuleKeys
* @param {string} pascalCaseFileName
*/
const generateGenericExportInterface = (cssModuleKeys, pascalCaseFileName) => {
const generateGenericExportInterface = (cssModuleKeys, pascalCaseFileName, disableLocalsExport) => {
const interfaceName = `I${pascalCaseFileName}`;
const moduleName = `${pascalCaseFileName}Module`;
const namespaceName = `${pascalCaseFileName}Namespace`;

const localsExportType = disableLocalsExport ? `` : ` & {
/** WARNING: Only available when \`css-loader\` is used without \`style-loader\` or \`mini-css-extract-plugin\` */
locals: ${namespaceName}.${interfaceName};
}`;

const interfaceProperties = cssModuleToTypescriptInterfaceProperties(
cssModuleKeys,
" "
Expand All @@ -62,10 +67,7 @@ ${interfaceProperties}
}
}

declare const ${moduleName}: ${namespaceName}.${interfaceName} & {
/** WARNING: Only available when \`css-loader\` is used without \`style-loader\` or \`mini-css-extract-plugin\` */
locals: ${namespaceName}.${interfaceName};
};
declare const ${moduleName}: ${namespaceName}.${interfaceName}${localsExportType};

export = ${moduleName};`;
};
Expand Down
15 changes: 15 additions & 0 deletions test/__snapshots__/index.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,21 @@ export = ExampleCssModule;
"
`;

exports[`with locals export disabled 1`] = `
"declare namespace ExampleCssNamespace {
export interface IExampleCss {
\\"bar-baz\\": string;
composed: string;
foo: string;
}
}

declare const ExampleCssModule: ExampleCssNamespace.IExampleCss;

export = ExampleCssModule;
"
`;

exports[`with no formatter 1`] = `
"declare namespace ExampleCssNamespace {
export interface IExampleCss {
Expand Down
62 changes: 37 additions & 25 deletions test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ beforeEach(() => {
it("default options", async () => {
await runTest();

const persisteMock = jest.requireMock("../src/persist");
expect(persisteMock).toBeCalledTimes(1);
expect(persisteMock.mock.calls[0][1]).toMatchSnapshot();
const persistMock = jest.requireMock("../src/persist");
expect(persistMock).toBeCalledTimes(1);
expect(persistMock.mock.calls[0][1]).toMatchSnapshot();

const verifyMock = jest.requireMock("../src/verify");
expect(verifyMock).toBeCalledTimes(0);
Expand All @@ -27,9 +27,9 @@ it("with sourcemap", async () => {
}
});

const persisteMock = jest.requireMock("../src/persist");
expect(persisteMock).toBeCalledTimes(1);
expect(persisteMock.mock.calls[0][1]).toMatchSnapshot();
const persistMock = jest.requireMock("../src/persist");
expect(persistMock).toBeCalledTimes(1);
expect(persistMock.mock.calls[0][1]).toMatchSnapshot();
});

it("no modules", async () => {
Expand All @@ -39,8 +39,8 @@ it("no modules", async () => {
}
});

const persisteMock = jest.requireMock("../src/persist");
expect(persisteMock).toBeCalledTimes(0);
const persistMock = jest.requireMock("../src/persist");
expect(persistMock).toBeCalledTimes(0);
});

it("localsConvention asIs", async () => {
Expand All @@ -50,9 +50,9 @@ it("localsConvention asIs", async () => {
}
});

const persisteMock = jest.requireMock("../src/persist");
expect(persisteMock).toBeCalledTimes(1);
expect(persisteMock.mock.calls[0][1]).toMatchSnapshot();
const persistMock = jest.requireMock("../src/persist");
expect(persistMock).toBeCalledTimes(1);
expect(persistMock.mock.calls[0][1]).toMatchSnapshot();
});

it("localsConvention camelCase", async () => {
Expand All @@ -62,9 +62,9 @@ it("localsConvention camelCase", async () => {
}
});

const persisteMock = jest.requireMock("../src/persist");
expect(persisteMock).toBeCalledTimes(1);
expect(persisteMock.mock.calls[0][1]).toMatchSnapshot();
const persistMock = jest.requireMock("../src/persist");
expect(persistMock).toBeCalledTimes(1);
expect(persistMock.mock.calls[0][1]).toMatchSnapshot();
});

it("with prettier", async () => {
Expand All @@ -74,9 +74,9 @@ it("with prettier", async () => {
}
});

const persisteMock = jest.requireMock("../src/persist");
expect(persisteMock).toBeCalledTimes(1);
expect(persisteMock.mock.calls[0][1]).toMatchSnapshot();
const persistMock = jest.requireMock("../src/persist");
expect(persistMock).toBeCalledTimes(1);
expect(persistMock.mock.calls[0][1]).toMatchSnapshot();
});

it("with no formatter", async () => {
Expand All @@ -86,9 +86,9 @@ it("with no formatter", async () => {
}
});

const persisteMock = jest.requireMock("../src/persist");
expect(persisteMock).toBeCalledTimes(1);
expect(persisteMock.mock.calls[0][1]).toMatchSnapshot();
const persistMock = jest.requireMock("../src/persist");
expect(persistMock).toBeCalledTimes(1);
expect(persistMock.mock.calls[0][1]).toMatchSnapshot();
});

it("with banner", async () => {
Expand All @@ -98,9 +98,21 @@ it("with banner", async () => {
}
});

const persisteMock = jest.requireMock("../src/persist");
expect(persisteMock).toBeCalledTimes(1);
expect(persisteMock.mock.calls[0][1]).toMatchSnapshot();
const persistMock = jest.requireMock("../src/persist");
expect(persistMock).toBeCalledTimes(1);
expect(persistMock.mock.calls[0][1]).toMatchSnapshot();
});

it("with locals export disabled", async () => {
await runTest({
options: {
disableLocalsExport: true
}
});

const persistMock = jest.requireMock("../src/persist");
expect(persistMock).toBeCalledTimes(1);
expect(persistMock.mock.calls[0][1]).toMatchSnapshot();
});

it("with verify only", async () => {
Expand All @@ -110,8 +122,8 @@ it("with verify only", async () => {
}
});

const persisteMock = jest.requireMock("../src/persist");
expect(persisteMock).toBeCalledTimes(0);
const persistMock = jest.requireMock("../src/persist");
expect(persistMock).toBeCalledTimes(0);

const verifyMock = jest.requireMock("../src/verify");
expect(verifyMock).toBeCalledTimes(1);
Expand Down