Release v1.0.3

This commit is contained in:
Jyotirmoy Bandyopadhayaya 2023-06-17 12:41:31 +05:30
commit 759cdf28db
Signed by: bravo68web
GPG Key ID: F5671FD7BCB9917A
47 changed files with 6570 additions and 0 deletions

8
.changeset/README.md Normal file
View File

@ -0,0 +1,8 @@
# Changesets
Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
with multi-package repos, or single-package repos to help you version and publish your code. You can
find the full documentation for it [in our repository](https://github.com/changesets/changesets)
We have a quick list of common questions to get you started engaging with this project in
[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)

16
.changeset/config.json Normal file
View File

@ -0,0 +1,16 @@
{
"$schema": "https://unpkg.com/@changesets/config@2.3.0/schema.json",
"access": "public",
"baseBranch": "main",
"changelog": [
"@changesets/changelog-github",
{
"repo": "bravo68web/nodejs-config"
}
],
"commit": false,
"fixed": [["@bravo68web/eslint-config", "@bravo68web/tsconfig", "@bravo68web/prettier-config"]],
"ignore": [],
"linked": [],
"updateInternalDependencies": "patch"
}

4
.eslintrc.json Normal file
View File

@ -0,0 +1,4 @@
{
"extends": ["@bravo68web/eslint-config/code-style"],
"ignorePatterns": ["node_modules", "dist"]
}

32
.github/actions/setup/action.yml vendored Normal file
View File

@ -0,0 +1,32 @@
name: Setup Node Environment
description: Prepare and install everything for nodejs repo
runs:
using: composite
steps:
- uses: pnpm/action-setup@v2
- name: Setup Node.js
uses: actions/setup-node@v3
with:
cache: pnpm
node-version: 18
registry-url: https://registry.npmjs.org/
- name: Install dependencies
shell: bash
run: pnpm i
- name: Restore Turborepo Cache
uses: actions/cache@v3
with:
path: |
apps/**/.turbo
node_modules/.cache/turbo
key: turbo-${{ runner.os }}-${{ github.job }}-${{ github.sha }}
restore-keys: |
turbo-${{ runner.os }}-${{ github.job }}
- name: Build packages
shell: bash
run: pnpm build

25
.github/workflows/lint.yml vendored Normal file
View File

@ -0,0 +1,25 @@
name: Linting
on:
push:
branches: [main, dev]
pull_request:
branches: [main, dev]
workflow_dispatch:
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Setup Environment
uses: ./.github/actions/setup
- name: Testing
run: pnpm test
- name: Run Checking
run: pnpm lint

39
.github/workflows/publish.yml vendored Normal file
View File

@ -0,0 +1,39 @@
name: Publish to NPM
on:
push:
branches:
- main
concurrency: ${{ github.workflow }}-${{ github.ref }}
permissions:
contents: read
jobs:
release:
name: Release
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
id-token: write
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Setup Environment
uses: ./.github/actions/setup
- name: Create Release Pull Request or Publish to NPM
id: changesets
uses: changesets/action@v1
with:
version: pnpm ci:version
publish: pnpm ci:publish
commit: 'chore(release): publish packages'
title: 'chore(release): publish packages'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

View File

@ -0,0 +1,27 @@
name: Sync Renovate changeset
on:
pull_request_target:
paths:
- '.github/workflows/sync_renovate-changesets.yml'
- 'pnpm-lock.yaml'
jobs:
generate-changeset:
runs-on: ubuntu-latest
if: github.actor == 'renovate[bot]' && github.repository == 'bravo68web/nodejs-config'
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 2
ref: ${{ github.head_ref }}
- name: Setup Environment
uses: ./.github/actions/setup
- name: Configure Git
run: |
git config --global user.email '41448663+BRAVO68WEB@users.noreply.github.com'
git config --global user.name 'Github changeset workflow'
- name: Generate changeset
run: pnpm sync-renovate-changesets

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
node_modules
dist
.turbo
.eslintcache

5
.husky/pre-commit Executable file
View File

@ -0,0 +1,5 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
# Check all files with Prettier.
npx prettier --check .

6
.npmrc Normal file
View File

@ -0,0 +1,6 @@
save-exact = true
engine-strict = false
ignore-engines = true
tag-version-prefix = ""
auto-install-peers = true
strict-peer-dependencies = false

3
.prettierignore Normal file
View File

@ -0,0 +1,3 @@
dist
package-lock.json
pnpm-lock.yaml

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2023 bravo68web
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

19
README.md Normal file
View File

@ -0,0 +1,19 @@
# Node.js Config
[![Linting](https://github.com/bravo68web/nodejs-config/actions/workflows/lint.yml/badge.svg?branch=main)](https://github.com/bravo68web/nodejs-config/actions/workflows/lint.yml)
This is a monorepo to share miscellaneous Node.js config for [bravo68web](https://github.com/bravo68web), monorepo is managed and versioned by [Changeset](https://github.com/changesets/changesets).
## Apps
- [@bravo68web/eslint-config](apps/eslint-config/) - ESLint config
- [@bravo68web/tsconfig](apps/tsconfig/) - TypeScript config
- [@bravo68web/prettier-config](apps/prettier-config/) - Prettier config
## Strict Configuration
Please be advised that this application has **strict configurations**. **_Adopt these configurations carefully_** and only if they meet the requirements of your project. It is recommended to thoroughly review and understand the configurations before implementation.
## License
This project is licensed under the MIT License - see the [LICENSE](./LICENSE) file for details

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2023 bravo68web
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,114 @@
# @bravo68web/eslint-config
[![Version](https://img.shields.io/npm/v/@bravo68web/eslint-config.svg?style=flat-square)](https://www.npmjs.com/package/@bravo68web/eslint-config)
Welcome to the `@bravo68web/eslint-config`! This is the official ESLint configuration for [bravo68web](https://github.com/bravo68web) projects, enforcing strict rules and best practices for a clean and organized codebase.
## Rules and plugins
This configuration includes a variety of rules and plugins, such as:
### [eslint-plugin-simple-import-sort](https://www.npmjs.com/package/eslint-plugin-simple-import-sort)
This plugin **sorts your imports, ensuring consistent formatting** across your codebase.
### [eslint-plugin-unicorn](https://www.npmjs.com/package/eslint-plugin-unicorn)
This plugin provides a set of rules for enforcing best practices for Node.js and JavaScript development, with a focus on improved security and maintainability.
### [eslint-plugin-tailwindcss](https://www.npmjs.com/package/eslint-plugin-tailwindcss)
This plugin integrates the Tailwind CSS framework into your ESLint setup, helping you write cleaner, more maintainable code when **using Tailwind**.
### [eslint-plugin-sonarjs](https://www.npmjs.com/package/eslint-plugin-sonarjs)
This plugin provides a set of rules aimed at **improving code quality and catching bugs early**, by leveraging the SonarJS engine.
### [eslint-plugin-promise](https://www.npmjs.com/package/eslint-plugin-promise)
This plugin provides a set of rules for enforcing best practices when working with **Promises in JavaScript**.
### [eslint-plugin-react](https://www.npmjs.com/package/eslint-plugin-react)
This plugin provides a set of rules for enforcing best practices when **writing React applications**, including guidelines for improving performance and maintainability.
### [@typescript-eslint/eslint-plugin](https://www.npmjs.com/package/@typescript-eslint/eslint-plugin)
This plugin provides a set of rules for enforcing best practices when **writing TypeScript code**, and is specifically designed for use with the TypeScript language.
### [eslint-plugin-deprecation](https://www.npmjs.com/package/eslint-plugin-deprecation)
(Stricter TypeScript only)
This plugin provides a set of rules to enfore best practices when using **deprecated APIs**.
## Installation
To start using `@bravo68web/eslint-config`, simply run:
```bash
npm install --save-dev @bravo68web/eslint-config
```
## Usage
Add the following code to your `.eslintrc.js` or `.eslintrc.json` file:
- Default: (TypeScript is also supported)
```js
module.exports = {
extends: ['@bravo68web'],
// extends: ['@bravo68web/eslint-config/default'], // if you want to use named config
};
```
- Code Style: (prettier)
```js
module.exports = {
extends: ['@bravo68web/eslint-config/code-style'],
};
```
- Typescript Strict:
```js
module.exports = {
extends: ['@bravo68web/eslint-config/typescript-strict'],
parserOptions: {
ecmaVersion: 'latest',
project: './tsconfig.json',
// tsconfigRootDir: __dirname, // if you use tsconfig.json in a different directory
},
};
```
- Ultimate: (TypeScript strict + Code Style)
```js
module.exports = {
extends: ['@bravo68web/eslint-config/ultimate'],
parserOptions: {
ecmaVersion: 'latest',
project: './tsconfig.json',
// tsconfigRootDir: __dirname, // if you use tsconfig.json in a different directory
},
};
```
And that's it! You're now ready to use
## Compatibility
This package is compatible with the following dependencies and Node.js versions:
- ESLint: 8.x
- TypeScript: 5.x
- Node.js: Any version that supports dependencies above
**Updating to the latest version of this package is recommended for the best compatibility.**
## License
This project is licensed under the MIT License - see the [LICENSE](./LICENSE) file for details

View File

@ -0,0 +1,88 @@
{
"name": "@bravo68web/eslint-config",
"version": "1.0.3",
"description": "The official ESLint configuration for bravo68web projects",
"license": "MIT",
"author": "Bravo68web <hi@b68.dev> (https://github.com/bravo68web/)",
"homepage": "https://github.com/bravo68web/nodejs-config#readme",
"repository": "git+https://github.com/bravo68web/nodejs-config",
"bugs": {
"url": "https://github.com/bravo68web/nodejs-config/issues"
},
"files": [
"dist"
],
"scripts": {
"build": "rollup -c --silent",
"lint": "tsc && eslint --fix . --cache",
"test": "vitest run"
},
"dependencies": {
"@typescript-eslint/eslint-plugin": "5.59.9",
"@typescript-eslint/parser": "5.59.9",
"deepmerge": "4.3.1",
"eslint-config-prettier": "8.8.0",
"eslint-plugin-autofix": "1.1.0",
"eslint-plugin-deprecation": "1.4.1",
"eslint-plugin-jsx-a11y": "6.7.1",
"eslint-plugin-prettier": "4.2.1",
"eslint-plugin-promise": "6.1.1",
"eslint-plugin-react": "7.32.2",
"eslint-plugin-regexp": "1.15.0",
"eslint-plugin-security": "1.7.1",
"eslint-plugin-simple-import-sort": "10.0.0",
"eslint-plugin-sonarjs": "0.19.0",
"eslint-plugin-tailwindcss": "3.12.1",
"eslint-plugin-unicorn": "47.0.0"
},
"peerDependencies": {
"eslint": "8.x",
"typescript": "5.x"
},
"devDependencies": {
"@bravo68web/tsconfig": "*",
"@rollup/plugin-commonjs": "25.0.1",
"@rollup/plugin-node-resolve": "15.1.0",
"@rollup/plugin-typescript": "11.1.1",
"@types/deepmerge": "2.2.0",
"@types/eslint": "8.40.1",
"@types/node": "18.16.17",
"@types/rollup-plugin-auto-external": "2.0.2",
"eslint": "8.42.0",
"rollup": "3.24.1",
"rollup-plugin-auto-external": "2.0.0",
"tsec": "0.2.7",
"typescript": "5.1.3",
"vitest": "0.32.0"
},
"keywords": [
"bravo68web",
"eslint",
"eslint-config"
],
"publishConfig": {
"access": "public"
},
"exports": {
".": {
"import": "./dist/default.mjs",
"require": "./dist/default.cjs"
},
"./default": {
"import": "./dist/default.mjs",
"require": "./dist/default.cjs"
},
"./code-style": {
"import": "./dist/code-style.mjs",
"require": "./dist/code-style.cjs"
},
"./typescript-strict": {
"import": "./dist/typescript-strict.mjs",
"require": "./dist/typescript-strict.cjs"
},
"./ultimate": {
"import": "./dist/ultimate.mjs",
"require": "./dist/ultimate.cjs"
}
}
}

View File

@ -0,0 +1,87 @@
import fs from 'node:fs';
import path from 'node:path';
import rollupPluginCommonjs from '@rollup/plugin-commonjs';
import rollupPluginNodeResolve from '@rollup/plugin-node-resolve';
import rollupPluginTypescript from '@rollup/plugin-typescript';
import rollupPluginAutoExternal from 'rollup-plugin-auto-external';
// Read the files in the src directory
const dir = './src/';
// Filter the .ts files
const files = fs.readdirSync(dir).filter(file => file.endsWith('.ts'));
const plugins = [
// Automatically mark all dependencies as external
rollupPluginAutoExternal(),
// Resolve node modules
rollupPluginNodeResolve(),
// Convert CommonJS modules to ES6
rollupPluginCommonjs(),
// Compile TypeScript files
rollupPluginTypescript({
tsconfig: 'tsconfig.json',
}),
];
/**
* @typedef {import('rollup').RollupOptions} RollupOptions
* @typedef {import('rollup').OutputOptions} OutputOptions
* @typedef {import('rollup').Plugin} Plugin
*/
/**
* @typedef {Object} ParticularFormatConfig
* @property {string} input
* @property {OutputOptions} output
* @property {Array<Plugin>} plugins
*/
/**
* Generates the Rollup configuration for CJS (CommonJS) builds.
*
* @param {string} filename - The name of the input TypeScript file.
* @returns {ParticularFormatConfig} The Rollup configuration for CJS builds.
*/
function getCjsConfig(filename) {
return {
input: `${dir}${filename}`,
output: {
dir: './dist',
exports: 'default',
entryFileNames: `${path.basename(filename, '.ts')}.cjs`,
format: 'cjs',
},
plugins,
};
}
/**
* Generates the Rollup configuration for CJS (CommonJS) builds.
*
* @param {string} filename - The name of the input TypeScript file.
* @returns {ParticularFormatConfig} The Rollup configuration for CJS builds.
*/
function getEsmConfig(filename) {
return {
input: `${dir}${filename}`,
output: {
dir: './dist',
exports: 'default',
entryFileNames: `${path.basename(filename, '.ts')}.mjs`,
format: 'esm',
},
plugins,
};
}
/**
* Generates the Rollup configuration for CJS (CommonJS) and ESM (ECMAScript Module) builds.
* @param {string} filename - The name of the input TypeScript file.
* @returns {Array<ParticularFormatConfig>} The Rollup configuration for CJS and ESM builds.
*/
function getEntryConfigs(filename) {
return [getCjsConfig(filename), getEsmConfig(filename)];
}
export default files.flatMap(element => getEntryConfigs(element));

View File

@ -0,0 +1,6 @@
import merge from 'deepmerge';
import defaultConfig from './default';
import strictCodeStyleConfig from './sub-rules/prettier';
export default merge(defaultConfig, strictCodeStyleConfig);

View File

@ -0,0 +1,105 @@
import type { Linter } from 'eslint';
const config: Linter.Config = {
env: {
browser: true,
es6: true,
node: true,
},
extends: [
'eslint:recommended',
'plugin:react/recommended',
'plugin:regexp/recommended',
'plugin:unicorn/recommended',
'plugin:sonarjs/recommended',
'plugin:security/recommended',
'plugin:tailwindcss/recommended',
'plugin:@typescript-eslint/recommended',
'plugin:@typescript-eslint/eslint-recommended',
],
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaFeatures: {
jsx: true,
},
ecmaVersion: 'latest',
},
plugins: [
'regexp',
'jsx-a11y',
'autofix',
'react',
'sonarjs',
'unicorn',
'@typescript-eslint',
'simple-import-sort',
],
rules: {
quotes: [
2,
'single',
{
avoidEscape: true,
},
],
// Eslint
'prefer-arrow-callback': 2,
semi: [2, 'always'],
// Import sorting
'simple-import-sort/imports': 2,
'simple-import-sort/exports': 2,
// React
'react/react-in-jsx-scope': 0,
'react/button-has-type': 2,
'react/prop-types': 0,
'react/no-array-index-key': 2,
// SonarJS
'sonarjs/no-duplicate-string': 0,
// Unicorn
'unicorn/no-null': 0,
'unicorn/prefer-module': 0,
'unicorn/no-useless-undefined': 0,
'unicorn/prevent-abbreviations': 0,
'unicorn/no-await-expression-member': 0,
// Typescript
'@typescript-eslint/no-namespace': 0,
'@typescript-eslint/no-misused-promises': 0,
'@typescript-eslint/no-unused-vars': [2],
'@typescript-eslint/no-unsafe-call': 0,
'@typescript-eslint/no-unsafe-assignment': 0,
'@typescript-eslint/no-unsafe-member-access': 0,
},
settings: {
react: {
version: 'detect',
},
},
overrides: [
{
files: ['*.js', '*.jsx', '*.cjs'],
rules: {
'@typescript-eslint/no-var-requires': 0,
},
},
{
files: ['*.js', '*.jsx', '*.ts', '*.tsx', '*.cjs', '*.mjs', '*.mts', '*.cts'],
rules: {
'simple-import-sort/imports': [
'error',
{
groups: [
['dotenv/config'],
['^node:', '^react$', '^react-dom$', '^next?/|^next$'],
['^@?\\w'],
['^[\\w]'],
['^'],
['^\\.'],
],
},
],
},
},
],
};
export default config;

View File

@ -0,0 +1,12 @@
import { Linter } from 'eslint';
const strictCodeStyleConfig: Linter.Config = {
// Create a strictCodeStyleConfig object of type Linter.Config.
extends: ['prettier'], // Add the prettier package to the extends array.
plugins: ['prettier'], // Add the prettier package to the plugins array.
rules: {
'prettier/prettier': 2, // Add a rule to enforce the prettier plugin.
},
};
export default strictCodeStyleConfig; // Export the strictCodeStyleConfig object as the default export.

View File

@ -0,0 +1,38 @@
import { Linter } from 'eslint';
const strictTypescriptConfig: Linter.Config = {
parser: '@typescript-eslint/parser',
extends: [
'plugin:@typescript-eslint/strict',
'plugin:@typescript-eslint/recommended',
'plugin:@typescript-eslint/recommended-requiring-type-checking',
],
plugins: ['deprecation', '@typescript-eslint'],
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
},
rules: {
// Enforce using the @deprecated tag in JSDoc comments
'deprecation/deprecation': 1,
// Typescript
// Disallow await on a non-promise
'@typescript-eslint/no-misused-promises': 0,
// Enforce consistent use of type imports
'@typescript-eslint/consistent-type-imports': 2,
// Enforce consistent type exports
'@typescript-eslint/consistent-type-exports': 2,
// Enforce that type arguments will use if not required
'@typescript-eslint/no-redundant-type-constituents': 2,
// Disallow calling an any type value
'@typescript-eslint/no-unsafe-call': 0,
// Disallow assigning any to variables and properties
'@typescript-eslint/no-unsafe-assignment': 0,
// Disallow member access on any typed variables
'@typescript-eslint/no-unsafe-member-access': 0,
// Disallow the use of custom TypeScript modules and namespaces
'@typescript-eslint/no-namespace': 0,
},
};
export default strictTypescriptConfig;

View File

@ -0,0 +1,6 @@
import merge from 'deepmerge';
import defaultConfig from './default';
import strictTypescriptConfig from './sub-rules/strict-typescript';
export default merge(defaultConfig, strictTypescriptConfig);

View File

@ -0,0 +1,9 @@
import merge from 'deepmerge';
import defaultConfig from './default';
import strictCodeStyleConfig from './sub-rules/prettier';
import strictTypescriptConfig from './sub-rules/strict-typescript';
const config = merge(strictCodeStyleConfig, strictTypescriptConfig);
export default merge(defaultConfig, config);

View File

@ -0,0 +1,14 @@
import { describe } from 'vitest';
import config from '../src/code-style';
import { checkLintingErrors, checkValidity, createEngine } from './utils';
describe('Code Style Configuration', () => {
const engine = createEngine(config);
// Check the validity of the engine.
checkValidity(engine);
// Check for any linting errors.
checkLintingErrors(engine);
});

View File

@ -0,0 +1,14 @@
import { describe } from 'vitest';
import config from '../src/default';
import { checkLintingErrors, checkValidity, createEngine } from './utils';
describe('Default Configuration', () => {
const engine = createEngine(config);
// Check if the script is valid
checkValidity(engine);
// Check if the script has any linting errors
checkLintingErrors(engine);
});

View File

@ -0,0 +1,6 @@
const config = {
apple: 'red',
banana: 'yellow',
};
export default config;

View File

@ -0,0 +1,19 @@
import { describe } from 'vitest';
import config from '../src/typescript-strict';
import { checkLintingErrorsFromFile, checkValidity, createEngine } from './utils';
describe('Typescript Strict Configuration', () => {
const engine = createEngine({
...config,
parserOptions: {
project: './tsconfig.json',
},
});
// check that the engine is valid
checkValidity(engine);
// check that there are no linting errors in the file
checkLintingErrorsFromFile(engine, './tests/examples/example-1.ts');
});

View File

@ -0,0 +1,19 @@
import { describe } from 'vitest';
import config from '../src/ultimate';
import { checkLintingErrorsFromFile, checkValidity, createEngine } from './utils';
describe('Ultimate Configuration', () => {
const engine = createEngine({
...config,
parserOptions: {
project: './tsconfig.json',
},
});
// Check the engine's configuration.
checkValidity(engine);
// Check the engine's linting errors.
checkLintingErrorsFromFile(engine, './tests/examples/example-1.ts');
});

View File

@ -0,0 +1,38 @@
import { ESLint, Linter } from 'eslint';
import { expect, it } from 'vitest';
// Create an ESLint engine, based on a base config.
export const createEngine = (baseConfig: Linter.Config) => {
return new ESLint({
useEslintrc: false, // do not use .eslintrc.* files
baseConfig, // set the base config
});
};
export const checkValidity = (engine: ESLint) => {
it('is valid configuration', async () => {
// Linting an empty string is invalid, so we expect it to throw
await expect(engine.lintText('')).resolves.not.toThrow();
});
};
// This test ensures that the linting engine is properly configured.
export const checkLintingErrors = (engine: ESLint) => {
it('does not produce linting errors', async () => {
// Run linting on an empty string.
const lintResults = await engine.lintText('');
// Expect that the linting engine does not produce any errors.
expect(lintResults[0].errorCount).toBe(0);
});
};
export const checkLintingErrorsFromFile = (engine: ESLint, file: string) => {
it('does not produce linting errors', async () => {
// Lint the file using the ESLint engine
const lintResults = await engine.lintFiles(file);
// Expect that the file has no errors
expect(lintResults[0].errorCount).toBe(0);
});
};

View File

@ -0,0 +1,9 @@
{
"compilerOptions": {
"moduleResolution": "node",
"noEmit": true
},
"exclude": ["node_modules", "dist"],
"extends": "@bravo68web/tsconfig/base.json",
"include": ["src", "rollup.config.mjs", "tests/examples/example-1.ts"]
}

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2023 bravo68web
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,80 @@
# @bravo68web/prettier-config
[![Version](https://img.shields.io/npm/v/@bravo68web/prettier-config.svg?style=flat-square)](https://www.npmjs.com/package/@bravo68web/prettier-config)
Welcome to the `@bravo68web/prettier-config`! This is the Prettier configuration for [bravo68web](https://github.com/bravo68web).
## Specificed Config
- **Single Quotes** - Use single quotes instead of double quotes.
- **Tab Width** - Use **2** spaces for indentation.
- **Trailing Comma** - Use trailing commas wherever possible.
- **Print Width** - Use a print width of **100** characters.
- **Avoid Parentheses** - Avoid parentheses when possible.
> `x => x * x` instead of `(x) => x * x`
- **Truey Bracket Spacing** - Add spaces inside of curly braces.
> `{ foo: bar }` instead of `{foo: bar}`
- **Disabled bracket same line** - Objects and arrays are formatted with each item on a new line.
## Prettier Plugins
In addition to the base Prettier configuration, this package also includes the following plugins:
### [prettier-plugin-package-perfection](https://npmjs.com/package/prettier-plugin-package-perfection)
This plugin makes sure your `package.json` file is correctly formatted and includes all necessary information.
### [prettier-plugin-prisma](https://npmjs.com/package/prettier-plugin-prisma)
This plugin makes sure your Prisma schema files are correctly formatted, making it easier to read and maintain.
### [prettier-plugin-sort-json](https://npmjs.com/package/prettier-plugin-sort-json)
This plugin sorts the properties of your JSON files, ensuring consistent formatting across your codebase.
### [prettier-plugin-tailwindcss](https://npmjs.com/package/prettier-plugin-tailwindcss)
This plugin makes sure your Tailwind CSS code is correctly formatted and adheres to best practices, helping you keep your codebase clean and maintainable.
## Installation
To start using `@bravo68web/prettier-config`, simply run:
```bash
npm install --save-dev @bravo68web/prettier-config
```
## Usage
Add the following code to your `.prettierrc` or `.prettierrc.json` file:
```json
"@bravo68web/prettier-config"
```
(or `package.json`)
```json
{
"prettier": "@bravo68web/prettier-config"
}
```
And that's it! You're now ready to use
## Compatibility
This package is compatible with the following Prettier and Node.js versions:
- Prettier: 2.0 or later (recommended: latest v2, before major version 3)
- Node.js: Any version that supports Prettier
**Updating to the latest version of this package is recommended for the best compatibility.**
## License
This project is licensed under the MIT License - see the [LICENSE](./LICENSE) file for details.

View File

@ -0,0 +1,18 @@
{
"$schema": "http://json.schemastore.org/prettierrc",
"arrowParens": "avoid",
"bracketSameLine": false,
"bracketSpacing": true,
"jsonRecursiveSort": true,
"plugins": [
"prettier-plugin-prisma",
"prettier-plugin-sort-json",
"prettier-plugin-tailwindcss",
"prettier-plugin-package-perfection"
],
"printWidth": 100,
"semi": true,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "all"
}

View File

@ -0,0 +1,39 @@
{
"name": "@bravo68web/prettier-config",
"version": "1.0.3",
"description": "The official Prettier configuration for bravo68web projects",
"author": "Bravo68web <hi@b68.dev> (https://github.com/bravo68web/)",
"homepage": "https://github.com/bravo68web/nodejs-config#readme",
"repository": "git+https://github.com/bravo68web/nodejs-config",
"bugs": {
"url": "https://github.com/bravo68web/nodejs-config/issues"
},
"main": "index.json",
"files": [
"index.json",
"package.json",
"README.md",
"LICENSE"
],
"scripts": {
"test": "vitest run"
},
"dependencies": {
"prettier-plugin-package-perfection": "1.1.0",
"prettier-plugin-prisma": "4.13.0",
"prettier-plugin-sort-json": "1.0.0",
"prettier-plugin-tailwindcss": "0.3.0",
"vitest": "0.32.0"
},
"peerDependencies": {
"prettier": "2.x"
},
"keywords": [
"bravo68web",
"prettier",
"prettier-config"
],
"publishConfig": {
"access": "public"
}
}

View File

@ -0,0 +1,20 @@
import prettier from 'prettier';
import { describe, expect, it } from 'vitest';
import config from '../index.json';
describe('Prettier Config', () => {
it('is valid configuration', () => {
// Format the code with Prettier
const code = prettier.format(
'const foo=1',
Object.assign(config as prettier.Options, {
parser: 'typescript',
}) as prettier.Options,
);
// Ensure it matches the expected formatting
expect(code).toBe(`const foo = 1;
`);
});
});

21
apps/tsconfig/LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2023 bravo68web
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

48
apps/tsconfig/README.md Normal file
View File

@ -0,0 +1,48 @@
# @bravo68web/tsconfig
[![Version](https://img.shields.io/npm/v/@bravo68web/tsconfig.svg?style=flat-square)](https://www.npmjs.com/package/@bravo68web/tsconfig)
Welcome to the `@bravo68web/eslint-config`! Strict Typescript configuration for [bravo68web](https://github.com/bravo68web). Use with caution.
## Installation
To start using `@bravo68web/tsconfig`, simply run:
```bash
npm install --save-dev @bravo68web/tsconfig
```
## Usage
Add the following code to your `tsconfig.json` file:
- Default configuration
```json
{
"extends": "@bravo68web/tsconfig/base.json"
}
```
- Web Frontend configuration
```json
{
"extends": "@bravo68web/tsconfig/web.json"
}
```
And that's it! You're now ready to use
## Compatibility
This package is compatible with the following TypeScript and Node.js versions:
- TypeScript: 5.0 or later
- Node.js: Any version that supports the above TypeScript version
**Updating to the latest version of this package is recommended for the best compatibility.**
## License
This project is licensed under the MIT License - see the [LICENSE](./LICENSE) file for details

38
apps/tsconfig/base.json Normal file
View File

@ -0,0 +1,38 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"compilerOptions": {
"allowJs": true,
"allowSyntheticDefaultImports": true,
"allowUnreachableCode": false,
"allowUnusedLabels": false,
"alwaysStrict": true,
"checkJs": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"isolatedModules": true,
"module": "esnext",
"moduleResolution": "node",
"noEmit": true,
"noFallthroughCasesInSwitch": true,
"noImplicitAny": true,
"noImplicitOverride": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noUncheckedIndexedAccess": false,
"noUnusedLocals": true,
"noUnusedParameters": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"strict": true,
"strictFunctionTypes": true,
"strictNullChecks": true,
"strictPropertyInitialization": true,
"target": "esnext"
},
"display": "Default tsconfig.json",
"exclude": ["node_modules"]
}

View File

@ -0,0 +1,30 @@
{
"name": "@bravo68web/tsconfig",
"version": "1.0.3",
"description": "Typescript config for bravo68web, ensure the consistency of code quality.",
"license": "MIT",
"author": "Bravo68web <hi@b68.dev> (https://github.com/bravo68web/)",
"homepage": "https://github.com/bravo68web/nodejs-config#readme",
"repository": "git+https://github.com/bravo68web/nodejs-config",
"bugs": {
"url": "https://github.com/bravo68web/nodejs-config/issues"
},
"files": [
"base.json",
"web.json"
],
"peerDependencies": {
"typescript": "5.x"
},
"devDependencies": {
"typescript": "5.1.3"
},
"keywords": [
"bravo68web",
"tsconfig",
"typescript"
],
"publishConfig": {
"access": "public"
}
}

10
apps/tsconfig/web.json Normal file
View File

@ -0,0 +1,10 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"compilerOptions": {
"jsx": "preserve",
"lib": ["dom", "dom.iterable", "esnext"]
},
"display": "Website tsconfig.json",
"exclude": ["node_modules"],
"extends": "./base.json"
}

35
package.json Normal file
View File

@ -0,0 +1,35 @@
{
"private": true,
"name": "@bravo68web/node-config",
"version": "0.0.0",
"description": "Sharable Node.js miscellaneous config for bravo68web",
"license": "MIT",
"repository": "git+https://github.com/bravo68web/nodejs-config",
"type": "module",
"scripts": {
"build": "turbo build",
"ci:publish": "changeset publish",
"ci:version": "changeset version",
"format": "prettier --write .",
"preinstall": "npx only-allow pnpm",
"lint": "turbo lint",
"prepare": "is-ci || husky install",
"sync-renovate-changesets": "node --loader @esbuild-kit/esm-loader scripts/sync-renovate-changesets.ts",
"test": "turbo test"
},
"dependencies": {
"@bravo68web/eslint-config": "*",
"@bravo68web/prettier-config": "*",
"@bravo68web/tsconfig": "*",
"@changesets/changelog-github": "0.4.8",
"@changesets/cli": "2.26.1",
"@esbuild-kit/esm-loader": "2.5.5",
"@types/node": "18.16.17",
"husky": "8.0.3",
"is-ci": "3.0.1",
"prettier": "2.8.8",
"turbo": "1.10.3"
},
"packageManager": "pnpm@8.6.2",
"prettier": "@bravo68web/prettier-config"
}

5226
pnpm-lock.yaml Normal file

File diff suppressed because it is too large Load Diff

2
pnpm-workspace.yaml Normal file
View File

@ -0,0 +1,2 @@
packages:
- apps/*

5
renovate.json Normal file
View File

@ -0,0 +1,5 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"baseBranches": ["dev"],
"extends": ["config:base"]
}

View File

@ -0,0 +1,145 @@
#!/usr/bin/env node
/* eslint-disable security/detect-non-literal-fs-filename */
import { exec as _exec } from 'node:child_process';
import { promises as fs } from 'node:fs';
import { promisify } from 'node:util';
const exec = promisify(_exec);
const branch = await exec('git branch --show-current');
if (!branch.stdout.startsWith('renovate/')) {
console.log('Not a renovate branch, skipping');
process.exit(0);
}
const diffOutput = await exec('git diff --name-only HEAD~1');
const diffFiles = diffOutput.stdout
.split('\n')
.filter(file => file !== 'package.json')
.filter(file => file.includes('package.json'));
if (diffFiles.some(f => f.startsWith('.changeset'))) {
console.log('Changeset already exists, skipping');
process.exit(0);
}
// If changed file does not include package.json in monorepo, skip
if (!diffFiles.some(file => file.includes('package.json'))) {
console.log('No package.json changes to published packages, skipping');
process.exit(0);
}
// Get changed dependencies inside package.json files, return array of package { name, version }
/**
* name: '@renovate/project-demo',
* dependencies: {
* + "@renovate/eslint-config": "1.0.1",
* - "@renovate/eslint-config": "1.0.0",
* + "@renovate/stylelint-config": "1.0.1",
* - "@renovate/stylelint-config": "1.0.0",
* }
*
* so we need to get the dependency names and versions in array of { name: '@renovate/eslint-config', newVersion: '1.0.1', oldVersion: '1.0.0' }, ...
*/
// Find all changed package.json files and extract their dependencies
const packageJsonFiles = await Promise.all(
diffFiles.map(file => fs.readFile(file, 'utf8').then(data => ({ file, data }))),
);
const dependencies: {
name: string;
newVersion: string;
projects: string[];
}[] = [];
// eslint-disable-next-line sonarjs/cognitive-complexity
const getChangedDependencies = (
projectName: string,
newDepsObj: Record<string, string>,
oldDepsObj: Record<string, string>,
) => {
for (const [depName, newVersion] of Object.entries(newDepsObj)) {
if (typeof newVersion !== 'string') continue;
const oldVersion: string = oldDepsObj[String(depName)];
// Check if the dependency version has changed
if (oldVersion === newVersion) continue;
// Check if the dependency exists in other projects and new version is the same
if (
dependencies.some(dep => dep.name === depName) &&
dependencies.some(dep => dep.newVersion === newVersion)
) {
const dep = dependencies.find(dep => dep.name === depName);
if (!dep) continue;
// Add project to existing dependency
dep.projects.push(projectName);
// Update the element in the array
const index = dependencies.findIndex(dep => dep.name === depName);
dependencies[Number(index)] = dep;
} else {
dependencies.push({ name: depName, newVersion, projects: [projectName] });
}
}
};
for (const { file } of packageJsonFiles) {
const { stdout: newDepsJson } = await exec(`git show HEAD:${file}`);
// Get old dependencies from git history
const { stdout: oldDepsJson } = await exec(`git show HEAD~1:${file}`);
const {
name: projectName,
dependencies: oldDeps = {},
devDependencies: oldDevDeps = {},
} = JSON.parse(oldDepsJson);
const { dependencies: newDeps = {}, devDependencies: newDevDeps = {} } = JSON.parse(newDepsJson);
getChangedDependencies(projectName, newDeps, oldDeps);
getChangedDependencies(projectName, newDevDeps, oldDevDeps);
}
// Create changeset
async function createChangeset(fileName: string, packageBumps: string[][], packages: string[]) {
let message = '';
for (const [pkg, bump] of packageBumps) {
message = message + `Updated dependency \`${pkg}\` to \`${bump}\`.\n`;
}
const pkgs = packages.map((pkg: string) => `'${pkg}': patch`).join('\n');
const body = `---\n${pkgs}\n---\n\n${message.trim()}\n`;
await fs.writeFile(fileName, body);
}
const addedFiles: string[] = [];
// Create changeset for each changed dependency
for (const { name, newVersion, projects } of dependencies) {
const safeName = name.replaceAll(/[^\w-]/g, '_').toLowerCase();
const fileName = `.changeset/${safeName}-${newVersion}.md`;
if (addedFiles.includes(fileName)) continue;
addedFiles.push(fileName);
const packageBumps = [[name, newVersion]];
const packages = projects;
await createChangeset(fileName, packageBumps, packages);
}
// Add changeset files to git
for (const fileName of addedFiles) await exec('git add ' + fileName);
// Commit changeset
await exec('git commit -C HEAD --amend --no-edit');
// Push changeset
await exec('git push --force');

3
tsconfig.json Normal file
View File

@ -0,0 +1,3 @@
{
"extends": "@bravo68web/tsconfig/base.json"
}

15
turbo.json Normal file
View File

@ -0,0 +1,15 @@
{
"$schema": "https://turbo.build/schema.json",
"pipeline": {
"build": {
"cache": true,
"outputs": ["**/dist"]
},
"lint": {
"cache": true,
"inputs": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"],
"outputs": ["**/.eslintcache"]
},
"test": {}
}
}