diff --git a/README.md b/README.md index e64ff4c..1b658f8 100644 --- a/README.md +++ b/README.md @@ -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` @@ -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: diff --git a/src/index.js b/src/index.js index 179f02d..9f2af79 100644 --- a/src/index.js +++ b/src/index.js @@ -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`", @@ -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) diff --git a/src/utils.js b/src/utils.js index d2cb087..c593fb1 100644 --- a/src/utils.js +++ b/src/utils.js @@ -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, " " @@ -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};`; }; diff --git a/test/__snapshots__/index.test.js.snap b/test/__snapshots__/index.test.js.snap index 153508b..edbbb14 100644 --- a/test/__snapshots__/index.test.js.snap +++ b/test/__snapshots__/index.test.js.snap @@ -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 { diff --git a/test/index.test.js b/test/index.test.js index 503bfaa..8b2dca4 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -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); @@ -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 () => { @@ -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 () => { @@ -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 () => { @@ -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 () => { @@ -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 () => { @@ -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 () => { @@ -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 () => { @@ -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);