Skip to content
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
4 changes: 2 additions & 2 deletions apps/rush-mcp-server/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# @rushstack/mcp-server

With the rapid advancement of LLMs, AI applications like Trae, Cursor, Cline, Windsurf, and others have been thriving. However, due to the large scale of monorepos and the context limitations of LLMs, it’s difficult for these models to fully understand your monorepo. This is where @rushstack/mcp-server comes in by providing a suite of MCP tools, it enables LLMs to better comprehend your monorepo and assist you more effectively with daily development tasks in a Rush-based monorepo environment.
With the rapid advancement of LLMs, AI applications like Trae, Cursor, Cline, Windsurf, and others have been thriving. However, due to the large scale of monorepos and the context limitations of LLMs, it’s difficult for these models to fully understand your monorepo. This is where @rushstack/mcp-server comes in - by providing a suite of MCP tools, it enables LLMs to better comprehend your monorepo and assist you more effectively with daily development tasks in a Rush-based monorepo environment.

## Usage

Expand All @@ -19,7 +19,7 @@ With the rapid advancement of LLMs, AI applications like Trae, Cursor, Cline, Wi
}
```

3. Congratulations 🎉 You’ve completed the setup Rush MCP is now ready to use!
3. Congratulations 🎉 You’ve completed the setup - Rush MCP is now ready to use!

## Available Tools

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@microsoft/rush",
"comment": "",
"type": "none"
}
],
"packageName": "@microsoft/rush"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@rushstack/eslint-plugin",
"comment": "",
"type": "none"
}
],
"packageName": "@rushstack/eslint-plugin"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@rushstack/heft-config-file",
"comment": "",
"type": "none"
}
],
"packageName": "@rushstack/heft-config-file"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@rushstack/heft-json-schema-typings-plugin",
"comment": "",
"type": "none"
}
],
"packageName": "@rushstack/heft-json-schema-typings-plugin"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@rushstack/heft-sass-plugin",
"comment": "Improve project README.",
"type": "patch"
}
],
"packageName": "@rushstack/heft-sass-plugin"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@rushstack/heft-static-asset-typings-plugin",
"comment": "",
"type": "none"
}
],
"packageName": "@rushstack/heft-static-asset-typings-plugin"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@rushstack/mcp-server",
"comment": "",
"type": "none"
}
],
"packageName": "@rushstack/mcp-server"
}
6 changes: 3 additions & 3 deletions eslint/eslint-plugin/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ import(
#### Notes

- If your bundler does not understand Webpack magic comments (e.g. plain Node ESM loader), disable this rule for that project.
- Choose stable, descriptive chunk namesavoid including hashes, timestamps, or environment‑specific tokens.
- Choose stable, descriptive chunk names-avoid including hashes, timestamps, or environment‑specific tokens.
- Chunk names share a global namespace in the final bundle; avoid collisions to keep analysis clear.

#### Rationale
Expand Down Expand Up @@ -531,14 +531,14 @@ unmountComponentAtNode(b);

```ts
// No legacy ReactDOM render/unmount usage in this file
// (e.g. uses React 18 createRoot API or just defines components) rule passes
// (e.g. uses React 18 createRoot API or just defines components) - rule passes
```

#### Notes

- The rule does not attempt dataflow analysis to verify the same container node is passed; it only enforces count parity.
- Modern React apps using `createRoot()` should migrate to pairing `root.unmount()`. This legacy rule helps older code until migration is complete.
- Multiple files can coordinate unmounting (e.g. via a shared cleanup utility); in that case this rule will flag the imbalanceconsider colocating the unmount or disabling the rule for that file.
- Multiple files can coordinate unmounting (e.g. via a shared cleanup utility); in that case this rule will flag the imbalance-consider colocating the unmount or disabling the rule for that file.

#### Rationale

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Stub for prettier. json-schema-to-typescript eagerly require('prettier') at
// module load time. Prettier v3's CJS entry does a top-level dynamic import()
// which crashes inside Jest's VM sandbox on Node 22+. Since compile() is called
// with format: false, prettier is never invoked this stub just prevents the
// with format: false, prettier is never invoked - this stub just prevents the
// module-load crash.
module.exports = {};
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export const X_TSDOC_RELEASE_TAG_KEY: 'x-tsdoc-release-tag' = 'x-tsdoc-release-t
const RELEASE_TAG_PATTERN: RegExp = /^@[a-z]+$/;

/**
* Validates that a string looks like a TSDoc release tag a single lowercase
* Validates that a string looks like a TSDoc release tag - a single lowercase
* word starting with `@` (e.g. `@public`, `@beta`, `@internal`).
*/
export function _validateTsDocReleaseTag(value: string, schemaPath: string): void {
Expand Down
242 changes: 237 additions & 5 deletions heft-plugins/heft-sass-plugin/README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,244 @@
# @rushstack/heft-sass-plugin

This is a Heft plugin for using sass-embedded during the "build" stage.
If `sass-embedded` is not supported on your platform, you can override the dependency via npm alias to use the `sass` package instead.
A [Heft](https://heft.rushstack.io/) plugin that compiles SCSS/Sass files during the build phase. It uses [`sass-embedded`](https://www.npmjs.com/package/sass-embedded) under the hood and produces:

- **TypeScript type definitions** (`.d.ts`) for CSS modules, giving you typed access to class names and `:export` values
- **Compiled CSS files** (optional) in one or more output folders
- **JavaScript shims** (optional) that re-export the CSS for consumption in CommonJS or ESM environments

> If `sass-embedded` is not supported on your platform, you can substitute it with the [`sass`](https://www.npmjs.com/package/sass) package using an npm alias.

## Links

- [CHANGELOG.md](
https://github.com/microsoft/rushstack/blob/main/heft-plugins/heft-sass-plugin/CHANGELOG.md) - Find
out what's new in the latest version
- [CHANGELOG.md](https://github.com/microsoft/rushstack/blob/main/heft-plugins/heft-sass-plugin/CHANGELOG.md) - Find out what's new in the latest version

Heft is part of the [Rush Stack](https://rushstack.io/) family of projects.

---

## Setup

### 1. Add the plugin to your project

In your project's `package.json`:

```json
{
"devDependencies": {
"@rushstack/heft": "...",
"@rushstack/heft-sass-plugin": "..."
}
}
```

### 2. Register the plugin in `config/heft.json`

The `sass` task must run before `typescript` so that the generated `.d.ts` files are available when TypeScript compiles your project.

```json
{
"$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json",
"phasesByName": {
"build": {
"tasksByName": {
"sass": {
"taskPlugin": {
"pluginPackage": "@rushstack/heft-sass-plugin"
}
},

"typescript": {
"taskDependencies": ["sass"],
"taskPlugin": {
"pluginPackage": "@rushstack/heft-typescript-plugin"
}
}
}
}
}
}
```

### 3. Create `config/sass.json`

A minimal config uses all defaults:

```json
{
"$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft-sass-plugin.schema.json"
}
```

A more complete setup that emits CSS and shims for both ESM and CommonJS:

```json
{
"$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft-sass-plugin.schema.json",
"cssOutputFolders": [
{ "folder": "lib-esm", "shimModuleFormat": "esnext" },
{ "folder": "lib-commonjs", "shimModuleFormat": "commonjs" }
],
"fileExtensions": [".module.scss", ".module.sass"],
"nonModuleFileExtensions": [".global.scss", ".global.sass"],
"silenceDeprecations": ["mixed-decls", "import", "global-builtin", "color-functions"]
}
```

### 4. Add generated files to `tsconfig.json`

Point TypeScript at the generated type definitions by including the `generatedTsFolder` in your `tsconfig.json`:

```json
{
"compilerOptions": {
"paths": {}
},
"include": ["src", "temp/sass-ts"]
}
```

## CSS Modules vs. global stylesheets

The plugin distinguishes between two kinds of files based on their extension:

**CSS modules** (extensions listed in `fileExtensions`, default: `.sass`, `.scss`, `.css`):
- Processed with [`postcss-modules`](https://www.npmjs.com/package/postcss-modules)
- Class names and `:export` values become properties in a generated TypeScript interface
- The generated `.d.ts` exports a typed `styles` object as its default export

**Global stylesheets** (extensions listed in `nonModuleFileExtensions`, default: `.global.sass`, `.global.scss`, `.global.css`):
- Compiled to plain CSS with no module scoping
- The generated `.d.ts` is a side-effect-only module (`export {}`)
- Useful for resets, themes, and base styles

**Partials** (filenames starting with `_`):
- Never compiled to output files; they are only meant to be `@use`d or `@forward`ed by other files

### Example: CSS module

```scss
// src/Button.module.scss
.root {
background: blue;
}
.label {
font-size: 14px;
}
:export {
brandColor: #0078d4;
}
```

Generated `temp/sass-ts/Button.module.scss.d.ts`:

```typescript
interface IStyles {
root: string;
label: string;
brandColor: string;
}
declare const styles: IStyles;
export default styles;
```

In your TypeScript source:

```typescript
import styles from './Button.module.scss';
// styles.root, styles.label, styles.brandColor are all typed strings
```

## Configuration reference

All options are set in `config/sass.json`. Every option is optional.

| Option | Default | Description |
|---|---|---|
| `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`. |
| `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 |
| `excludeFiles` | `[]` | Paths relative to `srcFolder` to skip entirely |
| `doNotTrimOriginalFileExtension` | `false` | When `true`, preserves the original extension in the CSS output filename. E.g. `styles.scss` → `styles.scss.css` instead of `styles.css`. Useful when downstream tooling needs to distinguish the source format. |
| `preserveIcssExports` | `false` | When `true`, keeps the `:export { }` block in the emitted CSS. This is needed when a webpack loader (e.g. `css-loader`'s `icssParser`) must extract `:export` values at bundle time. Has no effect on the generated `.d.ts`. |
| `silenceDeprecations` | `[]` | List of Sass deprecation codes to suppress (e.g. `"mixed-decls"`, `"import"`, `"global-builtin"`, `"color-functions"`) |
| `ignoreDeprecationsInDependencies` | `false` | Suppresses deprecation warnings that originate from `node_modules` dependencies |
| `extends` | _(none)_ | Path to another `sass.json` config file to inherit settings from |

### CSS output folders and JS shims

Each entry in `cssOutputFolders` can be a plain string (folder path only) or an object:

```json
{
"folder": "lib-esm",
"shimModuleFormat": "esnext"
}
```

When `shimModuleFormat` is set, the plugin writes a `.js` shim alongside each `.css` file. For a CSS module, the shim re-exports the CSS:

```js
// ESM shim (shimModuleFormat: "esnext")
export { default } from "./Button.module.css";

// CommonJS shim (shimModuleFormat: "commonjs")
module.exports = require("./Button.module.css");
module.exports.default = module.exports;
```

For a global stylesheet, the shim is a side-effect-only import:

```js
// ESM shim
import "./global.global.css";
export {};

// CommonJS shim
require("./global.global.css");
```

## Sass import resolution

The plugin supports the modern `pkg:` protocol for importing from npm packages:

```scss
@use "pkg:@fluentui/react/dist/sass/variables";
```

The legacy `~` prefix is automatically converted to `pkg:` for compatibility with older stylesheets:

```scss
// These are equivalent:
@use "~@fluentui/react/dist/sass/variables";
@use "pkg:@fluentui/react/dist/sass/variables";
```

## Incremental builds

The plugin tracks inter-file dependencies (via `@use`, `@forward`, and `@import`) and only recompiles files that changed or whose dependencies changed. This makes `heft build --watch` fast even in large projects.

## Plugin accessor API

Other Heft plugins can hook into the Sass compilation pipeline via the `ISassPluginAccessor` interface:

```typescript
import { ISassPluginAccessor } from '@rushstack/heft-sass-plugin';

// In your plugin's apply() method:
const sassAccessor = session.requestAccessToPlugin<ISassPluginAccessor>(
'@rushstack/heft-sass-plugin',
'sass-plugin',
'@rushstack/heft-sass-plugin'
);

sassAccessor.hooks.postProcessCss.tapPromise('my-plugin', async (css, filePath) => {
// Transform CSS after Sass compilation but before it is written to cssOutputFolders
return transformedCss;
});
```

The `postProcessCss` hook is an `AsyncSeriesWaterfallHook` that passes the compiled CSS string and source file path through each tap in sequence.
Loading