@gesslar/uglier 0.0.4 → 0.0.6

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/README.md CHANGED
@@ -1,9 +1,8 @@
1
1
  # @gesslar/uglier
2
2
 
3
- Composable ESLint flat config blocks you can mix and match for stylistic
4
- linting, JSDoc enforcement, and environment presets.
3
+ **Opinionated, composable ESLint flat config for people who like their code readable.**
5
4
 
6
- Uses [ESLint's flat config format](https://eslint.org/docs/latest/use/configure/configuration-files).
5
+ A flexible ESLint configuration system built on [flat config](https://eslint.org/docs/latest/use/configure/configuration-files) that lets you mix and match stylistic rules, JSDoc enforcement, and environment presets.
7
6
 
8
7
  ## Monotribe
9
8
 
@@ -28,87 +27,78 @@ kthx
28
27
 
29
28
  \[cat.gif\]
30
29
 
31
- ## Install
30
+ ## Quick Start
32
31
 
33
- ### Quick Install (Recommended)
32
+ ```bash
33
+ # Install and set up in one command
34
+ npx @gesslar/uglier init node
34
35
 
35
- The easiest way to install `@gesslar/uglier` and all its dependencies:
36
+ # Or for React projects
37
+ npx @gesslar/uglier init react
36
38
 
37
- ```sh
39
+ # Or just install without config generation
38
40
  npx @gesslar/uglier
39
41
  ```
40
42
 
41
- This will automatically install:
43
+ This automatically installs `@gesslar/uglier`, `eslint`, and all dependencies.
42
44
 
43
- - `@gesslar/uglier`
44
- - `eslint` (if not already installed)
45
- - `@stylistic/eslint-plugin`
46
- - `eslint-plugin-jsdoc`
47
- - `globals`
48
-
49
- ### Manual Install
50
-
51
- If you prefer to install manually:
45
+ ## Usage
52
46
 
53
- ```sh
54
- npm install --save-dev @gesslar/uglier eslint @stylistic/eslint-plugin eslint-plugin-jsdoc globals
55
- ```
47
+ ### Generated Config
56
48
 
57
- ### View Available Configs
49
+ Running `init` creates an `eslint.config.js` with helpful comments:
58
50
 
59
- To see all available config blocks:
51
+ ```js
52
+ import uglify from "@gesslar/uglier"
60
53
 
61
- ```sh
62
- npx @gesslar/uglier --help
54
+ export default [
55
+ ...uglify({
56
+ with: [
57
+ "lints-js", // default files: ["**/*.{js,mjs,cjs}"]
58
+ "lints-jsdoc", // default files: ["**/*.{js,mjs,cjs}"]
59
+ "node", // default files: ["**/*.{js,mjs,cjs}"]
60
+ ]
61
+ })
62
+ ]
63
63
  ```
64
64
 
65
- ## Usage
65
+ ### Common Scenarios
66
66
 
67
- ### Basic Setup
67
+ #### Node.js Project
68
68
 
69
69
  ```js
70
- // eslint.config.js
71
- import uglify from "@gesslar/uglier"
72
-
73
70
  export default [
74
71
  ...uglify({
75
- with: ["lints-js", "lints-jsdoc"]
72
+ with: ["lints-js", "node"]
76
73
  })
77
74
  ]
78
75
  ```
79
76
 
80
- ### Excluding Configs
81
-
82
- Use `without` to exclude specific configs:
77
+ #### React Project
83
78
 
84
79
  ```js
85
80
  export default [
86
81
  ...uglify({
87
- with: ["lints-js", "lints-jsdoc", "node"],
88
- without: ["lints-jsdoc"] // Remove JSDoc rules
82
+ with: ["lints-js", "react"]
89
83
  })
90
84
  ]
91
85
  ```
92
86
 
93
- ### Customizing File Patterns
94
-
95
- Override file patterns for specific configs:
87
+ #### Monorepo (Node + Web)
96
88
 
97
89
  ```js
98
90
  export default [
99
91
  ...uglify({
100
- with: ["lints-js", "lints-jsdoc", "tauri"],
92
+ with: ["lints-js", "node", "web"],
101
93
  overrides: {
102
- "lints-js": { files: ["src/**/*.js"] },
103
- "tauri": { files: ["src/**/*.js"] }
94
+ "node": { files: ["server/**/*.js"] },
95
+ "web": { files: ["client/**/*.js"] }
104
96
  }
105
97
  })
106
98
  ]
107
99
  ```
108
100
 
109
- ### Customizing Style Rules
110
-
111
- Override indent, maxLen, or specific rules:
101
+ #### Custom Style Preferences
112
102
 
113
103
  ```js
114
104
  export default [
@@ -116,8 +106,8 @@ export default [
116
106
  with: ["lints-js"],
117
107
  overrides: {
118
108
  "lints-js": {
119
- indent: 4, // Default: 2
120
- maxLen: 120, // Default: 80
109
+ indent: 4, // default: 2
110
+ maxLen: 120, // default: 80
121
111
  overrides: {
122
112
  "@stylistic/semi": ["error", "always"]
123
113
  }
@@ -127,36 +117,77 @@ export default [
127
117
  ]
128
118
  ```
129
119
 
120
+ #### Exclude JSDoc Requirements
121
+
122
+ ```js
123
+ export default [
124
+ ...uglify({
125
+ with: ["lints-js", "lints-jsdoc", "node"],
126
+ without: ["lints-jsdoc"]
127
+ })
128
+ ]
129
+ ```
130
+
130
131
  ## Available Configs
131
132
 
132
- ### Linting
133
+ ### Linting Rules
133
134
 
134
- - **`lints-js`** - Core stylistic rules (indent, spacing, quotes, etc.)
135
+ - **`lints-js`** - Stylistic rules (indent, spacing, quotes, braces, etc.)
135
136
  - **`lints-jsdoc`** - JSDoc documentation requirements
136
137
 
137
- ### Language
138
+ ### Environment Targets
138
139
 
139
- - **`languageOptions`** - Base ECMAScript language configuration
140
+ - **`node`** - Node.js globals (process, Buffer, etc.)
141
+ - **`web`** - Browser globals (window, document, etc.)
142
+ - **`react`** - React environment (browser + React/ReactDOM)
143
+ - **`tauri`** - Tauri apps (browser + `__TAURI__` APIs)
144
+ - **`vscode-extension`** - VSCode extension API
140
145
 
141
- ### Environments
146
+ ### Utilities
142
147
 
143
- - **`web`** - Browser globals (window, document, etc.)
144
- - **`node`** - Node.js globals (process, require, fetch, Headers)
145
- - **`tauri`** - Tauri app globals (browser + `__TAURI__`)
146
- - **`vscode-extension`** - VSCode extension API (acquireVsCodeApi)
148
+ - **`languageOptions`** - ECMAScript language settings
149
+ - **`cjs-override`** - CommonJS file handling (`.cjs`)
150
+ - **`mjs-override`** - ES Module file handling (`.mjs`)
147
151
 
148
- ### Module Overrides
152
+ Run `npx @gesslar/uglier --help` to see all available configs with descriptions.
149
153
 
150
- - **`cjs-override`** - CommonJS file handling (.cjs files)
151
- - **`mjs-override`** - ES Module file handling (.mjs files)
154
+ ## Commands
152
155
 
153
- You can also access the config names programmatically:
156
+ ```bash
157
+ # Install dependencies only
158
+ npx @gesslar/uglier
154
159
 
155
- ```js
156
- import {availableConfigs} from "@gesslar/uglier"
157
- console.log(availableConfigs)
160
+ # Generate config for specific targets
161
+ npx @gesslar/uglier init node
162
+ npx @gesslar/uglier init web
163
+ npx @gesslar/uglier init react
164
+ npx @gesslar/uglier init node web # Multiple targets
165
+
166
+ # Show available configs
167
+ npx @gesslar/uglier --help
168
+ ```
169
+
170
+ ## Manual Installation
171
+
172
+ If you prefer manual control:
173
+
174
+ ```bash
175
+ npm install --save-dev @gesslar/uglier eslint
158
176
  ```
159
177
 
178
+ Note: `@stylistic/eslint-plugin`, `eslint-plugin-jsdoc`, and `globals` are bundled as dependencies.
179
+
180
+ ## Philosophy
181
+
182
+ This config enforces:
183
+
184
+ - **Readable spacing** - Blank lines between control structures
185
+ - **Consistent style** - Double quotes, no semicolons, 2-space indent
186
+ - **Flexible customization** - Override anything via the `overrides` option
187
+ - **Composability** - Mix configs for different file patterns in the same project
188
+
189
+ It's opinionated, but you can override any rule. The defaults just happen to be correct. 😉
190
+
160
191
  ## License
161
192
 
162
- [Unlicense](UNLICENSE.txt) - "Because you're worth it." (- someone. maybe? idfk)
193
+ [Unlicense](https://unlicense.org/) - Public domain. Do whatever you want.
package/bin/install.js CHANGED
@@ -1,16 +1,24 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  /**
4
- * @file install.js - Auto-installer for @gesslar/uglier
4
+ * @file install.js - Auto-installer and config generator for @gesslar/uglier
5
5
  *
6
6
  * @description
7
7
  * This script can be run via `npx @gesslar/uglier` to automatically install
8
- * the package and all its dependencies to the current project.
8
+ * the package and its peer dependencies to the current project.
9
9
  *
10
- * It will:
10
+ * Commands:
11
+ * - npx @gesslar/uglier - Install package and dependencies
12
+ * - npx @gesslar/uglier init - Generate eslint.config.js with prompts
13
+ * - npx @gesslar/uglier init node - Generate eslint.config.js for Node.js
14
+ * - npx @gesslar/uglier --help - Show help
15
+ *
16
+ * Installation does:
11
17
  * 1. Install @gesslar/uglier as a dev dependency
12
18
  * 2. Install eslint as a peer dependency (if not present)
13
- * 3. Install all required plugins as dev dependencies
19
+ *
20
+ * Note: All other dependencies (@stylistic/eslint-plugin, eslint-plugin-jsdoc, globals)
21
+ * are bundled with the package and don't need to be installed separately.
14
22
  */
15
23
 
16
24
  import {execSync} from "child_process"
@@ -24,13 +32,8 @@ const __dirname = dirname(__filename)
24
32
 
25
33
  const PACKAGE_NAME = "@gesslar/uglier"
26
34
 
27
- // Dependencies that need to be installed
28
- const REQUIRED_DEPS = [
29
- "@stylistic/eslint-plugin",
30
- "eslint-plugin-jsdoc",
31
- "globals"
32
- ]
33
-
35
+ // Only peer dependencies need to be installed separately
36
+ // (all other dependencies come bundled with the package)
34
37
  const PEER_DEPS = [
35
38
  "eslint"
36
39
  ]
@@ -52,7 +55,7 @@ function exec(cmd) {
52
55
 
53
56
  /**
54
57
  * Get available configs from the source file
55
- * @returns {Promise<Array<{name: string, description: string}>|null>} Available configs
58
+ * @returns {Promise<Array<{name: string, description: string, files: string}>|null>} Available configs
56
59
  */
57
60
  async function getAvailableConfigs() {
58
61
  try {
@@ -77,16 +80,17 @@ async function getAvailableConfigs() {
77
80
 
78
81
  const source = await uglierFile.read()
79
82
 
80
- // Extract config names and their JSDoc descriptions
83
+ // Extract config names, descriptions, and default files
81
84
  const configs = []
82
85
  // Match individual config blocks within CONFIGS object
83
- const configBlockRegex = /\/\*\*\s*\n\s*\*\s*([^\n@*]+?)\s*\n(?:\s*\*[^\n]*\n)*?\s*\*\/\s*\n\s*["']([^"']+)["']:\s*\([^)]*\)\s*=>/g
86
+ const configBlockRegex = /\/\*\*\s*\n\s*\*\s*([^\n@*]+?)\s*\n(?:\s*\*[^\n]*\n)*?\s*\*\/\s*\n\s*["']([^"']+)["']:\s*\([^)]*\)\s*=>\s*\{[^}]*?files\s*=\s*(\[[^\]]+\])/g
84
87
  let match
85
88
 
86
89
  while((match = configBlockRegex.exec(source)) !== null) {
87
90
  configs.push({
88
91
  name: match[2],
89
- description: match[1].trim()
92
+ description: match[1].trim(),
93
+ files: match[3]
90
94
  })
91
95
  }
92
96
 
@@ -105,8 +109,10 @@ async function showHelp() {
105
109
  console.log()
106
110
  console.log("Usage:")
107
111
  console.log()
108
- console.log(c` {<B}npx @gesslar/uglier{B>} Install package and dependencies`)
109
- console.log(c` {<B}npx @gesslar/uglier --help{B>} Show this help`)
112
+ console.log(c` {<B}npx @gesslar/uglier{B>} Install package and dependencies`)
113
+ console.log(c` {<B}npx @gesslar/uglier init{B>} Generate eslint.config.js interactively`)
114
+ console.log(c` {<B}npx @gesslar/uglier init <targets>{B>} Generate eslint.config.js with targets`)
115
+ console.log(c` {<B}npx @gesslar/uglier --help{B>} Show this help`)
110
116
  console.log()
111
117
 
112
118
  const configs = await getAvailableConfigs()
@@ -178,18 +184,9 @@ async function install() {
178
184
  }
179
185
  }
180
186
 
181
- // Check required dependencies
182
- for(const dep of REQUIRED_DEPS) {
183
- if(!(await isInstalled(dep))) {
184
- toInstall.push(dep)
185
- } else {
186
- console.log(c`{F070}✓{/} {<B}${dep}{B>} already installed`)
187
- }
188
- }
189
-
190
187
  // Install missing packages
191
188
  if(toInstall.length > 0) {
192
- console.log(c`\n{F027} Installing:{/} ${toInstall.map(p => c`{F172}${p}{/}`).join(", ")}\n`)
189
+ console.log(c`\n{F027} Installing:{/} ${toInstall.map(p => c`{F172}${p}{/}`).join(", ")}`)
193
190
 
194
191
  const installCmd = `npm install -D ${toInstall.join(" ")}`
195
192
 
@@ -205,11 +202,104 @@ async function install() {
205
202
  console.log(c`https://github.com/gesslar/uglier#readme`)
206
203
  }
207
204
 
205
+ /**
206
+ * Generate eslint.config.js file
207
+ * @param {string[]} targets - Target environments (node, web, react, etc.)
208
+ */
209
+ async function generateConfig(targets = []) {
210
+ const configFile = new FileObject("eslint.config.js", process.cwd())
211
+
212
+ if(await configFile.exists) {
213
+ console.log(c`{F214}Warning:{/} {<B}eslint.config.js{B>} already exists`)
214
+ console.log(c`Delete it first or edit it manually`)
215
+
216
+ return
217
+ }
218
+
219
+ // Get available configs dynamically
220
+ const configs = await getAvailableConfigs()
221
+ const environmentTargets = configs
222
+ ? configs.filter(c => !c.name.startsWith("lints-") && c.name !== "languageOptions" && !c.name.endsWith("-override"))
223
+ .map(c => c.name)
224
+ : ["node", "web", "react", "tauri", "vscode-extension"]
225
+
226
+ // If no targets specified, make it interactive
227
+ if(targets.length === 0) {
228
+ console.log(c`{F027}Choose your target environments:{/}`)
229
+ console.log()
230
+ console.log(c`Available targets: ${environmentTargets.map(t => c`{F172}${t}{/}`).join(", ")}`)
231
+ console.log()
232
+ console.log(c`{F244}Example: npx @gesslar/uglier init ${environmentTargets[0] || "node"}{/}`)
233
+
234
+ return
235
+ }
236
+
237
+ // Validate targets
238
+ const validTargets = environmentTargets
239
+ const invalidTargets = targets.filter(t => !validTargets.includes(t))
240
+
241
+ if(invalidTargets.length > 0) {
242
+ console.log(c`{F214}Error:{/} Invalid targets: {F172}${invalidTargets.join(", ")}{/}`)
243
+ console.log(c`Valid targets: {F070}${validTargets.join(", ")}{/}`)
244
+
245
+ return
246
+ }
247
+
248
+ // Build the config with comments
249
+ const withArray = ["lints-js", "lints-jsdoc", ...targets]
250
+
251
+ // Get file patterns dynamically from source
252
+ const allConfigs = await getAvailableConfigs()
253
+ const filePatterns = {}
254
+
255
+ if(allConfigs) {
256
+ for(const config of allConfigs) {
257
+ filePatterns[config.name] = config.files
258
+ }
259
+ }
260
+
261
+ // Build the with array with comments
262
+ const withLines = withArray.map(target => {
263
+ const pattern = filePatterns[target] || "[]"
264
+
265
+ return ` "${target}", // default files: ${pattern}`
266
+ }).join("\n")
267
+
268
+ const configContent = `import uglify from "@gesslar/uglier"
269
+
270
+ export default [
271
+ ...uglify({
272
+ with: [
273
+ ${withLines}
274
+ ]
275
+ })
276
+ ]
277
+ `
278
+
279
+ await configFile.write(configContent)
280
+
281
+ console.log(c`{F070}✓{/} Created {<B}eslint.config.js{B>}`)
282
+ console.log()
283
+ console.log(c`{F039}Configuration includes:{/}`)
284
+
285
+ for(const target of withArray) {
286
+ console.log(c` {F070}•{/} ${target}`)
287
+ }
288
+
289
+ console.log()
290
+ console.log(c`{F244}Run {<B}npx eslint .{B>} to lint your project{/}`)
291
+ }
292
+
208
293
  // Parse command line arguments and run
209
294
  const args = process.argv.slice(2)
210
295
 
211
296
  if(args.includes("--help") || args.includes("-h")) {
212
297
  await showHelp()
298
+ } else if(args[0] === "init") {
299
+ const targets = args.slice(1)
300
+
301
+ await install()
302
+ await generateConfig(targets)
213
303
  } else {
214
304
  await install()
215
305
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gesslar/uglier",
3
- "version": "0.0.4",
3
+ "version": "0.0.6",
4
4
  "description": "Composable ESLint flat config blocks for stylistic, JSDoc, and environment presets.",
5
5
  "type": "module",
6
6
  "main": "src/uglier.js",
@@ -25,7 +25,7 @@
25
25
  "cat.gif"
26
26
  ],
27
27
  "scripts": {
28
- "submit": "npm publish --access public",
28
+ "submit": "npm login && npm publish --access public",
29
29
  "update": "npx npm-check-updates -u && npm install",
30
30
  "pr": "gt submit --publish --restack --ai"
31
31
  },
@@ -34,11 +34,13 @@
34
34
  "eslint": "^9.0.0"
35
35
  },
