Skip to content

Commit

Permalink
feat(eslint): use prettier if enabled (projen#1450)
Browse files Browse the repository at this point in the history
When `prettier` is enabled, automatically configure `Eslint` to use it for code formatting, while disabling any rules that may conflict. Previously, users would have had to explicitly set `prettier: true` both at the project level and within `eslintOptions`.

BREAKING CHANGE: Prettier configuration is now under a `settings` option instead (instead of `prettierOptions: { bracketSpacing: false }`, write `prettierOptions: { settings: { bracketSpacing: false } }`).
* **prettier:** `prettier.config` is now called `prettier.settings` and DOES NOT include `overrides`.
* **node:** The `prettierIgnoreEnabled` option is now under `prettierOptions.ignoreFile` and can be accessed via `prettier.ignoreFile`. Similarly, `project.addPrettierIgnore()` is now `project.prettier.addIgnorePattern()`.

---
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
  • Loading branch information
Elad Ben-Israel authored Jan 2, 2022
1 parent 28f87cb commit 5d970d8
Show file tree
Hide file tree
Showing 9 changed files with 501 additions and 668 deletions.
287 changes: 118 additions & 169 deletions API.md

Large diffs are not rendered by default.

21 changes: 21 additions & 0 deletions docs/components.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Components

Components are building blocks that can be composed together into projects. They
represent a self-contained project feature.

When a component is created, it is associated with a specific project:

```ts
const p = new Project(...);

new MyComponent(p);
new YourComponent(p, { /* options */ });
```

Projects can be queried for which components have been added to them:

```ts
for (const c of p.components) {
// do something with `component`
}
```
84 changes: 55 additions & 29 deletions src/javascript/eslint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { PROJEN_RC } from '../common';
import { Component } from '../component';
import { NodeProject } from '../javascript';
import { JsonFile } from '../json';

import { Prettier } from './prettier';

export interface EslintOptions {
/**
Expand Down Expand Up @@ -118,11 +118,17 @@ export class Eslint extends Component {
*/
public readonly ignorePatterns: string[];

private _formattingRules: Record<string, any>;
private readonly _allowDevDeps: Set<string>;
private readonly _plugins = new Array<string>();
private readonly _extends = new Array<string>();
private readonly nodeProject: NodeProject;

constructor(project: NodeProject, options: EslintOptions) {
super(project);

this.nodeProject = project;

project.addDevDeps(
'eslint@^8',
'@typescript-eslint/eslint-plugin@^5',
Expand All @@ -133,14 +139,6 @@ export class Eslint extends Component {
'json-schema',
);

if (options.prettier) {
project.addDevDeps(
'prettier',
'eslint-plugin-prettier',
'eslint-config-prettier',
);
}

if (options.aliasMap) {
project.addDevDeps('eslint-import-resolver-alias');
}
Expand Down Expand Up @@ -171,9 +169,7 @@ export class Eslint extends Component {
// exclude some files
project.npmignore?.exclude('/.eslintrc.json');

const formattingRules: { [rule: string]: any } = options.prettier ? {
'prettier/prettier': ['error'],
} : {
this._formattingRules = {
// see https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/indent.md
'indent': ['off'],
'@typescript-eslint/indent': ['error', 2],
Expand Down Expand Up @@ -212,7 +208,6 @@ export class Eslint extends Component {
};

this.rules = {
...formattingRules,
// Require use of the `import { foo } from 'bar';` form instead of `import foo = require('bar');`
'@typescript-eslint/no-require-imports': ['error'],

Expand Down Expand Up @@ -309,34 +304,24 @@ export class Eslint extends Component {

const tsconfig = options.tsconfigPath ?? './tsconfig.json';

const plugins = [
'@typescript-eslint',
'import',
...(options.prettier ? ['prettier'] : []),
];

const extendsConf = [
'plugin:import/typescript',
...(options.prettier ? [
'prettier',
'plugin:prettier/recommended',
] : []),
];
this.addPlugins('@typescript-eslint');
this.addPlugins('import');
this.addExtends('plugin:import/typescript');

this.config = {
env: {
jest: true,
node: true,
},
root: true,
plugins,
plugins: () => this._plugins,
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaVersion: 2018,
sourceType: 'module',
project: tsconfig,
},
extends: extendsConf,
extends: () => this._extends,
settings: {
'import/parsers': {
'@typescript-eslint/parser': ['.ts', '.tsx'],
Expand All @@ -356,11 +341,17 @@ export class Eslint extends Component {
},
},
ignorePatterns: this.ignorePatterns,
rules: this.rules,
rules: () => ({ ...this._formattingRules, ...this.rules }),
overrides: this.overrides,
};

new JsonFile(project, '.eslintrc.json', { obj: this.config, marker: false });

// if the user enabled prettier explicitly _or_ if the project has a
// `Prettier` component, we shall tweak our configuration accordingly.
if (options.prettier || Prettier.of(project)) {
this.enablePrettier();
}
}

/**
Expand All @@ -372,6 +363,14 @@ export class Eslint extends Component {
}
}

/**
* Adds an eslint plugin
* @param plugin The name of the plugin
*/
public addPlugins(...plugins: string[]) {
this._plugins.push(...plugins);
}

/**
* Add an eslint override.
*/
Expand All @@ -386,6 +385,14 @@ export class Eslint extends Component {
this.ignorePatterns.push(pattern);
}

/**
* Adds an `extends` item to the eslint configuration.
* @param extendList The list of "extends" to add.
*/
public addExtends(...extendList: string[]) {
this._extends.push(...extendList);
}

/**
* Add a glob file pattern which allows importing dev dependencies.
* @param pattern glob pattern.
Expand All @@ -394,6 +401,25 @@ export class Eslint extends Component {
this._allowDevDeps.add(pattern);
}

/**
* Enables prettier for code formatting.
*/
private enablePrettier() {
this.nodeProject.addDevDeps(
'prettier',
'eslint-plugin-prettier',
'eslint-config-prettier',
);

this.addPlugins('prettier');

this._formattingRules = {
'prettier/prettier': ['error'],
};

this.addExtends('prettier', 'plugin:prettier/recommended');
}

private renderDevDepsAllowList() {
return Array.from(this._allowDevDeps);
}
Expand Down
30 changes: 2 additions & 28 deletions src/javascript/node-project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -244,13 +244,6 @@ export interface NodeProjectOptions extends GitHubProjectOptions, NodePackageOpt
*/
readonly pullRequestTemplateContents?: string[];

/**
* Defines an .prettierIgnore file
*
* @default false
*/
readonly prettierIgnoreEnabled?: boolean;

/**
* Setup prettier.
*
Expand All @@ -260,7 +253,7 @@ export interface NodeProjectOptions extends GitHubProjectOptions, NodePackageOpt

/**
* Prettier options
* @default - opinionated default options
* @default - default options
*/
readonly prettierOptions?: PrettierOptions;

Expand Down Expand Up @@ -328,7 +321,7 @@ export enum AutoRelease {
/**
* Automatically bump & release a new version on a daily basis.
*/
DAILY
DAILY,
}

/**
Expand All @@ -347,11 +340,6 @@ export class NodeProject extends GitHubProject {
*/
public readonly npmignore?: IgnoreFile;

/**
* The .prettierIgnore file.
*/
public readonly prettierIgnore?: IgnoreFile;

/**
* @deprecated use `package.allowLibraryDependencies`
*/
Expand Down Expand Up @@ -476,10 +464,6 @@ export class NodeProject extends GitHubProject {
this.npmignore = new IgnoreFile(this, '.npmignore');
}

if (options.prettierIgnoreEnabled ?? false) {
this.prettierIgnore = new IgnoreFile(this, '.prettierignore');
}

this.addDefaultGitIgnore();

if (options.gitignore?.length) {
Expand Down Expand Up @@ -859,16 +843,6 @@ export class NodeProject extends GitHubProject {
this.npmignore?.addPatterns(pattern);
}

/**
* Defines Prettier ignore Patterns
* these patterns will be added to the file .prettierignore
*
* @param pattern filepatterns so exclude from prettier formatting
*/
public addPrettierIgnore(pattern: string) {
this.prettierIgnore?.addPatterns(pattern);
}

private addLicense(options: NodeProjectOptions) {
if (this.package.license) {
new License(this, {
Expand Down
Loading

0 comments on commit 5d970d8

Please sign in to comment.