Skip to content

feat: enable compatibility with noUncheckedIndexedAccess #177

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
merged 1 commit into from
Dec 4, 2022
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
25 changes: 13 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,17 +97,18 @@ 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. |
| `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 |
| -------------------------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------ |
| `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
{
Expand Down Expand Up @@ -195,7 +196,7 @@ The `classes` object represents all the classnames extracted from the CSS Module

#### `goToDefinition`

This allows an editor like Visual Studio Code to jump to a classname's definition (file and line).
This allows an editor like Visual Studio Code to go to a classname's definition (file and line).

This is experimental, and only works with Sass (for now) and may not always work as expected.

Expand Down
49 changes: 49 additions & 0 deletions src/helpers/__tests__/__snapshots__/getDtsSnapshot.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -855,3 +855,52 @@ exports[`utils / cssSnapshots with includePaths in stylus options should find ex
"include-path": "include-path-module__include-path---2f2uR",
}
`;

exports[`utils / cssSnapshots with noUncheckedIndexedAccess enabled should return a dts file with only possibly undefined strings 1`] = `
"declare let classes: {
'localClassInsideGlobal'?: string;
'localClass'?: string;
'localClass2'?: string;
'localClassInsideLocal'?: string;
'reservedWords'?: string;
'default'?: string;
'const'?: string;
'nestedClassParent'?: string;
'childClass'?: string;
'nestedClassParentExtended'?: string;
'section1'?: string;
'section2'?: string;
'section3'?: string;
'section4'?: string;
'section5'?: string;
'section6'?: string;
'section7'?: string;
'section8'?: string;
'section9'?: string;
'classWithMixin'?: string;
'appLogo'?: string;
'appLogo'?: string;
};
export default classes;
export let localClassInsideGlobal?: string;
export let localClass?: string;
export let localClass2?: string;
export let localClassInsideLocal?: string;
export let reservedWords?: string;
export let nestedClassParent?: string;
export let childClass?: string;
export let nestedClassParentExtended?: string;
export let section1?: string;
export let section2?: string;
export let section3?: string;
export let section4?: string;
export let section5?: string;
export let section6?: string;
export let section7?: string;
export let section8?: string;
export let section9?: string;
export let classWithMixin?: string;
export let appLogo?: string;
export let appLogo?: string;
"
`;
29 changes: 29 additions & 0 deletions src/helpers/__tests__/getDtsSnapshot.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -253,4 +253,33 @@ describe('utils / cssSnapshots', () => {
expect(dts).toMatchSnapshot();
});
});

describe('with noUncheckedIndexedAccess enabled', () => {
const fileName = join(__dirname, 'fixtures', 'test.module.scss');
const css = readFileSync(fileName, 'utf8');
const options: Options = {
classnameTransform: 'camelCaseOnly',
noUncheckedIndexedAccess: true,
};

const cssExports = getCssExports({
css,
fileName,
logger,
options,
processor,
compilerOptions,
});

it('should return a dts file with only possibly undefined strings', () => {
const dts = createDtsExports({
cssExports,
fileName,
logger,
options,
});
expect(dts).not.toMatch(/\w'?: string/);
expect(dts).toMatchSnapshot();
});
});
});
2 changes: 1 addition & 1 deletion src/helpers/classTransforms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import camelCase from 'lodash.camelcase';
import { ClassnameTransformOptions } from '../options';

// The below is based on the CSS Modules implementation found here:
// https://github.com/webpack-contrib/css-loader/blob/master/lib/compile-exports.js
// https://github.com/webpack-contrib/css-loader

const dashCase = (className: string): string =>
className.replace(/-+(\w)/g, (_match: string, firstLetter: string) =>
Expand Down
11 changes: 7 additions & 4 deletions src/helpers/createDtsExports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,6 @@ import { Logger } from './logger';
const isValidVariable = (className: string) =>
VALID_VARIABLE_REGEXP.test(className);

const classNameToProperty = (className: string) => `'${className}': string;`;
const classNameToNamedExport = (className: string) =>
`export let ${className}: string;`;

const flattenClassNames = (
previousValue: string[] = [],
currentValue: string[],
Expand All @@ -30,6 +26,13 @@ export const createDtsExports = ({
}): string => {
const classes = cssExports.classes;

const possiblyUndefined = Boolean(options.noUncheckedIndexedAccess);

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, []);
Expand Down
5 changes: 2 additions & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,8 @@ function init({ typescript: ts }: { typescript: typeof tsModule }) {
process.chdir(directory);

// User options for plugin.

const config = info.config as { options?: Options };
const options = config.options ?? {};
const options: Options =
(info.config as { options?: Options }).options ?? {};
logger.log(`options: ${JSON.stringify(options)}`);

// Load environment variables like SASS_PATH.
Expand Down
3 changes: 2 additions & 1 deletion src/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@ export interface Options {
dotenvOptions?: DotenvConfigOptions;
goToDefinition?: boolean;
namedExports?: boolean;
noUncheckedIndexedAccess?: boolean;
postcssOptions?: PostcssOptions;
/** @deprecated To align with other projects. */
/** @deprecated To align with naming in other projects. */
postCssOptions?: PostcssOptions;
rendererOptions?: RendererOptions;
}
Expand Down