36
36
  "dependencies": {
37
- "@stylistic/eslint-plugin": "^5.6.1",
38
- "eslint-plugin-jsdoc": "^61.4.0",
39
- "globals": "^16.5.0",
40
37
  "@gesslar/colours": "^0.0.1",
41
- "@gesslar/toolkit": "^0.8.0"
38
+ "@gesslar/toolkit": "^1.10.0",
39
+ "@stylistic/eslint-plugin": "^5.6.1",
40
+ "eslint-plugin-jsdoc": "^61.5.0",
41
+ "globals": "^16.5.0"
42
42
  },
43
- "devDependencies": {}
43
+ "devDependencies": {
44
+ "@gesslar/uglier": "^0.0.5"
45
+ }
44
46
  }
package/src/uglier.js CHANGED
@@ -66,6 +66,7 @@
66
66
  * - languageOptions: Base ECMAScript language configuration
67
67
  * - web: Browser globals (window, document, etc.)
68
68
  * - node: Node.js globals (process, require, fetch, Headers)
69
+ * - react: React globals (browser + React, ReactDOM)
69
70
  * - tauri: Tauri app globals (browser + __TAURI__)
70
71
  * - vscode-extension: VSCode extension API (acquireVsCodeApi)
71
72
  * - cjs-override: CommonJS file handling (.cjs files)
