lintroll 0.0.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) Hiroki Osame <hiroki.osame@gmail.com>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,257 @@
1
+ <p align="center">
2
+ <img src="./.github/logo.webp" width="120">
3
+ </p>
4
+ <h2 align="center">
5
+ lintroll
6
+ <br>
7
+ <a href="https://npm.im/lintroll"><img src="https://badgen.net/npm/v/lintroll"></a>
8
+ </h2>
9
+
10
+ An opinionated JavaScript, TypeScript, Vue.js, React, etc. linter.
11
+
12
+ Powered by ESLint that's enhanced with 12 plugins, covering a wide scope including TypeScript, React, Vue.js, JSON & YAML, and even Markdown code blocks.
13
+
14
+ ### Features
15
+
16
+ - **Streamlined syntax**: Single quotes, semicolons, tabs, and [arrow functions](./src/custom-rules/prefer-arrow-functions/) for a clear & intentional coding style.
17
+
18
+ - **Versatile language support**: Lints TypeScript, Vue.js, React, JSON & YAML, and even Markdown code blocks ensuring a wide scope of code.
19
+
20
+ - **CLI command** Comes with a quick and easy-to-use CLI command, which even supports `eslint.config.ts`.
21
+
22
+ - **ESLint config**: Also exports an ESLint config so you can itegrate it into your own config!
23
+
24
+ ### What does the linted code look like?
25
+ Checkout the code fixtures from the passing tests [here](https://github.com/search?q=repo%3Aprivatenumber%2Feslint-config+path%3Atests%2F**%2Ffixtures%2Fpass*&type=code).
26
+
27
+ ## Install
28
+
29
+ ```sh
30
+ npm i -D lintroll
31
+ ```
32
+
33
+ ## Using as a CLI command
34
+
35
+ The `lintroll` command can be used as drop-in replacement for `eslint`, allowing you to lint your code with this config without any extra configuration.
36
+
37
+ #### Lint files in the current directory
38
+
39
+ ```sh
40
+ lintroll .
41
+ ```
42
+
43
+ #### Apply auto fix
44
+
45
+ ```sh
46
+ lintroll . --fix
47
+ ```
48
+
49
+ #### Lint with caching enabled
50
+ ```sh
51
+ lintroll --cache .
52
+ ```
53
+
54
+ #### Lint only staged files
55
+ ```sh
56
+ lintroll --staged .
57
+ ```
58
+
59
+ #### Specify Node.js files
60
+ ```sh
61
+ lintroll --node=./build .
62
+ ```
63
+
64
+ ### Optional `package.json` script
65
+
66
+ Adding it to `package.json#scripts` allows you to simply run `npm run lint` (or `pnpm lint`) without needing to pass in the current directory (`.`) every time.
67
+
68
+ This also follows the best practice of documenting available commands in a central place.
69
+
70
+ ```diff
71
+ "scripts": {
72
+ + "lint": "lintroll .",
73
+ "build": "..."
74
+ "dev": "..."
75
+ }
76
+ ```
77
+ ### Configuration
78
+
79
+ If you'd like to customize the linting rules further, you can add one of these ESLint config files to your project root and `lint` will detect them automatically:
80
+
81
+ - `eslint.config.ts`: The typed version of the configuration file, ideal if you are working with TypeScript.
82
+
83
+ - `eslint.config.js`: A standard JavaScript file for ESLint configuration, suitable for projects not using TypeScript.
84
+
85
+ > [!NOTE]
86
+ > When creating your own ESLint config file, you must manually add the `pvtnbr` config. Read the section below to learn how.
87
+
88
+ ### `--help`
89
+ ```
90
+ lintroll
91
+
92
+ by @privatenumber (Hiroki Osame)
93
+
94
+ Usage:
95
+ lintroll [flags...] <files...>
96
+
97
+ Flags:
98
+ --cache Only check changed files
99
+ --cache-location <string> Path to the cache file or directory
100
+ --fix Automatically fix problems
101
+ -h, --help Show help
102
+ --ignore-pattern <string> Pattern of files to ignore
103
+ --node <string> Enable Node.js rules. Pass in a glob to specify files
104
+ --quiet Report errors only
105
+ --staged Only lint staged files within the files passed in
106
+ ```
107
+
108
+ ## Using as an ESLint config
109
+
110
+ To use the `eslint` command, create a [flat configuration](https://eslint.org/docs/latest/use/configure/configuration-files-new) file `eslint.config.js` at your project root.
111
+
112
+ > [!TIP]
113
+ > If you'd like to use TypeScript for your config file (`eslint.config.ts`), use the `lint` command from the previous section. The `eslint` command only supports `eslint.config.js`.
114
+
115
+ ### Simple config
116
+ If you want a simple setup with no customization, create the following `eslint.config.js`:
117
+
118
+ Module:
119
+ ```js
120
+ export { default } from 'lintroll'
121
+ ```
122
+
123
+ CommonJS:
124
+ ```js
125
+ module.exports = require('lintroll')
126
+ ```
127
+
128
+ ### Extended config
129
+
130
+ In `eslint.config.js`:
131
+
132
+ Module:
133
+ ```js
134
+ // @ts-check
135
+
136
+ import { defineConfig, pvtnbr } from 'lintroll'
137
+
138
+ export default defineConfig([
139
+ {
140
+ // Don't lint these files
141
+ ignores: [
142
+ 'tests/fixtures/**/*'
143
+ ]
144
+ },
145
+
146
+ // Configure the pvtnbr config
147
+ ...pvtnbr({
148
+
149
+ // Indicate Node.js project
150
+ node: true,
151
+
152
+ // Indicate Vue.js project (auto-detected by default)
153
+ vue: true
154
+ })
155
+
156
+ // Other configs...
157
+ ])
158
+ ```
159
+
160
+ CommonJS:
161
+ ```js
162
+ // @ts-check
163
+
164
+ const { defineConfig, pvtnbr } = require('lintroll')
165
+
166
+ module.exports = defineConfig([
167
+ {
168
+ // Don't lint these files
169
+ ignores: [
170
+ 'tests/fixtures/**/*'
171
+ ]
172
+ },
173
+
174
+ // Configure the pvtnbr config
175
+ ...pvtnbr({
176
+
177
+ // Indicate Node.js project or pass in file paths
178
+ node: true
179
+ })
180
+
181
+ // Other configs...
182
+ ])
183
+ ```
184
+
185
+ > [!TIP]
186
+ > If you'd like to type check your `eslint.config.js` file, you can add [`// @ts-check`](https://www.typescriptlang.org/docs/handbook/intro-to-js-ts.html#ts-check) to the top.
187
+
188
+
189
+ ## Linting coverage
190
+
191
+ This ESLint config comprehensively supports a variety of languages and file types, ensuring coding standards and best practices across your project.
192
+
193
+ | Language/File Type | Extensions |
194
+ | ------------------ | -------------------- |
195
+ | JavaScript | `.js`, `.cjs`, `.mjs` |
196
+ | Node.js | `.cjs`, `.mjs` |
197
+ | Service Workers | `.sw.js`, `.sw.ts` |
198
+ | TypeScript | `.ts`, `.cts`, `.mts`, `.d.ts` |
199
+ | Vue.js | `.vue` |
200
+ | React | `.jsx`, `.tsx` |
201
+ | JSON | `.json`, `.json5`, `.jsonc` |
202
+ | YML | `.yml`, `.yaml` |
203
+ | Markdown | `.md` |
204
+
205
+
206
+ ### Integrated plugins
207
+
208
+ Each plugin in this ESLint configuration targets specific aspects of your code, ensuring quality and consistency.
209
+
210
+ | Plugin | Focus area |
211
+ | ------ | ---------- |
212
+ | [eslint-comments](https://www.npmjs.com/package/@eslint-community/eslint-plugin-eslint-comments) | ESLint directive comments |
213
+ | [node](https://www.npmjs.com/package/eslint-plugin-node) | Node.js coding practices |
214
+ | [@typescript-eslint](https://www.npmjs.com/package/@typescript-eslint/eslint-plugin) | TypeScript coding Practices |
215
+ | [@stylistic](https://www.npmjs.com/package/@stylistic/eslint-plugin) | JavaScript & TypeScript code style |
216
+ | [promise](https://www.npmjs.com/package/eslint-plugin-promise) | Promises best practices |
217
+ | [regexp](https://www.npmjs.com/package/eslint-plugin-regexp) | Regular Expressions best practices |
218
+ | [import](https://www.npmjs.com/package/eslint-plugin-import) | ES6+ Import/Export |
219
+ | [jsonc](https://www.npmjs.com/package/eslint-plugin-jsonc) | JSON, JSON5, and JSONC style |
220
+ | [yml](https://www.npmjs.com/package/eslint-plugin-yml) | YAML style |
221
+ | [vue](https://www.npmjs.com/package/eslint-plugin-vue) | Vue.js Templates & Scripts |
222
+ | [react](https://www.npmjs.com/package/eslint-plugin-react) <!--& [react-hooks](https://www.npmjs.com/package/eslint-plugin-react-hooks)--> | React best practices<!--& React Hooks--> |
223
+ | [markdown](https://www.npmjs.com/package/eslint-plugin-markdown) | Markdown embedded code blocks |
224
+ | [no-use-extend-native](https://www.npmjs.com/package/eslint-plugin-no-use-extend-native) | Native prototype extensions |
225
+ | [unicorn](https://www.npmjs.com/package/eslint-plugin-unicorn) | Miscellaneous code quality rules |
226
+ | [Custom](https://github.com/privatenumber/eslint-config/tree/develop/src/custom-rules) | Custom rules made for this config |
227
+
228
+ ## API
229
+
230
+ ### pvtbr(options)
231
+
232
+ The main config factory. It takes an object of options and returns a config object.
233
+
234
+ #### options.node
235
+
236
+ Type: `boolean | string[]`
237
+
238
+ Default: `false`
239
+
240
+ Whether to lint Node.js code. When `true`, it will treat all files as Node.js files. You can also pass in an array of glob patterns to specify which files are Node.js files.
241
+
242
+ ### defineConfig(configs)
243
+
244
+ An identity function to enforce type checking on the config.
245
+
246
+ #### configs
247
+
248
+ Type: `FlatConfig | FlatConfig[]`
249
+
250
+ ## Awesome ESLint configs
251
+
252
+ Make sure you also check out these awesome ESLint configs. They are a constant source of inspiration for me, and are great alternatives to consider.
253
+
254
+ - [antfu/eslint-config](https://github.com/antfu/eslint-config) by [@antfu](https://github.com/antfu)
255
+ - [sxzz/eslint-config](https://github.com/sxzz/eslint-config) by [@sxzz](https://github.com/sxzz)
256
+ - [@ota-meshi/eslint-plugin](https://github.com/ota-meshi/eslint-plugin) by [@ota-meshi](https://github.com/ota-meshi)
257
+ - [standard config](https://github.com/standard/eslint-config-standard) by [@feross](https://github.com/feross)
@@ -0,0 +1,2 @@
1
+ "use strict";require("tsx/esm");var c=require("path"),h=require("cleye"),y=require("eslint/use-at-your-own-risk"),f=require("execa"),l=require("../index-DRoRpPeV.cjs"),m=require("url"),v=require("fs/promises");require("@eslint/js"),require("globals"),require("confusing-browser-globals"),require("module"),require("@eslint-community/eslint-plugin-eslint-comments"),require("@stylistic/eslint-plugin"),require("eslint-plugin-import-x"),require("@typescript-eslint/eslint-plugin"),require("@typescript-eslint/parser"),require("eslint-plugin-regexp"),require("node:fs"),require("eslint-plugin-n"),require("node:path"),require("../index-BsUJzcDL.cjs"),require("node:process"),require("node:fs/promises"),require("node:url"),require("tty"),require("os"),require("util"),require("eslint-plugin-promise"),require("eslint-plugin-markdown"),require("eslint-plugin-jsonc"),require("eslint-plugin-yml"),require("yaml-eslint-parser"),require("eslint-plugin-no-use-extend-native"),require("eslint-plugin-unicorn"),require("eslint-plugin-react"),require("eslint-plugin-react-hooks"),require("get-tsconfig"),require("fs"),require("eslint-plugin-vue"),require("vue-eslint-parser"),require("eslint");const g=async e=>v.access(e).then(()=>e,()=>{}),w=async e=>{const r=await g("eslint.config.ts")??await g("eslint.config.js");if(r){const t=await import(m.pathToFileURL(r).toString());if(t.default)return console.log(`[${l.name}]: Using config file: ${r}`),t.default}return l.pvtnbr(e)},x=e=>{let r=0,t=0,o=0;for(const n of e)r+=n.errorCount,t+=n.fatalErrorCount,o+=n.warningCount;return{errorCount:r,fatalErrorCount:t,warningCount:o}},C=e=>e.fatalErrorCount>0?2:e.errorCount>0?1:0,i=h.cli({name:l.name,parameters:["<files...>"],help:{description:"Opinionated ESLint by @privatenumber (Hiroki Osame)"},flags:{fix:{type:Boolean,description:"Automatically fix problems"},staged:{type:Boolean,description:"Only lint staged files within the files passed in"},quiet:{type:Boolean,description:"Report errors only"},cache:{type:Boolean,description:"Only check changed files"},cacheLocation:{type:String,description:"Path to the cache file or directory"},ignorePattern:{type:[String],description:"Pattern of files to ignore"},node:{type:[String],description:"Enable Node.js rules. Pass in a glob to specify files"}}}),E=e=>{if(e.length===0)return!1;const r=e.filter(t=>t.length>0);return r.length>0?r:!0};(async()=>{const{FlatESLint:e}=y,r=new e({baseConfig:await w({node:E(i.flags.node)}),overrideConfigFile:!0,fix:i.flags.fix,cache:i.flags.cache,cacheLocation:i.flags.cacheLocation,ignorePatterns:i.flags.ignorePattern});let t=i._.files.map(s=>c.resolve(s));if(i.flags.staged)try{const{stdout:s}=await f.execa("git",["rev-parse","--show-toplevel"]),{stdout:d}=await f.execa("git",["diff","--staged","--name-only","--diff-filter=ACMR"]);t=d.split(`
2
+ `).filter(Boolean).map(a=>c.resolve(s,a)).filter(a=>t.some(p=>a.startsWith(p)))}catch{console.error("Error: Failed to detect staged files from git"),process.exit(1)}const o=await r.lintFiles(t);i.flags.fix&&await e.outputFixes(o);let n=o;i.flags.quiet&&(n=e.getErrorResults(o));const q=x(o),u=await(await r.loadFormatter()).format(n);u&&console.log(u),process.exitCode=C(q)})();
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ import"tsx/esm";import p from"path";import{cli as h}from"cleye";import y from"eslint/use-at-your-own-risk";import{execa as c}from"execa";import{n as f,p as w}from"../index-jdY9gLh9.mjs";import{pathToFileURL as C}from"url";import x from"fs/promises";import"@eslint/js";import"globals";import"confusing-browser-globals";import"module";import"@eslint-community/eslint-plugin-eslint-comments";import"@stylistic/eslint-plugin";import"eslint-plugin-import-x";import"@typescript-eslint/eslint-plugin";import"@typescript-eslint/parser";import"eslint-plugin-regexp";import"node:fs";import"eslint-plugin-n";import"node:path";import"../index-DW7ozoHd.mjs";import"node:process";import"node:fs/promises";import"node:url";import"tty";import"os";import"util";import"eslint-plugin-promise";import"eslint-plugin-markdown";import"eslint-plugin-jsonc";import"eslint-plugin-yml";import"yaml-eslint-parser";import"eslint-plugin-no-use-extend-native";import"eslint-plugin-unicorn";import"eslint-plugin-react";import"eslint-plugin-react-hooks";import"get-tsconfig";import"fs";import"eslint-plugin-vue";import"vue-eslint-parser";import"eslint";const m=async t=>x.access(t).then(()=>t,()=>{}),E=async t=>{const o=await m("eslint.config.ts")??await m("eslint.config.js");if(o){const e=await import(C(o).toString());if(e.default)return console.log(`[${f}]: Using config file: ${o}`),e.default}return w(t)},F=t=>{let o=0,e=0,r=0;for(const n of t)o+=n.errorCount,e+=n.fatalErrorCount,r+=n.warningCount;return{errorCount:o,fatalErrorCount:e,warningCount:r}},b=t=>t.fatalErrorCount>0?2:t.errorCount>0?1:0,i=h({name:f,parameters:["<files...>"],help:{description:"Opinionated ESLint by @privatenumber (Hiroki Osame)"},flags:{fix:{type:Boolean,description:"Automatically fix problems"},staged:{type:Boolean,description:"Only lint staged files within the files passed in"},quiet:{type:Boolean,description:"Report errors only"},cache:{type:Boolean,description:"Only check changed files"},cacheLocation:{type:String,description:"Path to the cache file or directory"},ignorePattern:{type:[String],description:"Pattern of files to ignore"},node:{type:[String],description:"Enable Node.js rules. Pass in a glob to specify files"}}}),v=t=>{if(t.length===0)return!1;const o=t.filter(e=>e.length>0);return o.length>0?o:!0};(async()=>{const{FlatESLint:t}=y,o=new t({baseConfig:await E({node:v(i.flags.node)}),overrideConfigFile:!0,fix:i.flags.fix,cache:i.flags.cache,cacheLocation:i.flags.cacheLocation,ignorePatterns:i.flags.ignorePattern});let e=i._.files.map(s=>p.resolve(s));if(i.flags.staged)try{const{stdout:s}=await c("git",["rev-parse","--show-toplevel"]),{stdout:d}=await c("git",["diff","--staged","--name-only","--diff-filter=ACMR"]);e=d.split(`
3
+ `).filter(Boolean).map(a=>p.resolve(s,a)).filter(a=>e.some(u=>a.startsWith(u)))}catch{console.error("Error: Failed to detect staged files from git"),process.exit(1)}const r=await o.lintFiles(e);i.flags.fix&&await t.outputFixes(r);let n=r;i.flags.quiet&&(n=t.getErrorResults(r));const g=F(r),l=await(await o.loadFormatter()).format(n);l&&console.log(l),process.exitCode=b(g)})();
@@ -0,0 +1 @@
1
+ "use strict";var l=require("node:process");require("node:fs/promises");var u=require("node:url"),d=require("node:fs"),i=require("node:path");const f=r=>r instanceof URL?u.fileURLToPath(r):r;function y(r,{cwd:a=l.cwd(),type:o="file",stopAt:t}={}){let e=i.resolve(f(a)??"");const{root:s}=i.parse(e);for(t=i.resolve(e,f(t)??s);e&&e!==t&&e!==s;){const c=i.isAbsolute(r)?r:i.join(e,r);try{const n=d.statSync(c,{throwIfNoEntry:!1});if(o==="file"&&n?.isFile()||o==="directory"&&n?.isDirectory())return c}catch{}e=i.dirname(e)}}exports.findUpSync=y;