From 78df5042c3a190d0f6b87a7cba4fa23ea01fd3f4 Mon Sep 17 00:00:00 2001 From: Brody McKee Date: Sun, 4 Dec 2022 17:08:12 +1100 Subject: [PATCH 1/2] feat: add option to allow unknown classnames --- .prettierignore | 1 + README.md | 25 ++++++++++--------- .../__snapshots__/getDtsSnapshot.test.ts.snap | 18 ++++++------- src/helpers/__tests__/getDtsSnapshot.test.ts | 4 +-- src/helpers/createDtsExports.ts | 2 +- src/options.ts | 2 +- 6 files changed, 27 insertions(+), 25 deletions(-) diff --git a/.prettierignore b/.prettierignore index ba2c7d0..09850a8 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,2 +1,3 @@ pnpm-lock.yaml /dist/ +*.snap diff --git a/README.md b/README.md index 7a7f9a5..04d102c 100644 --- a/README.md +++ b/README.md @@ -97,18 +97,19 @@ const b = styles['my_other-class']; Please note that no options are required. However, depending on your configuration, you may need to customise these options. -| Option | Default value | Description | -| -------------------------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------ | -| `classnameTransform` | `asIs` | See [`classnameTransform`](#classnameTransform) below. | -| `customMatcher` | `"\\.module\\.(c\|le\|sa\|sc)ss$"` | Changes the file extensions that this plugin processes. | -| `customRenderer` | `false` | See [`customRenderer`](#customRenderer) below. | -| `customTemplate` | `false` | See [`customTemplate`](#customTemplate) below. | -| `goToDefinition` | `false` | Enables jump to definition, with limited compatibility. See [`goToDefinition`](#goToDefinition) below. | -| `noUncheckedIndexedAccess` | `false` | Enable for compatibility with TypeScript's `noUncheckedIndexedAccess`. | -| `namedExports` | `true` | Enables named exports for compatible classnames. | -| `dotenvOptions` | `{}` | Provides options for [`dotenv`](https://github.com/motdotla/dotenv#options). | -| `postcssOptions` | `{}` | See [`postcssOptions`](#postcssOptions) below. | -| `rendererOptions` | `{}` | See [`rendererOptions`](#rendererOptions) below. | +| Option | Default value | Description | +| --------------------------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------ | +| `allowAdditionalClassnames` | `false` | Disables TypeScript warnings on unknown classnames (for default imports only). | +| `classnameTransform` | `asIs` | See [`classnameTransform`](#classnameTransform) below. | +| `customMatcher` | `"\\.module\\.(c\|le\|sa\|sc)ss$"` | Changes the file extensions that this plugin processes. | +| `customRenderer` | `false` | See [`customRenderer`](#customRenderer) below. | +| `customTemplate` | `false` | See [`customTemplate`](#customTemplate) below. | +| `goToDefinition` | `false` | Enables jump to definition, with limited compatibility. See [`goToDefinition`](#goToDefinition) below. | +| `noUncheckedIndexedAccess` | `false` | Enable for compatibility with TypeScript's `noUncheckedIndexedAccess`. | +| `namedExports` | `true` | Enables named exports for compatible classnames. | +| `dotenvOptions` | `{}` | Provides options for [`dotenv`](https://github.com/motdotla/dotenv#options). | +| `postcssOptions` | `{}` | See [`postcssOptions`](#postcssOptions) below. | +| `rendererOptions` | `{}` | See [`rendererOptions`](#rendererOptions) below. | ```json { diff --git a/src/helpers/__tests__/__snapshots__/getDtsSnapshot.test.ts.snap b/src/helpers/__tests__/__snapshots__/getDtsSnapshot.test.ts.snap index f4933c4..3dfc946 100644 --- a/src/helpers/__tests__/__snapshots__/getDtsSnapshot.test.ts.snap +++ b/src/helpers/__tests__/__snapshots__/getDtsSnapshot.test.ts.snap @@ -9,7 +9,7 @@ exports[`utils / cssSnapshots with a custom renderer should process a file and l } `; -exports[`utils / cssSnapshots with allowAdditionalClasses enabled should return a dts file that allows any string value 1`] = ` +exports[`utils / cssSnapshots with allowAdditionalClassnames enabled should return a dts file that allows any string value 1`] = ` "declare let classes: { 'localClassInsideGlobal': string; 'localClass': string; @@ -69,7 +69,7 @@ exports[`utils / cssSnapshots with baseUrl and paths in compilerOptions sass sho exports[`utils / cssSnapshots with file 'empty.module.less' createExports should create an exports file 1`] = ` "declare let classes: { - + }; export default classes; " @@ -80,7 +80,7 @@ exports[`utils / cssSnapshots with file 'empty.module.less' getCssExports should exports[`utils / cssSnapshots with file 'empty.module.less' with a custom template should transform the generated dts 1`] = ` "/* eslint-disable */ declare let classes: { - + }; export default classes; @@ -90,7 +90,7 @@ export type AllClassNames = '';" exports[`utils / cssSnapshots with file 'empty.module.sass' createExports should create an exports file 1`] = ` "declare let classes: { - + }; export default classes; " @@ -101,7 +101,7 @@ exports[`utils / cssSnapshots with file 'empty.module.sass' getCssExports should exports[`utils / cssSnapshots with file 'empty.module.sass' with a custom template should transform the generated dts 1`] = ` "/* eslint-disable */ declare let classes: { - + }; export default classes; @@ -111,7 +111,7 @@ export type AllClassNames = '';" exports[`utils / cssSnapshots with file 'empty.module.scss' createExports should create an exports file 1`] = ` "declare let classes: { - + }; export default classes; " @@ -122,7 +122,7 @@ exports[`utils / cssSnapshots with file 'empty.module.scss' getCssExports should exports[`utils / cssSnapshots with file 'empty.module.scss' with a custom template should transform the generated dts 1`] = ` "/* eslint-disable */ declare let classes: { - + }; export default classes; @@ -132,7 +132,7 @@ export type AllClassNames = '';" exports[`utils / cssSnapshots with file 'empty.module.styl' createExports should create an exports file 1`] = ` "declare let classes: { - + }; export default classes; " @@ -143,7 +143,7 @@ exports[`utils / cssSnapshots with file 'empty.module.styl' getCssExports should exports[`utils / cssSnapshots with file 'empty.module.styl' with a custom template should transform the generated dts 1`] = ` "/* eslint-disable */ declare let classes: { - + }; export default classes; diff --git a/src/helpers/__tests__/getDtsSnapshot.test.ts b/src/helpers/__tests__/getDtsSnapshot.test.ts index 24b4dba..9384911 100644 --- a/src/helpers/__tests__/getDtsSnapshot.test.ts +++ b/src/helpers/__tests__/getDtsSnapshot.test.ts @@ -291,12 +291,12 @@ describe('utils / cssSnapshots', () => { }); }); - describe('with allowAdditionalClasses enabled', () => { + describe('with allowAdditionalClassnames enabled', () => { const fileName = join(__dirname, 'fixtures', 'test.module.scss'); const css = readFileSync(fileName, 'utf8'); const options: Options = { classnameTransform: 'camelCaseOnly', - allowAdditionalClasses: true, + allowAdditionalClassnames: true, }; const cssExports = getCssExports({ diff --git a/src/helpers/createDtsExports.ts b/src/helpers/createDtsExports.ts index 9a071af..09f7070 100644 --- a/src/helpers/createDtsExports.ts +++ b/src/helpers/createDtsExports.ts @@ -43,7 +43,7 @@ export const createDtsExports = ({ let dts = `\ declare let classes: { ${processedClasses.map(classNameToProperty).join('\n ')}${ - options.allowAdditionalClasses ? '\n [key: string]: string;' : '' + options.allowAdditionalClassnames ? '\n [key: string]: string;' : '' } }; export default classes; diff --git a/src/options.ts b/src/options.ts index 324f084..44b3825 100644 --- a/src/options.ts +++ b/src/options.ts @@ -20,7 +20,7 @@ export interface RendererOptions { } export interface Options { - allowAdditionalClasses?: boolean; + allowAdditionalClassnames?: boolean; classnameTransform?: ClassnameTransformOptions; customMatcher?: string; customRenderer?: string; From 59525e11244ea016219b4bafce5618c3f4256780 Mon Sep 17 00:00:00 2001 From: Brody McKee Date: Sun, 4 Dec 2022 17:12:29 +1100 Subject: [PATCH 2/2] refactor: standardise classname casing --- README.md | 26 ++++++++-------- .../__snapshots__/getDtsSnapshot.test.ts.snap | 18 +++++------ src/helpers/__tests__/classTransforms.test.ts | 6 ++-- src/helpers/__tests__/getDtsSnapshot.test.ts | 4 +-- src/helpers/classTransforms.ts | 24 +++++++-------- src/helpers/createDtsExports.ts | 30 +++++++++---------- src/options.ts | 2 +- 7 files changed, 55 insertions(+), 55 deletions(-) diff --git a/README.md b/README.md index 04d102c..b18390a 100644 --- a/README.md +++ b/README.md @@ -97,19 +97,19 @@ const b = styles['my_other-class']; Please note that no options are required. However, depending on your configuration, you may need to customise these options. -| Option | Default value | Description | -| --------------------------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------ | -| `allowAdditionalClassnames` | `false` | Disables TypeScript warnings on unknown classnames (for default imports only). | -| `classnameTransform` | `asIs` | See [`classnameTransform`](#classnameTransform) below. | -| `customMatcher` | `"\\.module\\.(c\|le\|sa\|sc)ss$"` | Changes the file extensions that this plugin processes. | -| `customRenderer` | `false` | See [`customRenderer`](#customRenderer) below. | -| `customTemplate` | `false` | See [`customTemplate`](#customTemplate) below. | -| `goToDefinition` | `false` | Enables jump to definition, with limited compatibility. See [`goToDefinition`](#goToDefinition) below. | -| `noUncheckedIndexedAccess` | `false` | Enable for compatibility with TypeScript's `noUncheckedIndexedAccess`. | -| `namedExports` | `true` | Enables named exports for compatible classnames. | -| `dotenvOptions` | `{}` | Provides options for [`dotenv`](https://github.com/motdotla/dotenv#options). | -| `postcssOptions` | `{}` | See [`postcssOptions`](#postcssOptions) below. | -| `rendererOptions` | `{}` | See [`rendererOptions`](#rendererOptions) below. | +| Option | Default value | Description | +| -------------------------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------ | +| `allowUnknownClassnames` | `false` | Disables TypeScript warnings on unknown classnames (for default imports only). | +| `classnameTransform` | `asIs` | See [`classnameTransform`](#classnameTransform) below. | +| `customMatcher` | `"\\.module\\.(c\|le\|sa\|sc)ss$"` | Changes the file extensions that this plugin processes. | +| `customRenderer` | `false` | See [`customRenderer`](#customRenderer) below. | +| `customTemplate` | `false` | See [`customTemplate`](#customTemplate) below. | +| `goToDefinition` | `false` | Enables jump to definition, with limited compatibility. See [`goToDefinition`](#goToDefinition) below. | +| `noUncheckedIndexedAccess` | `false` | Enable for compatibility with TypeScript's `noUncheckedIndexedAccess`. | +| `namedExports` | `true` | Enables named exports for compatible classnames. | +| `dotenvOptions` | `{}` | Provides options for [`dotenv`](https://github.com/motdotla/dotenv#options). | +| `postcssOptions` | `{}` | See [`postcssOptions`](#postcssOptions) below. | +| `rendererOptions` | `{}` | See [`rendererOptions`](#rendererOptions) below. | ```json { diff --git a/src/helpers/__tests__/__snapshots__/getDtsSnapshot.test.ts.snap b/src/helpers/__tests__/__snapshots__/getDtsSnapshot.test.ts.snap index 3dfc946..b52333d 100644 --- a/src/helpers/__tests__/__snapshots__/getDtsSnapshot.test.ts.snap +++ b/src/helpers/__tests__/__snapshots__/getDtsSnapshot.test.ts.snap @@ -9,7 +9,7 @@ exports[`utils / cssSnapshots with a custom renderer should process a file and l } `; -exports[`utils / cssSnapshots with allowAdditionalClassnames enabled should return a dts file that allows any string value 1`] = ` +exports[`utils / cssSnapshots with allowUnknownClassnames enabled should return a dts file that allows any string value 1`] = ` "declare let classes: { 'localClassInsideGlobal': string; 'localClass': string; @@ -69,7 +69,7 @@ exports[`utils / cssSnapshots with baseUrl and paths in compilerOptions sass sho exports[`utils / cssSnapshots with file 'empty.module.less' createExports should create an exports file 1`] = ` "declare let classes: { - + }; export default classes; " @@ -80,7 +80,7 @@ exports[`utils / cssSnapshots with file 'empty.module.less' getCssExports should exports[`utils / cssSnapshots with file 'empty.module.less' with a custom template should transform the generated dts 1`] = ` "/* eslint-disable */ declare let classes: { - + }; export default classes; @@ -90,7 +90,7 @@ export type AllClassNames = '';" exports[`utils / cssSnapshots with file 'empty.module.sass' createExports should create an exports file 1`] = ` "declare let classes: { - + }; export default classes; " @@ -101,7 +101,7 @@ exports[`utils / cssSnapshots with file 'empty.module.sass' getCssExports should exports[`utils / cssSnapshots with file 'empty.module.sass' with a custom template should transform the generated dts 1`] = ` "/* eslint-disable */ declare let classes: { - + }; export default classes; @@ -111,7 +111,7 @@ export type AllClassNames = '';" exports[`utils / cssSnapshots with file 'empty.module.scss' createExports should create an exports file 1`] = ` "declare let classes: { - + }; export default classes; " @@ -122,7 +122,7 @@ exports[`utils / cssSnapshots with file 'empty.module.scss' getCssExports should exports[`utils / cssSnapshots with file 'empty.module.scss' with a custom template should transform the generated dts 1`] = ` "/* eslint-disable */ declare let classes: { - + }; export default classes; @@ -132,7 +132,7 @@ export type AllClassNames = '';" exports[`utils / cssSnapshots with file 'empty.module.styl' createExports should create an exports file 1`] = ` "declare let classes: { - + }; export default classes; " @@ -143,7 +143,7 @@ exports[`utils / cssSnapshots with file 'empty.module.styl' getCssExports should exports[`utils / cssSnapshots with file 'empty.module.styl' with a custom template should transform the generated dts 1`] = ` "/* eslint-disable */ declare let classes: { - + }; export default classes; diff --git a/src/helpers/__tests__/classTransforms.test.ts b/src/helpers/__tests__/classTransforms.test.ts index 897a4ef..dc391e6 100644 --- a/src/helpers/__tests__/classTransforms.test.ts +++ b/src/helpers/__tests__/classTransforms.test.ts @@ -2,7 +2,7 @@ import { transformClasses } from '../classTransforms'; import { ClassnameTransformOptions } from '../../options'; describe('utils / classTransforms', () => { - const classNames = [ + const classnames = [ 'class-name-a', 'classNameB', 'class-Name-C', @@ -18,14 +18,14 @@ describe('utils / classTransforms', () => { it('should not transform classes when no option is set', () => { const transformer = transformClasses(); - const transformedClasses = classNames.map(transformer); + const transformedClasses = classnames.map(transformer); expect(transformedClasses).toMatchSnapshot(); }); tests.forEach((option) => { it(`should transform classes correctly when \`classnameTransform\` set to \`${option}\``, () => { const transformer = transformClasses(option); - const transformedClasses = classNames.map(transformer); + const transformedClasses = classnames.map(transformer); expect(transformedClasses).toMatchSnapshot(); }); }); diff --git a/src/helpers/__tests__/getDtsSnapshot.test.ts b/src/helpers/__tests__/getDtsSnapshot.test.ts index 9384911..bfb60f1 100644 --- a/src/helpers/__tests__/getDtsSnapshot.test.ts +++ b/src/helpers/__tests__/getDtsSnapshot.test.ts @@ -291,12 +291,12 @@ describe('utils / cssSnapshots', () => { }); }); - describe('with allowAdditionalClassnames enabled', () => { + describe('with allowUnknownClassnames enabled', () => { const fileName = join(__dirname, 'fixtures', 'test.module.scss'); const css = readFileSync(fileName, 'utf8'); const options: Options = { classnameTransform: 'camelCaseOnly', - allowAdditionalClassnames: true, + allowUnknownClassnames: true, }; const cssExports = getCssExports({ diff --git a/src/helpers/classTransforms.ts b/src/helpers/classTransforms.ts index 31e4b2f..0e53459 100644 --- a/src/helpers/classTransforms.ts +++ b/src/helpers/classTransforms.ts @@ -4,42 +4,42 @@ import { ClassnameTransformOptions } from '../options'; // The below is based on the CSS Modules implementation found here: // https://github.com/webpack-contrib/css-loader -const dashCase = (className: string): string => - className.replace(/-+(\w)/g, (_match: string, firstLetter: string) => +const dashCase = (classname: string): string => + classname.replace(/-+(\w)/g, (_match: string, firstLetter: string) => firstLetter.toUpperCase(), ); export const transformClasses = (camelCaseOption?: ClassnameTransformOptions) => - (className: string): string[] => { + (classname: string): string[] => { const entries: string[] = []; switch (camelCaseOption) { case 'camelCase': { - entries.push(className); - const targetClassName = camelCase(className); - if (targetClassName !== className) { + entries.push(classname); + const targetClassName = camelCase(classname); + if (targetClassName !== classname) { entries.push(targetClassName); } break; } case 'camelCaseOnly': - entries.push(camelCase(className)); + entries.push(camelCase(classname)); break; case 'dashes': { - entries.push(className); - const targetClassName = dashCase(className); - if (targetClassName !== className) { + entries.push(classname); + const targetClassName = dashCase(classname); + if (targetClassName !== classname) { entries.push(targetClassName); } break; } case 'dashesOnly': - entries.push(dashCase(className)); + entries.push(dashCase(classname)); break; case 'asIs': default: - entries.push(className); + entries.push(classname); break; } diff --git a/src/helpers/createDtsExports.ts b/src/helpers/createDtsExports.ts index 09f7070..7533e0e 100644 --- a/src/helpers/createDtsExports.ts +++ b/src/helpers/createDtsExports.ts @@ -5,8 +5,8 @@ import { CSSExportsWithSourceMap } from './getCssExports'; import { VALID_VARIABLE_REGEXP } from './validVarRegexp'; import { Logger } from './logger'; -const isValidVariable = (className: string) => - VALID_VARIABLE_REGEXP.test(className); +const isValidVariable = (classname: string) => + VALID_VARIABLE_REGEXP.test(classname); const flattenClassNames = ( previousValue: string[] = [], @@ -28,22 +28,22 @@ export const createDtsExports = ({ const possiblyUndefined = Boolean(options.noUncheckedIndexedAccess); - const classNameToProperty = (className: string) => - `'${className}'${possiblyUndefined ? '?' : ''}: string;`; - const classNameToNamedExport = (className: string) => - `export let ${className}${possiblyUndefined ? '?' : ''}: string;`; + const classnameToProperty = (classname: string) => + `'${classname}'${possiblyUndefined ? '?' : ''}: string;`; + const classnameToNamedExport = (classname: string) => + `export let ${classname}${possiblyUndefined ? '?' : ''}: string;`; const processedClasses = Object.keys(classes) .map(transformClasses(options.classnameTransform)) .reduce(flattenClassNames, []); const filteredClasses = processedClasses .filter(isValidVariable) - .map(classNameToNamedExport); + .map(classnameToNamedExport); let dts = `\ declare let classes: { - ${processedClasses.map(classNameToProperty).join('\n ')}${ - options.allowAdditionalClassnames ? '\n [key: string]: string;' : '' + ${processedClasses.map(classnameToProperty).join('\n ')}${ + options.allowUnknownClassnames ? '\n [key: string]: string;' : '' } }; export default classes; @@ -65,15 +65,15 @@ export default classes; // Create a list of filtered classnames and hashed classnames. const filteredClasses = Object.entries(cssExports.classes) - .map(([className, hashedClassName]) => [ + .map(([classname, hashedClassname]) => [ // TODO: Improve this. It may return multiple valid classnames and we // want to handle all of those. - transformClasses(options.classnameTransform)(className)[0], - hashedClassName, + transformClasses(options.classnameTransform)(classname)[0], + hashedClassname, ]) - .filter(([className]) => isValidVariable(className)); + .filter(([classname]) => isValidVariable(classname)); - filteredClasses.forEach(([className, hashedClassName]) => { + filteredClasses.forEach(([classname, hashedClassName]) => { const matchedLine = cssLines.findIndex((line) => line.includes(hashedClassName), ); @@ -85,7 +85,7 @@ export default classes; column: matchedColumn >= 0 ? matchedColumn : 0, }); dtsLines[lineNumber ? lineNumber - 1 : 0] += - classNameToNamedExport(className); + classnameToNamedExport(classname); }); dts = dtsLines.join('\n'); diff --git a/src/options.ts b/src/options.ts index 44b3825..da348e9 100644 --- a/src/options.ts +++ b/src/options.ts @@ -20,7 +20,7 @@ export interface RendererOptions { } export interface Options { - allowAdditionalClassnames?: boolean; + allowUnknownClassnames?: boolean; classnameTransform?: ClassnameTransformOptions; customMatcher?: string; customRenderer?: string;