rsnext/packages/eslint-plugin-next/lib/utils/get-root-dirs.js
Brody McKee 4cd45aabcf
Add rootDir setting to eslint-plugin-next (#27918)
## Introduction

This PR enables setting a `rootDir` for a Next.js project, and follows the same pattern used by [`@typescript-eslint/parser`](https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/parser#parseroptionsproject).

## Details

Previously, users had to pass paths to the rule itself.
```js
module.exports = {
  rules: { 
    "@next/next/no-html-link-for-pages": [
      "error",
      // This could be a string, or array of strings.
      "/packages/my-app/pages",
    ],
  },
};
```

With this PR, this has been simplified (the previous implementation still works as expected).
```js
module.exports = {
  settings: { 
    next: {
      rootDir: "/packages/my-app",
    },
  },
  rules: { 
    "@next/next/no-html-link-for-pages": "error",
  },
};
```

Further, this rule allows the use of globs, again aligning with `@typescript-eslint/parser`.
```js
module.exports = {
  settings: { 
    next: {
      // Globs
      rootDir: "/packages/*",
      rootDir: "/packages/{app-a,app-b}",

      // Arrays
      rootDir: ["/app-a", "/app-b"],
      
      // Arrays with globs
      rootDir: ["/main-app", "/other-apps/*"],
  },
};
```

This enables users to either provide per-workspace configuration with overrides, or to use globs for situations like monorepos where the apps share a domain (micro-frontends).

This doesn't solve, but improves https://github.com/vercel/next.js/issues/26330.

## Feature

- [x] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR.
- [x] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [ ] Documentation added
- [ ] Telemetry added. In case of a feature if it's used or not.
- [ ] Errors have helpful link attached, see `contributing.md`

## Documentation / Examples

- [x] Make sure the linting passes
2021-08-11 10:37:55 +00:00

40 lines
1,011 B
JavaScript

// @ts-check
const glob = require('glob')
/**
* Process a Next.js root directory glob.
*
* @param {string} rootDir - A Next.js root directory glob.
* @returns {string[]} - An array of Root directories.
*/
const processRootDir = (rootDir) => {
// Ensures we only match folders.
if (!rootDir.endsWith('/')) rootDir += '/'
return glob.sync(rootDir)
}
/**
* Gets one or more Root
*
* @param {import('eslint').Rule.RuleContext} context - ESLint rule context
* @returns An array of root directories.
*/
const getRootDirs = (context) => {
let rootDirs = [context.getCwd()]
/** @type {{rootDir?:string|string[]}|undefined} */
const nextSettings = context.settings.next || {}
let rootDir = nextSettings.rootDir
if (typeof rootDir === 'string') {
rootDirs = processRootDir(rootDir)
} else if (Array.isArray(rootDir)) {
rootDirs = rootDir
.map((dir) => (typeof dir === 'string' ? processRootDir(dir) : []))
.flat()
}
return rootDirs
}
module.exports = getRootDirs