Skip to content

Commit

Permalink
feat: setup configs for linting (#1)
Browse files Browse the repository at this point in the history
  • Loading branch information
PKulkoRaccoonGang authored Dec 11, 2024
1 parent f0bca0a commit 4b9b607
Show file tree
Hide file tree
Showing 22 changed files with 22,027 additions and 3 deletions.
7 changes: 7 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.DS_Store
.eslintcache
.idea
.vscode
coverage
dist
node_modules
4 changes: 4 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// eslint-disable-next-line import/no-extraneous-dependencies
const { createConfig } = require('@openedx/frontend-build');

module.exports = createConfig('eslint');
24 changes: 24 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: Default CI
on:
push:
branches:
- main
pull_request:
branches:
- '**'
jobs:
tests:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Nodejs
uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
- name: Install dependencies
run: npm ci
- name: Lint
run: npm run lint
10 changes: 10 additions & 0 deletions .github/workflows/commitlint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Run commitlint on the commit messages in a pull request.

name: Lint Commit Messages

on:
- pull_request

jobs:
commitlint:
uses: openedx/.github/.github/workflows/commitlint.yml@master
13 changes: 13 additions & 0 deletions .github/workflows/lockfileversion-check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#check package-lock file version

name: Lockfile Version check

on:
push:
branches:
- main
pull_request:

jobs:
version-check:
uses: openedx/.github/.github/workflows/lockfileversion-check-v3.yml@master
74 changes: 73 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,73 @@
# rg-frontend-linters
# RG Frontend Linters

**RG Frontend Linters** provides standardized configurations for **ESLint**, **Stylelint**, and **CommitLint**.
This ensures consistent code quality, style, and commit message conventions across all projects.

## Configurations

- **ESLint**: Enforce consistent JavaScript code style and quality.
- **Stylelint**: Maintain uniform SCSS formatting and conventions.
- **CommitLint**: Validate commit messages against defined standards.

---

## Installation and Usage

### 1. Add the repository to `package.json`:

Include `rg-frontend-linters` as a dependency:

```json
"dependencies": {
"rg-frontend-linters": "git+https://github.com/raccoongang/rg-frontend-linters.git#<version>"
}
```

### 2. Create a configuration file

Add a configuration file for the desired linter in the root of your project. For example, to configure Stylelint:

```bash
touch .stylelintrc.js
```

### 3. Initialize the configuration

Use the provided helper function to set up the linter configuration. For example:

Stylelint (`.stylelintrc.js`):

```javascript
const { createConfig } = require('rg-frontend-linters');

module.exports = createConfig('stylelint');
```

ESLint (`.eslintrc.js`):

```javascript
const { createConfig } = require('rg-frontend-linters');

module.exports = createConfig('eslint');
```

CommitLint (`commitlint.config.js`):

```javascript
const { createConfig } = require('rg-frontend-linters');

module.exports = createConfig('commitlint');
```

### Extending Configuration

Extend the default configuration by adding custom rules or overriding existing ones.

```javascript
const { createConfig } = require('rg-frontend-linters');

module.exports = createConfig('<configName>', {
// Custom rules go here
});
```

18 changes: 18 additions & 0 deletions RG_CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
RG Changelog
############

All notable changes to this project will be documented in this file.

The format is based on `Keep a Changelog <https://keepachangelog.com/en/1.0.0/>`_,
and this project adheres to customized Semantic Versioning e.g.: `redwood-rg.1`

[Unreleased]
************

Added:
=====
* initialize project structure and add default configs (RGInt-303)

- add CI checkers: tests, linters checkers
- add configs and tests
- add documentation
31 changes: 31 additions & 0 deletions config/.commitlintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
module.exports = {
extends: ['@commitlint/config-conventional'],

helpUrl: 'https://open-edx-proposals.readthedocs.io/en/latest/oep-0051-bp-conventional-commits.html',

rules: {
'type-enum':
[2, 'always', [
'revert', 'feat', 'fix', 'perf', 'docs', 'test', 'build', 'refactor', 'style', 'chore', 'temp',
]],

// Default rules we want to suppress:
'body-leading-blank': [0, 'always'],
'body-max-line-length': [0, 'always'],
'footer-max-line-length': [0, 'always'],
'footer-leading-blank': [0, 'always'],
'subject-case': [0, 'always', []],
'subject-full-stop': [0, 'never', '.'],
},

ignores: [
// Allow GitHub revert messages, like:
// Revert "introduce a bug"
// Revert "introduce a bug" (#1234)
message => /^Revert ".*"( \(#\d+\))?/.test(message),

// BTW: commitlint has a built-in list of ignores which are also applied.
// Those include the typical "Merged" messages, so those are implicitly ignored:
// https://github.com/conventional-changelog/commitlint/blob/master/%40commitlint/is-ignored/src/defaults.ts
],
};
4 changes: 4 additions & 0 deletions config/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// eslint-disable-next-line import/no-extraneous-dependencies
const { createConfig } = require('@openedx/frontend-build');

module.exports = createConfig('eslint');
51 changes: 51 additions & 0 deletions config/.stylelintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
module.exports = {
extends: ["@edx/stylelint-config-edx"],
rules: {
indentation: 2,
"string-quotes": "double",
"color-hex-case": "lower",
"declaration-block-trailing-semicolon": "always",
"declaration-colon-space-after": "always",
"declaration-colon-space-before": "never",
"max-empty-lines": 1,
"media-feature-colon-space-after": "always",
"media-feature-colon-space-before": "never",
"media-feature-parentheses-space-inside": "never",
"media-feature-range-operator-space-after": "always",
"media-feature-range-operator-space-before": "always",
"number-leading-zero": "always",
"selector-attribute-brackets-space-inside": "never",
"selector-attribute-operator-space-after": "never",
"selector-attribute-operator-space-before": "never",
"selector-combinator-space-after": "always",
"selector-combinator-space-before": "always",
"selector-list-comma-newline-after": "always",
"selector-pseudo-class-parentheses-space-inside": "never",
"block-closing-brace-newline-after": [
"always",
{ ignoreAtRules: ["if", "else if", "else"] },
],
"font-weight-notation": "numeric",
"selector-pseudo-element-colon-notation": "single",
"scss/at-rule-no-unknown": [
true,
{
ignoreAtRules: ["@import"],
},
],
"alpha-value-notation": "number",
"color-function-notation": "legacy",
"value-keyword-case": [
"lower",
{ ignoreProperties: ["/font/"], camelCaseSvgKeywords: true },
],
"selector-class-pattern": null,
"selector-id-pattern": null,
"hue-degree-notation": null,
"scss/at-extend-no-missing-placeholder": null,
"scss/no-global-function-names": null,
"no-descending-specificity": null,
"import-notation": null,
"media-feature-range-notation": null,
},
};
37 changes: 37 additions & 0 deletions docs/decisions/0001-rg-frontend-linters.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
Technical Solution Overview: RG Frontend Linters
================================================

**RG Frontend Linters** is a solution designed to standardize configurations for **ESLint**, **Stylelint**, and **CommitLint**,
ensuring consistent code quality, styling, and commit message validation across projects. By abstracting the configuration logic into reusable modules,
this approach streamlines the integration process for developers, reduces onboarding time, and enforces consistent standards across teams and projects.

Key Features and Benefits
-------------------------

1. **Centralized Configuration Management**

Developers can leverage predefined configurations for **ESLint**, **Stylelint**, and **CommitLint**, eliminating the need for project-specific setup.
This centralization ensures that all projects follow the same conventions, reducing discrepancies and improving maintainability.

2. **Modular and Reusable Design**

The ``createConfig`` function allows easy initialization of linter configurations. Teams can extend the default configurations with
custom rules tailored to specific project requirements, promoting flexibility without sacrificing consistency.

3. **Simplified Setup Process**

Adding the package as a dependency and initializing the configurations requires minimal effort. This reduces the setup overhead,
enabling developers to focus on coding rather than configuration.

4. **Consistency Across Projects**

Uniform linting and formatting rules enhance readability, simplify collaboration, and reduce code review friction.
Commit message validation ensures adherence to version control standards, further promoting structured development workflows.

Inspired by Frontend Build Repository
--------------------------------------

The concept for **RG Frontend Linters** draws inspiration from the **frontend-build** repository, which similarly provides centralized
configurations for JavaScript testing and linting. Adopting this approach ensures that all tools in the development ecosystem,
including linters and test frameworks, follow a unified configuration pattern across Open edX ecosystem. This alignment fosters standardization and makes
configurations easier to manage and extend.
12 changes: 12 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const getBaseConfig = require('./lib/getBaseConfig');
const createConfig = require('./lib/createConfig');

/**
* Provides utility functions for managing and creating configurations.
*
* @module ConfigUtils
*/
module.exports = {
getBaseConfig,
createConfig,
};
33 changes: 33 additions & 0 deletions lib/ConfigPreset.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
const path = require('path');

const defaultConfigDir = path.resolve(__dirname, '../config');

/**
* Creates a configuration preset object with methods to access configuration files.
*
* @param {Object} options - Configuration options for the preset.
* @param {string} [options.defaultDir=defaultConfigDir] - The directory to search
* for the configuration file. Defaults to `../config`.
* @param {string} options.defaultFilename - The name of the default configuration file.
* @returns {Object} - An object representing the configuration preset.
* @property {string} defaultFilename - The name of the default configuration file.
* @property {Function} getDefault - A function that retrieves the default
* configuration object by resolving and requiring the configuration file.
*/
function ConfigPreset({
defaultDir = defaultConfigDir,
defaultFilename,
}) {
return {
defaultFilename,
/**
* Retrieves the default configuration object by requiring the resolved configuration file.
*
* @returns {any} - The required default configuration object.
*/
// eslint-disable-next-line import/no-dynamic-require, global-require
getDefault: () => require(require.resolve(`./${defaultFilename}`, { paths: [defaultDir] })),
};
}

module.exports = ConfigPreset;
15 changes: 15 additions & 0 deletions lib/createConfig.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
const { merge } = require('webpack-merge');

const getBaseConfig = require('./getBaseConfig');

/**
* Merges a base configuration with a custom configuration fragment.
*
* @param {string} commandName - The name of the command for which the base configuration is retrieved.
* @param {Object} [configFragment={}] - A custom configuration fragment to merge with the base configuration.
* @returns {Object} - The resulting configuration after merging the base configuration with the custom fragment.
*/
module.exports = (commandName, configFragment = {}) => {
const baseConfig = getBaseConfig(commandName);
return merge(baseConfig, configFragment);
};
16 changes: 16 additions & 0 deletions lib/getBaseConfig.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
const presets = require('./presets');

/**
* Retrieves the default configuration for a given preset name.
*
* @param {string} presetName - The name of the preset for which the default configuration is requested.
* @throws {Error} Throws an error if the given preset name is unsupported.
* @returns {any} - The default configuration associated with the preset.
*/
module.exports = (presetName) => {
if (presets[presetName] === undefined) {
throw new Error(`Argument: ${presetName} is unsupported`);
}

return presets[presetName].getDefault();
};
Loading

0 comments on commit 4b9b607

Please sign in to comment.