diff --git a/common/changes/@rushstack/heft-sass-plugin/named-css-shims_2026-10-28-13-00.json b/common/changes/@rushstack/heft-sass-plugin/named-css-shims_2026-10-28-13-00.json new file mode 100644 index 00000000000..dc74a62ebd9 --- /dev/null +++ b/common/changes/@rushstack/heft-sass-plugin/named-css-shims_2026-10-28-13-00.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@rushstack/heft-sass-plugin", + "comment": "Support named exports when emitting CSS and CommonJS or ESM shims with `exportAsDefault` set to false.", + "type": "minor" + } + ], + "packageName": "@rushstack/heft-sass-plugin" +} diff --git a/heft-plugins/heft-sass-plugin/README.md b/heft-plugins/heft-sass-plugin/README.md index fe276a33d04..5202ffe6d3c 100644 --- a/heft-plugins/heft-sass-plugin/README.md +++ b/heft-plugins/heft-sass-plugin/README.md @@ -157,7 +157,7 @@ All options are set in `config/sass.json`. Every option is optional. | `srcFolder` | `"src/"` | Root directory that is scanned for SCSS files | | `generatedTsFolder` | `"temp/sass-ts/"` | Output directory for generated `.d.ts` files | | `secondaryGeneratedTsFolders` | `[]` | Additional directories to also write `.d.ts` files to (e.g. `"lib-esm"` when publishing typings alongside compiled output) | -| `exportAsDefault` | `true` | When `true`, wraps exports in a typed default interface. When `false`, generates individual named exports (`export const className: string`). Note: `false` is incompatible with `cssOutputFolders`. | +| `exportAsDefault` | `true` | When `true`, wraps exports in a typed default interface. When `false`, generates individual named string exports. JavaScript shims use the same export style; configure the downstream CSS loader to match. | | `cssOutputFolders` | _(none)_ | Folders where compiled `.css` files are written. Each entry is either a plain folder path string, or an object with `folder` and optional `shimModuleFormat` (see below). | | `fileExtensions` | `[".sass", ".scss", ".css"]` | File extensions to treat as CSS modules | | `nonModuleFileExtensions` | `[".global.sass", ".global.scss", ".global.css"]` | File extensions to treat as global (non-module) stylesheets | @@ -181,7 +181,7 @@ Each entry in `cssOutputFolders` can be a plain string (folder path only) or an } ``` -When `shimModuleFormat` is set, the plugin writes a `.js` shim alongside each `.css` file. For a CSS module, the shim re-exports the CSS: +When `shimModuleFormat` is set, the plugin writes a `.js` shim alongside each `.css` file. For a CSS module with `exportAsDefault: true` (the default), the shim re-exports the CSS: ```js // ESM shim (shimModuleFormat: "esnext") @@ -192,7 +192,63 @@ module.exports = require("./Button.module.css"); module.exports.default = module.exports; ``` -For a global stylesheet, the shim is a side-effect-only import: +With `exportAsDefault: false`, the shim forwards named exports instead: + +```js +// ESM shim +export * from "./Button.module.css"; + +// CommonJS shim +module.exports = require("./Button.module.css"); +``` + +The ESM shim keeps named re-exports statically analyzable and does not forward the CSS loader's default +export. The CommonJS shim forwards the loader's exports unchanged, including any `__esModule` marker; +it does not synthesize a default styles object or overwrite a loader-provided default export. + +The consuming bundler must configure its CSS loader for named exports (for example, css-loader with +`esModule: true` and `modules.namedExport: true`). Export names must match the generated typings; use +`modules.exportLocalsConvention: "as-is"` with css-loader versions that support it, or restrict names +to ones unchanged by the loader's convention. Non-identifier names such as `base-style` use quoted +export aliases in the typings (requiring TypeScript 5.6 or newer): + +```typescript +declare const id0: string; +export { id0 as "base-style" }; +``` + +Generated alias names avoid collisions with the stylesheet's own exports. The CSS loader must also +preserve these export names; consumers can access them with `styles["base-style"]`. +Aliases such as `id0` are private bindings inside the declaration file, not additional public exports +or runtime variables. `styles.id0` is available only if the stylesheet itself exports a name `id0`. +Named declarations use private bindings for identifier-shaped names as well, so JavaScript keywords +such as `class` and `function` never become invalid variable declarations. +Set `preserveIcssExports: true` when the downstream loader must process ICSS `:export` values or +`composes` declarations. + +#### Loader compatibility + +CSS Modules do not inherently require a JavaScript default export; the loader determines that +interface. [css-loader 5](https://github.com/webpack/css-loader/tree/v5.2.7#namedexport) already supported +opt-in named exports, but required camelCase names and disallowed JavaScript keywords. +[css-loader 7](https://github.com/webpack/css-loader/tree/v7.1.5#namedexport) enables named exports by +default with `esModule: true` and supports `exportLocalsConvention: "as-is"`. + +The class name `default` is a special case: css-loader exposes it as `_default` in named mode, and +the generated typings follow that convention. A stylesheet exporting both `default` and `_default` +is rejected in named mode because the loader would produce duplicate exports; default-export mode +still supports both names. +For default-export mode, use ESM shims when a stylesheet has a `default` class: the legacy CommonJS +shim synthesizes a `.default` interop property, which can overwrite that key in a loader's class map. + +Valid declarations alone cannot fix loader-generated JavaScript. css-loader 7.1.4 and 7.1.5 have a +reserved-word limitation for names such as `let`, `yield`, `await`, `eval`, and `arguments`. Avoid those +names in named mode, or use matching default-export settings until the loader supports them. +The [css-loader repository](https://github.com/webpack/css-loader) is archived; these are compatibility +limits of the tested releases, not a promise of a future loader fix. + +For a global stylesheet, or a CSS module with no local exports, the shim is a side-effect-only import +regardless of `exportAsDefault`: ```js // ESM shim diff --git a/heft-plugins/heft-sass-plugin/src/SassProcessor.ts b/heft-plugins/heft-sass-plugin/src/SassProcessor.ts index e2e8d9057ed..f71f32b5e3f 100644 --- a/heft-plugins/heft-sass-plugin/src/SassProcessor.ts +++ b/heft-plugins/heft-sass-plugin/src/SassProcessor.ts @@ -88,7 +88,8 @@ export interface ISassProcessorOptions { cssOutputFolders?: ICssOutputFolder[]; /** - * Determines whether export values are wrapped in a default property, or not. + * Determines whether typings and JavaScript shims use a default export or named exports. + * The downstream CSS loader must use the corresponding export style. */ exportAsDefault: boolean; @@ -1004,10 +1005,6 @@ export class SassProcessor { } if (cssOutputFolders && cssOutputFolders.length > 0) { - if (!exportAsDefault) { - throw new Error(`The "cssOutputFolders" option is not supported when "exportAsDefault" is false.`); - } - const filename: string = path.basename(relativeFilePath); let cssFilename: string; let relativeCssPath: string; @@ -1058,7 +1055,8 @@ export class SassProcessor { const jsShimContent: string = generateJsShimContent( shimModuleFormat, cssPathFromJs, - hasModuleExports + hasModuleExports, + exportAsDefault ); await FileSystem.writeFileAsync(jsFilePath, jsShimContent, writeFileOptions); } @@ -1096,14 +1094,31 @@ function createDTS( source.push(`declare const styles: IStyles;`); source.push(`export default styles;`); } else { - for (const className of Object.keys(moduleMap)) { - if (!SIMPLE_IDENTIFIER_REGEX.test(className)) { - throw new Error( - `Class name "${className}" is not a valid identifier and may only be exported using "exportAsDefault: true"` - ); - } + // css-loader exposes a class named "default" as "_default", reserving default for its CSS API. + if ( + Object.prototype.hasOwnProperty.call(moduleMap, 'default') && + Object.prototype.hasOwnProperty.call(moduleMap, '_default') + ) { + throw new Error( + 'CSS exports "default" and "_default" both map to "_default" in named mode. Rename one of them or use "exportAsDefault: true".' + ); + } - source.push(`export const ${className}: string;`); + let identifierIndex: number = 0; + for (const className of Object.keys(moduleMap)) { + let identifier: string; + do { + identifier = `id${identifierIndex++}`; + } while (Object.prototype.hasOwnProperty.call(moduleMap, identifier)); + + const exportName: string = className === 'default' ? '_default' : className; + const exportSpecifier: string = SIMPLE_IDENTIFIER_REGEX.test(exportName) + ? exportName + : JSON.stringify(exportName); + source.push( + `declare const ${identifier}: string;`, + `export { ${identifier} as ${exportSpecifier} };` + ); } } @@ -1275,15 +1290,23 @@ function determineSyntaxFromFilePath(filePath: string): Syntax { function generateJsShimContent( format: 'commonjs' | 'esnext', relativePathToCss: string, - isModule: boolean | undefined + hasModuleExports: boolean | undefined, + exportAsDefault: boolean ): string { const pathString: string = JSON.stringify(relativePathToCss); switch (format) { case 'commonjs': - return isModule + if (!hasModuleExports) { + return `require(${pathString});`; + } + + // Named exports preserve the loader's namespace and __esModule marker without synthesizing a default. + return exportAsDefault ? `module.exports = require(${pathString});\nmodule.exports.default = module.exports;` - : `require(${pathString});`; + : `module.exports = require(${pathString});`; case 'esnext': - return isModule ? `export { default } from ${pathString};` : `import ${pathString};export {};`; + return hasModuleExports + ? `export ${exportAsDefault ? '{ default }' : '*'} from ${pathString};` + : `import ${pathString};export {};`; } } diff --git a/heft-plugins/heft-sass-plugin/src/schemas/heft-sass-plugin.schema.json b/heft-plugins/heft-sass-plugin/src/schemas/heft-sass-plugin.schema.json index f4b34b60856..13518760204 100644 --- a/heft-plugins/heft-sass-plugin/src/schemas/heft-sass-plugin.schema.json +++ b/heft-plugins/heft-sass-plugin/src/schemas/heft-sass-plugin.schema.json @@ -37,7 +37,7 @@ "exportAsDefault": { "type": "boolean", - "description": "Determines whether export values are wrapped in a default property, or not." + "description": "Determines whether typings and JavaScript shims use a default export (true) or named exports (false). Configure the downstream CSS loader to use the same export style." }, "cssOutputFolders": { diff --git a/heft-plugins/heft-sass-plugin/src/templates/sass.json b/heft-plugins/heft-sass-plugin/src/templates/sass.json index 73f4eff6584..cb0ccb2fd57 100644 --- a/heft-plugins/heft-sass-plugin/src/templates/sass.json +++ b/heft-plugins/heft-sass-plugin/src/templates/sass.json @@ -36,7 +36,7 @@ * Determines whether CSS module exports are wrapped in a typed default interface (true) or emitted as * individual named exports (false). * - * Note: setting this to false is incompatible with cssOutputFolders. + * JavaScript shims use the same export style. Configure the downstream CSS loader to match. * * Default value: true */ diff --git a/heft-plugins/heft-sass-plugin/src/test/SassProcessor.test.ts b/heft-plugins/heft-sass-plugin/src/test/SassProcessor.test.ts index b5eefedfad4..eb4565aa79a 100644 --- a/heft-plugins/heft-sass-plugin/src/test/SassProcessor.test.ts +++ b/heft-plugins/heft-sass-plugin/src/test/SassProcessor.test.ts @@ -3,6 +3,7 @@ import path from 'node:path'; import nodeJsPath from 'node:path'; +import { runInNewContext } from 'node:vm'; import { FileSystem, Path, Text } from '@rushstack/node-core-library'; import { MockScopedLogger } from '@rushstack/heft/lib/pluginFramework/logging/MockScopedLogger'; @@ -271,17 +272,14 @@ describe(SassProcessor.name, () => { }); it('generates named exports in .d.ts when exportAsDefault is false', async () => { - // cssOutputFolders requires exportAsDefault: true, so omit it here const { processor } = createProcessor(terminalProvider, { - exportAsDefault: false, - cssOutputFolders: [] + exportAsDefault: false }); await compileFixtureAsync(processor, 'classes-and-exports.module.scss'); const dts: string = getDtsOutput('classes-and-exports.module.scss'); - // Named exports: "export const root: string;" instead of a default interface - expect(dts).toContain('export const root'); - expect(dts).toContain('export const highlighted'); - expect(dts).toContain('export const themeColor'); + expect(dts).toContain(' as root };'); + expect(dts).toContain(' as highlighted };'); + expect(dts).toContain(' as themeColor };'); expect(dts).not.toContain('export default'); }); }); @@ -387,6 +385,155 @@ describe(SassProcessor.name, () => { }); describe('JS shim files', () => { + it('uses collision-free quoted export aliases for non-identifier class names and ICSS exports', async () => { + const { processor } = createProcessor(terminalProvider, { exportAsDefault: false }); + await compileFixtureAsync(processor, 'composed.module.scss'); + const dts: string = getDtsOutput('composed.module.scss'); + expect(dts).toContain(' as base_style };'); + expect(dts).toContain(' as id0 };'); + expect(dts).toContain('declare const id2: string;\nexport { id2 as "theme-color" };'); + expect(dts).toContain('declare const id4: string;\nexport { id4 as "base-style" };'); + expect(dts).not.toContain('export default'); + expect(terminalProvider.getOutput({ normalizeSpecialCharacters: true })).not.toContain('ERROR'); + }); + + it('uses private bindings for reserved names and matches the loader default-class convention', async () => { + const { processor, logger } = createProcessor(terminalProvider, { exportAsDefault: false }); + await compileFixtureAsync(processor, 'reserved.module.scss'); + expect(logger.errors).toHaveLength(0); + const dts: string = getDtsOutput('reserved.module.scss'); + for (const name of [ + 'class', + 'function', + 'for', + 'return', + 'enum', + 'implements', + 'interface', + 'private', + 'protected', + 'public', + 'static', + 'let', + 'yield', + 'await', + 'eval', + 'arguments', + 'true', + 'false', + 'null', + '_default', + 'id0' + ]) { + expect(dts).toContain(` as ${name} };`); + expect(dts).not.toContain(`export const ${name}:`); + } + + expect(dts).not.toContain(' as default };'); + }); + + it('reports the loader default-name collision in named mode', async () => { + const { processor, logger } = createProcessor(terminalProvider, { exportAsDefault: false }); + await compileFixtureAsync(processor, 'default-collision.module.scss'); + expect(logger.errors).toHaveLength(1); + expect(logger.errors[0].message).toContain('"default" and "_default"'); + expect(writtenFiles.size).toBe(0); + }); + + it('preserves both default and _default class names in default mode', async () => { + const { processor, logger } = createProcessor(terminalProvider); + await compileFixtureAsync(processor, 'default-collision.module.scss'); + expect(logger.errors).toHaveLength(0); + const dts: string = getDtsOutput('default-collision.module.scss'); + expect(dts).toContain('default: string;'); + expect(dts).toContain('_default: string;'); + expect(dts).toContain('export default styles;'); + }); + + describe.each(['commonjs', 'esnext'] as const)('named exports (%s)', (format: 'commonjs' | 'esnext') => { + it.each([ + 'classes-and-exports.module.scss', + 'export-only.module.scss', + 'composed.module.scss', + 'loader-reserved.module.scss', + 'simple.module.sass' + ])( + 'forwards named exports for %s without changing CSS or source maps', + async (fixtureFilename: string) => { + const options: ICreateProcessorOptions = { + cssOutputFolders: [{ folder: CSS_OUTPUT_FOLDER, shimModuleFormat: format }], + doNotTrimOriginalFileExtension: true, + preserveIcssExports: true, + sourceMap: true + }; + const { processor: defaultProcessor } = createProcessor(terminalProvider, options); + await compileFixtureAsync(defaultProcessor, fixtureFilename); + const defaultCss: string = getWrittenFile(`${fixtureFilename}.css`); + const defaultMap: string = getWrittenFile(`${fixtureFilename}.css.map`); + writtenFiles.clear(); + + const { processor } = createProcessor(terminalProvider, { ...options, exportAsDefault: false }); + await compileFixtureAsync(processor, fixtureFilename); + const shim: string = getJsShimOutput(fixtureFilename); + const cssSpecifier: string = JSON.stringify(`./${fixtureFilename}.css`); + expect(shim).toBe( + format === 'esnext' + ? `export * from ${cssSpecifier};` + : `module.exports = require(${cssSpecifier});` + ); + expect(getDtsOutput(fixtureFilename)).toContain('declare const '); + expect(getDtsOutput(fixtureFilename)).not.toContain('export default'); + expect(getWrittenFile(`${fixtureFilename}.css`)).toBe(defaultCss); + expect(getWrittenFile(`${fixtureFilename}.css.map`)).toBe(defaultMap); + } + ); + + it.each(['global-styles.global.scss', 'global-only.module.scss', 'empty.module.scss'])( + 'keeps %s side-effect-only', + async (fixtureFilename: string) => { + const { processor } = createProcessor(terminalProvider, { + exportAsDefault: false, + cssOutputFolders: [{ folder: CSS_OUTPUT_FOLDER, shimModuleFormat: format }] + }); + await compileFixtureAsync(processor, fixtureFilename); + const cssSpecifier: string = JSON.stringify(`./${fixtureFilename.replace(/\.scss$/, '.css')}`); + expect(getJsShimOutput(fixtureFilename)).toBe( + format === 'esnext' ? `import ${cssSpecifier};export {};` : `require(${cssSpecifier});` + ); + expect(getDtsOutput(fixtureFilename)).toBe('export {};'); + } + ); + }); + + it.each([false, true])( + 'forwards CommonJS named exports unchanged with __esModule=%s', + async (esModule: boolean) => { + const { processor } = createProcessor(terminalProvider, { + exportAsDefault: false, + cssOutputFolders: [{ folder: CSS_OUTPUT_FOLDER, shimModuleFormat: 'commonjs' }] + }); + await compileFixtureAsync(processor, 'classes-and-exports.module.scss'); + const cssExports: { root: string; default?: unknown } = { root: 'hashed-root' }; + if (esModule) { + Object.defineProperty(cssExports, '__esModule', { value: true }); + // css-loader can export its CSS API as default alongside named class exports. + cssExports.default = ['CSS API']; + } + + const originalDescriptors: PropertyDescriptorMap = Object.getOwnPropertyDescriptors(cssExports); + const shimModule: { exports: unknown } = { exports: {} }; + const requireCss: jest.Mock = jest.fn(() => cssExports); + runInNewContext(getJsShimOutput('classes-and-exports.module.scss'), { + module: shimModule, + require: requireCss + }); + expect(requireCss).toHaveBeenCalledTimes(1); + expect(requireCss).toHaveBeenCalledWith('./classes-and-exports.module.css'); + expect(shimModule.exports).toBe(cssExports); + expect(Object.getOwnPropertyDescriptors(cssExports)).toEqual(originalDescriptors); + } + ); + it('emits a CommonJS shim for a module file', async () => { const { processor } = createProcessor(terminalProvider, { cssOutputFolders: [{ folder: CSS_OUTPUT_FOLDER, shimModuleFormat: 'commonjs' }] diff --git a/heft-plugins/heft-sass-plugin/src/test/__snapshots__/SassProcessor.test.ts.snap b/heft-plugins/heft-sass-plugin/src/test/__snapshots__/SassProcessor.test.ts.snap index 586fa188657..808f48fa252 100644 --- a/heft-plugins/heft-sass-plugin/src/test/__snapshots__/SassProcessor.test.ts.snap +++ b/heft-plugins/heft-sass-plugin/src/test/__snapshots__/SassProcessor.test.ts.snap @@ -135,6 +135,701 @@ h1 { } `; +exports[`SassProcessor JS shim files forwards CommonJS named exports unchanged with __esModule=false: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor JS shim files forwards CommonJS named exports unchanged with __esModule=false: written-files 1`] = ` +Map { + "/fake/output/dts/classes-and-exports.module.scss.d.ts" => "declare const id0: string; +export { id0 as themeColor }; +declare const id1: string; +export { id1 as spacing }; +declare const id2: string; +export { id2 as root }; +declare const id3: string; +export { id3 as highlighted };", + "/fake/output/css/classes-and-exports.module.css" => ".root { + color: red; + font-size: 14px; +} + +.highlighted { + background-color: yellow; +}", + "/fake/output/css/classes-and-exports.module.scss.js" => "module.exports = require(\\"./classes-and-exports.module.css\\");", +} +`; + +exports[`SassProcessor JS shim files forwards CommonJS named exports unchanged with __esModule=true: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor JS shim files forwards CommonJS named exports unchanged with __esModule=true: written-files 1`] = ` +Map { + "/fake/output/dts/classes-and-exports.module.scss.d.ts" => "declare const id0: string; +export { id0 as themeColor }; +declare const id1: string; +export { id1 as spacing }; +declare const id2: string; +export { id2 as root }; +declare const id3: string; +export { id3 as highlighted };", + "/fake/output/css/classes-and-exports.module.css" => ".root { + color: red; + font-size: 14px; +} + +.highlighted { + background-color: yellow; +}", + "/fake/output/css/classes-and-exports.module.scss.js" => "module.exports = require(\\"./classes-and-exports.module.css\\");", +} +`; + +exports[`SassProcessor JS shim files named exports (commonjs) forwards named exports for classes-and-exports.module.scss without changing CSS or source maps: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor JS shim files named exports (commonjs) forwards named exports for classes-and-exports.module.scss without changing CSS or source maps: written-files 1`] = ` +Map { + "/fake/output/dts/classes-and-exports.module.scss.d.ts" => "declare const id0: string; +export { id0 as themeColor }; +declare const id1: string; +export { id1 as spacing }; +declare const id2: string; +export { id2 as root }; +declare const id3: string; +export { id3 as highlighted };", + "/fake/output/css/classes-and-exports.module.scss.css" => ".root { + color: red; + font-size: 14px; +} + +.highlighted { + background-color: yellow; +} + +:export { + themeColor: blue; + spacing: 8px; +} +/*# sourceMappingURL=classes-and-exports.module.scss.css.map */ +", + "/fake/output/css/classes-and-exports.module.scss.css.map" => "{\\"version\\":3,\\"sourceRoot\\":\\"\\",\\"sources\\":[\\"fixtures/classes-and-exports.module.scss\\"],\\"names\\":[],\\"mappings\\":\\"AACA;EACE;EACA;;;AAGF;EACE;;;AAGF;EACE;EACA\\",\\"sourcesContent\\":[\\"// A CSS module that exports both class names and ICSS :export values.\\\\n.root {\\\\n color: red;\\\\n font-size: 14px;\\\\n}\\\\n\\\\n.highlighted {\\\\n background-color: yellow;\\\\n}\\\\n\\\\n:export {\\\\n themeColor: blue;\\\\n spacing: 8px;\\\\n}\\\\n\\"],\\"file\\":\\"classes-and-exports.module.scss.css\\"}", + "/fake/output/css/classes-and-exports.module.scss.js" => "module.exports = require(\\"./classes-and-exports.module.scss.css\\");", +} +`; + +exports[`SassProcessor JS shim files named exports (commonjs) forwards named exports for composed.module.scss without changing CSS or source maps: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor JS shim files named exports (commonjs) forwards named exports for composed.module.scss without changing CSS or source maps: written-files 1`] = ` +Map { + "/fake/output/dts/composed.module.scss.d.ts" => "declare const id1: string; +export { id1 as themeColor }; +declare const id2: string; +export { id2 as \\"theme-color\\" }; +declare const id3: string; +export { id3 as base_style }; +declare const id4: string; +export { id4 as \\"base-style\\" }; +declare const id5: string; +export { id5 as composedStyle }; +declare const id6: string; +export { id6 as id0 };", + "/fake/output/css/composed.module.scss.css" => ".base_style { + color: red; +} + +.base-style { + composes: base_style; +} + +.composedStyle { + composes: base-style; + color: blue; +} + +.id0 { + color: green; +} + +:export { + themeColor: purple; + theme-color: purple; +} +/*# sourceMappingURL=composed.module.scss.css.map */ +", + "/fake/output/css/composed.module.scss.css.map" => "{\\"version\\":3,\\"sourceRoot\\":\\"\\",\\"sources\\":[\\"fixtures/composed.module.scss\\"],\\"names\\":[],\\"mappings\\":\\"AAGA;EACE;;;AAGF;EACE;;;AAGF;EACE;EACA;;;AAGF;EACE;;;AAGF;EACE;EACA\\",\\"sourcesContent\\":[\\"// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\\\\n// See LICENSE in the project root for license information.\\\\n\\\\n.base_style {\\\\n color: red;\\\\n}\\\\n\\\\n.base-style {\\\\n composes: base_style;\\\\n}\\\\n\\\\n.composedStyle {\\\\n composes: base-style;\\\\n color: blue;\\\\n}\\\\n\\\\n.id0 {\\\\n color: green;\\\\n}\\\\n\\\\n:export {\\\\n themeColor: purple;\\\\n theme-color: purple;\\\\n}\\\\n\\"],\\"file\\":\\"composed.module.scss.css\\"}", + "/fake/output/css/composed.module.scss.js" => "module.exports = require(\\"./composed.module.scss.css\\");", +} +`; + +exports[`SassProcessor JS shim files named exports (commonjs) forwards named exports for export-only.module.scss without changing CSS or source maps: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor JS shim files named exports (commonjs) forwards named exports for export-only.module.scss without changing CSS or source maps: written-files 1`] = ` +Map { + "/fake/output/dts/export-only.module.scss.d.ts" => "declare const id0: string; +export { id0 as primaryColor }; +declare const id1: string; +export { id1 as fontFamily };", + "/fake/output/css/export-only.module.scss.css" => ":export { + primaryColor: #0078d4; + fontFamily: \\"Segoe UI\\"; +} +/*# sourceMappingURL=export-only.module.scss.css.map */ +", + "/fake/output/css/export-only.module.scss.css.map" => "{\\"version\\":3,\\"sourceRoot\\":\\"\\",\\"sources\\":[\\"fixtures/export-only.module.scss\\"],\\"names\\":[],\\"mappings\\":\\"AAEA;EACE;EACA\\",\\"sourcesContent\\":[\\"// A CSS module that only exports ICSS values - no class names.\\\\n// Used to verify that the :export block is preserved or stripped based on preserveIcssExports.\\\\n:export {\\\\n primaryColor: #0078d4;\\\\n fontFamily: 'Segoe UI';\\\\n}\\\\n\\"],\\"file\\":\\"export-only.module.scss.css\\"}", + "/fake/output/css/export-only.module.scss.js" => "module.exports = require(\\"./export-only.module.scss.css\\");", +} +`; + +exports[`SassProcessor JS shim files named exports (commonjs) forwards named exports for loader-reserved.module.scss without changing CSS or source maps: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor JS shim files named exports (commonjs) forwards named exports for loader-reserved.module.scss without changing CSS or source maps: written-files 1`] = ` +Map { + "/fake/output/dts/loader-reserved.module.scss.d.ts" => "declare const id0: string; +export { id0 as class }; +declare const id1: string; +export { id1 as function }; +declare const id2: string; +export { id2 as for }; +declare const id3: string; +export { id3 as enum }; +declare const id4: string; +export { id4 as true }; +declare const id5: string; +export { id5 as _default };", + "/fake/output/css/loader-reserved.module.scss.css" => ".class, +.function, +.for, +.enum, +.true, +.default { + color: red; +} +/*# sourceMappingURL=loader-reserved.module.scss.css.map */ +", + "/fake/output/css/loader-reserved.module.scss.css.map" => "{\\"version\\":3,\\"sourceRoot\\":\\"\\",\\"sources\\":[\\"fixtures/loader-reserved.module.scss\\"],\\"names\\":[],\\"mappings\\":\\"AAGA;AAAA;AAAA;AAAA;AAAA;AAAA;EAME\\",\\"sourcesContent\\":[\\"// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\\\\n// See LICENSE in the project root for license information.\\\\n\\\\n.class,\\\\n.function,\\\\n.for,\\\\n.enum,\\\\n.true,\\\\n.default {\\\\n color: red;\\\\n}\\\\n\\"],\\"file\\":\\"loader-reserved.module.scss.css\\"}", + "/fake/output/css/loader-reserved.module.scss.js" => "module.exports = require(\\"./loader-reserved.module.scss.css\\");", +} +`; + +exports[`SassProcessor JS shim files named exports (commonjs) forwards named exports for simple.module.sass without changing CSS or source maps: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor JS shim files named exports (commonjs) forwards named exports for simple.module.sass without changing CSS or source maps: written-files 1`] = ` +Map { + "/fake/output/dts/simple.module.sass.d.ts" => "declare const id0: string; +export { id0 as exampleClass }; +declare const id1: string; +export { id1 as exampleHeading };", + "/fake/output/css/simple.module.sass.css" => ".exampleClass { + color: red; + font-size: 14px; +} + +.exampleHeading { + font-weight: bold; + color: navy; +} +/*# sourceMappingURL=simple.module.sass.css.map */ +", + "/fake/output/css/simple.module.sass.css.map" => "{\\"version\\":3,\\"sourceRoot\\":\\"\\",\\"sources\\":[\\"fixtures/simple.module.sass\\"],\\"names\\":[],\\"mappings\\":\\"AAEA;EACE;EACA;;;AAEF;EACE;EACA\\",\\"sourcesContent\\":[\\"// Indented Sass syntax (whitespace-significant, no braces).\\\\n// Used to verify that .sass files are parsed with the indented syntax.\\\\n.exampleClass\\\\n color: red\\\\n font-size: 14px\\\\n\\\\n.exampleHeading\\\\n font-weight: bold\\\\n color: navy\\\\n\\"],\\"file\\":\\"simple.module.sass.css\\"}", + "/fake/output/css/simple.module.sass.js" => "module.exports = require(\\"./simple.module.sass.css\\");", +} +`; + +exports[`SassProcessor JS shim files named exports (commonjs) keeps empty.module.scss side-effect-only: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor JS shim files named exports (commonjs) keeps empty.module.scss side-effect-only: written-files 1`] = ` +Map { + "/fake/output/dts/empty.module.scss.d.ts" => "export {};", + "/fake/output/css/empty.module.css" => "", + "/fake/output/css/empty.module.scss.js" => "require(\\"./empty.module.css\\");", +} +`; + +exports[`SassProcessor JS shim files named exports (commonjs) keeps global-only.module.scss side-effect-only: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor JS shim files named exports (commonjs) keeps global-only.module.scss side-effect-only: written-files 1`] = ` +Map { + "/fake/output/dts/global-only.module.scss.d.ts" => "export {};", + "/fake/output/css/global-only.module.css" => ".ms-Nav-group { + overflow: hidden; +} +.ms-Nav-link { + height: 30px; +}", + "/fake/output/css/global-only.module.scss.js" => "require(\\"./global-only.module.css\\");", +} +`; + +exports[`SassProcessor JS shim files named exports (commonjs) keeps global-styles.global.scss side-effect-only: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor JS shim files named exports (commonjs) keeps global-styles.global.scss side-effect-only: written-files 1`] = ` +Map { + "/fake/output/dts/global-styles.global.scss.d.ts" => "export {};", + "/fake/output/css/global-styles.global.css" => "body { + margin: 0; + padding: 0; + font-family: \\"Segoe UI\\", sans-serif; +} + +h1 { + font-size: 24px; + color: #333; +}", + "/fake/output/css/global-styles.global.scss.js" => "require(\\"./global-styles.global.css\\");", +} +`; + +exports[`SassProcessor JS shim files named exports (esnext) forwards named exports for classes-and-exports.module.scss without changing CSS or source maps: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor JS shim files named exports (esnext) forwards named exports for classes-and-exports.module.scss without changing CSS or source maps: written-files 1`] = ` +Map { + "/fake/output/dts/classes-and-exports.module.scss.d.ts" => "declare const id0: string; +export { id0 as themeColor }; +declare const id1: string; +export { id1 as spacing }; +declare const id2: string; +export { id2 as root }; +declare const id3: string; +export { id3 as highlighted };", + "/fake/output/css/classes-and-exports.module.scss.css" => ".root { + color: red; + font-size: 14px; +} + +.highlighted { + background-color: yellow; +} + +:export { + themeColor: blue; + spacing: 8px; +} +/*# sourceMappingURL=classes-and-exports.module.scss.css.map */ +", + "/fake/output/css/classes-and-exports.module.scss.css.map" => "{\\"version\\":3,\\"sourceRoot\\":\\"\\",\\"sources\\":[\\"fixtures/classes-and-exports.module.scss\\"],\\"names\\":[],\\"mappings\\":\\"AACA;EACE;EACA;;;AAGF;EACE;;;AAGF;EACE;EACA\\",\\"sourcesContent\\":[\\"// A CSS module that exports both class names and ICSS :export values.\\\\n.root {\\\\n color: red;\\\\n font-size: 14px;\\\\n}\\\\n\\\\n.highlighted {\\\\n background-color: yellow;\\\\n}\\\\n\\\\n:export {\\\\n themeColor: blue;\\\\n spacing: 8px;\\\\n}\\\\n\\"],\\"file\\":\\"classes-and-exports.module.scss.css\\"}", + "/fake/output/css/classes-and-exports.module.scss.js" => "export * from \\"./classes-and-exports.module.scss.css\\";", +} +`; + +exports[`SassProcessor JS shim files named exports (esnext) forwards named exports for composed.module.scss without changing CSS or source maps: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor JS shim files named exports (esnext) forwards named exports for composed.module.scss without changing CSS or source maps: written-files 1`] = ` +Map { + "/fake/output/dts/composed.module.scss.d.ts" => "declare const id1: string; +export { id1 as themeColor }; +declare const id2: string; +export { id2 as \\"theme-color\\" }; +declare const id3: string; +export { id3 as base_style }; +declare const id4: string; +export { id4 as \\"base-style\\" }; +declare const id5: string; +export { id5 as composedStyle }; +declare const id6: string; +export { id6 as id0 };", + "/fake/output/css/composed.module.scss.css" => ".base_style { + color: red; +} + +.base-style { + composes: base_style; +} + +.composedStyle { + composes: base-style; + color: blue; +} + +.id0 { + color: green; +} + +:export { + themeColor: purple; + theme-color: purple; +} +/*# sourceMappingURL=composed.module.scss.css.map */ +", + "/fake/output/css/composed.module.scss.css.map" => "{\\"version\\":3,\\"sourceRoot\\":\\"\\",\\"sources\\":[\\"fixtures/composed.module.scss\\"],\\"names\\":[],\\"mappings\\":\\"AAGA;EACE;;;AAGF;EACE;;;AAGF;EACE;EACA;;;AAGF;EACE;;;AAGF;EACE;EACA\\",\\"sourcesContent\\":[\\"// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\\\\n// See LICENSE in the project root for license information.\\\\n\\\\n.base_style {\\\\n color: red;\\\\n}\\\\n\\\\n.base-style {\\\\n composes: base_style;\\\\n}\\\\n\\\\n.composedStyle {\\\\n composes: base-style;\\\\n color: blue;\\\\n}\\\\n\\\\n.id0 {\\\\n color: green;\\\\n}\\\\n\\\\n:export {\\\\n themeColor: purple;\\\\n theme-color: purple;\\\\n}\\\\n\\"],\\"file\\":\\"composed.module.scss.css\\"}", + "/fake/output/css/composed.module.scss.js" => "export * from \\"./composed.module.scss.css\\";", +} +`; + +exports[`SassProcessor JS shim files named exports (esnext) forwards named exports for export-only.module.scss without changing CSS or source maps: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor JS shim files named exports (esnext) forwards named exports for export-only.module.scss without changing CSS or source maps: written-files 1`] = ` +Map { + "/fake/output/dts/export-only.module.scss.d.ts" => "declare const id0: string; +export { id0 as primaryColor }; +declare const id1: string; +export { id1 as fontFamily };", + "/fake/output/css/export-only.module.scss.css" => ":export { + primaryColor: #0078d4; + fontFamily: \\"Segoe UI\\"; +} +/*# sourceMappingURL=export-only.module.scss.css.map */ +", + "/fake/output/css/export-only.module.scss.css.map" => "{\\"version\\":3,\\"sourceRoot\\":\\"\\",\\"sources\\":[\\"fixtures/export-only.module.scss\\"],\\"names\\":[],\\"mappings\\":\\"AAEA;EACE;EACA\\",\\"sourcesContent\\":[\\"// A CSS module that only exports ICSS values - no class names.\\\\n// Used to verify that the :export block is preserved or stripped based on preserveIcssExports.\\\\n:export {\\\\n primaryColor: #0078d4;\\\\n fontFamily: 'Segoe UI';\\\\n}\\\\n\\"],\\"file\\":\\"export-only.module.scss.css\\"}", + "/fake/output/css/export-only.module.scss.js" => "export * from \\"./export-only.module.scss.css\\";", +} +`; + +exports[`SassProcessor JS shim files named exports (esnext) forwards named exports for loader-reserved.module.scss without changing CSS or source maps: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor JS shim files named exports (esnext) forwards named exports for loader-reserved.module.scss without changing CSS or source maps: written-files 1`] = ` +Map { + "/fake/output/dts/loader-reserved.module.scss.d.ts" => "declare const id0: string; +export { id0 as class }; +declare const id1: string; +export { id1 as function }; +declare const id2: string; +export { id2 as for }; +declare const id3: string; +export { id3 as enum }; +declare const id4: string; +export { id4 as true }; +declare const id5: string; +export { id5 as _default };", + "/fake/output/css/loader-reserved.module.scss.css" => ".class, +.function, +.for, +.enum, +.true, +.default { + color: red; +} +/*# sourceMappingURL=loader-reserved.module.scss.css.map */ +", + "/fake/output/css/loader-reserved.module.scss.css.map" => "{\\"version\\":3,\\"sourceRoot\\":\\"\\",\\"sources\\":[\\"fixtures/loader-reserved.module.scss\\"],\\"names\\":[],\\"mappings\\":\\"AAGA;AAAA;AAAA;AAAA;AAAA;AAAA;EAME\\",\\"sourcesContent\\":[\\"// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\\\\n// See LICENSE in the project root for license information.\\\\n\\\\n.class,\\\\n.function,\\\\n.for,\\\\n.enum,\\\\n.true,\\\\n.default {\\\\n color: red;\\\\n}\\\\n\\"],\\"file\\":\\"loader-reserved.module.scss.css\\"}", + "/fake/output/css/loader-reserved.module.scss.js" => "export * from \\"./loader-reserved.module.scss.css\\";", +} +`; + +exports[`SassProcessor JS shim files named exports (esnext) forwards named exports for simple.module.sass without changing CSS or source maps: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor JS shim files named exports (esnext) forwards named exports for simple.module.sass without changing CSS or source maps: written-files 1`] = ` +Map { + "/fake/output/dts/simple.module.sass.d.ts" => "declare const id0: string; +export { id0 as exampleClass }; +declare const id1: string; +export { id1 as exampleHeading };", + "/fake/output/css/simple.module.sass.css" => ".exampleClass { + color: red; + font-size: 14px; +} + +.exampleHeading { + font-weight: bold; + color: navy; +} +/*# sourceMappingURL=simple.module.sass.css.map */ +", + "/fake/output/css/simple.module.sass.css.map" => "{\\"version\\":3,\\"sourceRoot\\":\\"\\",\\"sources\\":[\\"fixtures/simple.module.sass\\"],\\"names\\":[],\\"mappings\\":\\"AAEA;EACE;EACA;;;AAEF;EACE;EACA\\",\\"sourcesContent\\":[\\"// Indented Sass syntax (whitespace-significant, no braces).\\\\n// Used to verify that .sass files are parsed with the indented syntax.\\\\n.exampleClass\\\\n color: red\\\\n font-size: 14px\\\\n\\\\n.exampleHeading\\\\n font-weight: bold\\\\n color: navy\\\\n\\"],\\"file\\":\\"simple.module.sass.css\\"}", + "/fake/output/css/simple.module.sass.js" => "export * from \\"./simple.module.sass.css\\";", +} +`; + +exports[`SassProcessor JS shim files named exports (esnext) keeps empty.module.scss side-effect-only: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor JS shim files named exports (esnext) keeps empty.module.scss side-effect-only: written-files 1`] = ` +Map { + "/fake/output/dts/empty.module.scss.d.ts" => "export {};", + "/fake/output/css/empty.module.css" => "", + "/fake/output/css/empty.module.scss.js" => "import \\"./empty.module.css\\";export {};", +} +`; + +exports[`SassProcessor JS shim files named exports (esnext) keeps global-only.module.scss side-effect-only: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor JS shim files named exports (esnext) keeps global-only.module.scss side-effect-only: written-files 1`] = ` +Map { + "/fake/output/dts/global-only.module.scss.d.ts" => "export {};", + "/fake/output/css/global-only.module.css" => ".ms-Nav-group { + overflow: hidden; +} +.ms-Nav-link { + height: 30px; +}", + "/fake/output/css/global-only.module.scss.js" => "import \\"./global-only.module.css\\";export {};", +} +`; + +exports[`SassProcessor JS shim files named exports (esnext) keeps global-styles.global.scss side-effect-only: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor JS shim files named exports (esnext) keeps global-styles.global.scss side-effect-only: written-files 1`] = ` +Map { + "/fake/output/dts/global-styles.global.scss.d.ts" => "export {};", + "/fake/output/css/global-styles.global.css" => "body { + margin: 0; + padding: 0; + font-family: \\"Segoe UI\\", sans-serif; +} + +h1 { + font-size: 24px; + color: #333; +}", + "/fake/output/css/global-styles.global.scss.js" => "import \\"./global-styles.global.css\\";export {};", +} +`; + +exports[`SassProcessor JS shim files preserves both default and _default class names in default mode: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor JS shim files preserves both default and _default class names in default mode: written-files 1`] = ` +Map { + "/fake/output/dts/default-collision.module.scss.d.ts" => "declare interface IStyles { + default: string; + _default: string; +} +declare const styles: IStyles; +export default styles;", + "/fake/output/css/default-collision.module.css" => ".default { + color: red; +} + +._default { + color: blue; +}", +} +`; + +exports[`SassProcessor JS shim files reports the loader default-name collision in named mode: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor JS shim files reports the loader default-name collision in named mode: written-files 1`] = `Map {}`; + +exports[`SassProcessor JS shim files uses collision-free quoted export aliases for non-identifier class names and ICSS exports: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor JS shim files uses collision-free quoted export aliases for non-identifier class names and ICSS exports: written-files 1`] = ` +Map { + "/fake/output/dts/composed.module.scss.d.ts" => "declare const id1: string; +export { id1 as themeColor }; +declare const id2: string; +export { id2 as \\"theme-color\\" }; +declare const id3: string; +export { id3 as base_style }; +declare const id4: string; +export { id4 as \\"base-style\\" }; +declare const id5: string; +export { id5 as composedStyle }; +declare const id6: string; +export { id6 as id0 };", + "/fake/output/css/composed.module.css" => ".base_style { + color: red; +} + +.base-style { +} + +.composedStyle { + color: blue; +} + +.id0 { + color: green; +}", +} +`; + +exports[`SassProcessor JS shim files uses private bindings for reserved names and matches the loader default-class convention: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor JS shim files uses private bindings for reserved names and matches the loader default-class convention: written-files 1`] = ` +Map { + "/fake/output/dts/reserved.module.scss.d.ts" => "declare const id1: string; +export { id1 as class }; +declare const id2: string; +export { id2 as function }; +declare const id3: string; +export { id3 as for }; +declare const id4: string; +export { id4 as return }; +declare const id5: string; +export { id5 as enum }; +declare const id6: string; +export { id6 as implements }; +declare const id7: string; +export { id7 as interface }; +declare const id8: string; +export { id8 as private }; +declare const id9: string; +export { id9 as protected }; +declare const id10: string; +export { id10 as public }; +declare const id11: string; +export { id11 as static }; +declare const id12: string; +export { id12 as let }; +declare const id13: string; +export { id13 as yield }; +declare const id14: string; +export { id14 as await }; +declare const id15: string; +export { id15 as eval }; +declare const id16: string; +export { id16 as arguments }; +declare const id17: string; +export { id17 as true }; +declare const id18: string; +export { id18 as false }; +declare const id19: string; +export { id19 as null }; +declare const id20: string; +export { id20 as _default }; +declare const id21: string; +export { id21 as id0 };", + "/fake/output/css/reserved.module.css" => ".class, +.function, +.for, +.return, +.enum, +.implements, +.interface, +.private, +.protected, +.public, +.static, +.let, +.yield, +.await, +.eval, +.arguments, +.true, +.false, +.null, +.default, +.id0 { + color: red; +}", +} +`; + exports[`SassProcessor JS shim files writes shims to each configured cssOutputFolder independently: terminal-output 1`] = ` Array [ "[verbose] Checking for changes to 1 files...[n]", @@ -309,10 +1004,22 @@ Array [ exports[`SassProcessor classes-and-exports.module.scss generates named exports in .d.ts when exportAsDefault is false: written-files 1`] = ` Map { - "/fake/output/dts/classes-and-exports.module.scss.d.ts" => "export const themeColor: string; -export const spacing: string; -export const root: string; -export const highlighted: string;", + "/fake/output/dts/classes-and-exports.module.scss.d.ts" => "declare const id0: string; +export { id0 as themeColor }; +declare const id1: string; +export { id1 as spacing }; +declare const id2: string; +export { id2 as root }; +declare const id3: string; +export { id3 as highlighted };", + "/fake/output/css/classes-and-exports.module.css" => ".root { + color: red; + font-size: 14px; +} + +.highlighted { + background-color: yellow; +}", } `; diff --git a/heft-plugins/heft-sass-plugin/src/test/fixtures/composed.module.scss b/heft-plugins/heft-sass-plugin/src/test/fixtures/composed.module.scss new file mode 100644 index 00000000000..ad2dc76bf73 --- /dev/null +++ b/heft-plugins/heft-sass-plugin/src/test/fixtures/composed.module.scss @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +.base_style { + color: red; +} + +.base-style { + composes: base_style; +} + +.composedStyle { + composes: base-style; + color: blue; +} + +.id0 { + color: green; +} + +:export { + themeColor: purple; + theme-color: purple; +} diff --git a/heft-plugins/heft-sass-plugin/src/test/fixtures/default-collision.module.scss b/heft-plugins/heft-sass-plugin/src/test/fixtures/default-collision.module.scss new file mode 100644 index 00000000000..dc4bbccebe6 --- /dev/null +++ b/heft-plugins/heft-sass-plugin/src/test/fixtures/default-collision.module.scss @@ -0,0 +1,10 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +.default { + color: red; +} + +._default { + color: blue; +} diff --git a/heft-plugins/heft-sass-plugin/src/test/fixtures/empty.module.scss b/heft-plugins/heft-sass-plugin/src/test/fixtures/empty.module.scss new file mode 100644 index 00000000000..b2d2e4d1b84 --- /dev/null +++ b/heft-plugins/heft-sass-plugin/src/test/fixtures/empty.module.scss @@ -0,0 +1,2 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. diff --git a/heft-plugins/heft-sass-plugin/src/test/fixtures/loader-reserved.module.scss b/heft-plugins/heft-sass-plugin/src/test/fixtures/loader-reserved.module.scss new file mode 100644 index 00000000000..7f9928c4d46 --- /dev/null +++ b/heft-plugins/heft-sass-plugin/src/test/fixtures/loader-reserved.module.scss @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +.class, +.function, +.for, +.enum, +.true, +.default { + color: red; +} diff --git a/heft-plugins/heft-sass-plugin/src/test/fixtures/reserved.module.scss b/heft-plugins/heft-sass-plugin/src/test/fixtures/reserved.module.scss new file mode 100644 index 00000000000..bf41a73144a --- /dev/null +++ b/heft-plugins/heft-sass-plugin/src/test/fixtures/reserved.module.scss @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +.class, +.function, +.for, +.return, +.enum, +.implements, +.interface, +.private, +.protected, +.public, +.static, +.let, +.yield, +.await, +.eval, +.arguments, +.true, +.false, +.null, +.default, +.id0 { + color: red; +}