@@ -171,7 +172,7 @@ const CONFIGS = {
171
172
  }],
172
173
  "@stylistic/quotes": ["error", "double", {
173
174
  avoidEscape: true,
174
- allowTemplateLiterals: true,
175
+ allowTemplateLiterals: "always",
175
176
  }],
176
177
  "@stylistic/semi": ["error", "never"],
177
178
  "@stylistic/space-before-function-paren": ["error", "never"],
@@ -317,6 +318,31 @@ const CONFIGS = {
317
318
  }
318
319
  },
319
320
 
321
+ /**
322
+ * React application globals
323
+ * @param {object} options - Configuration options
324
+ * @returns {object} Config object
325
+ */
326
+ "react": (options = {}) => {
327
+ const {
328
+ files = ["src/**/*.{js,jsx,mjs,cjs}"],
329
+ additionalGlobals = {},
330
+ } = options
331
+
332
+ return {
333
+ name: "gesslar/uglier/react",
334
+ files: Array.isArray(files) ? files : [files],
335
+ languageOptions: {
336
+ globals: {
337
+ ...globals.browser,
338
+ React: "readonly",
339
+ ReactDOM: "readonly",
340
+ ...additionalGlobals,
341
+ }
342
+ }
343
+ }
344
+ },
345
+
320
346
  /**
321
347
  * CommonJS file override
322
348
  * @param {object} options - Configuration options