eslint-plugin-unslop 0.2.0 → 0.2.2

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
@@ -12,7 +12,7 @@ npm install --save-dev eslint-plugin-unslop
12
12
 
13
13
  ## Quick Start
14
14
 
15
- The recommended config enables the three most universal rules out of the box:
15
+ The recommended config enables the two most universal rules out of the box:
16
16
 
17
17
  ```js
18
18
  // eslint.config.mjs
@@ -27,7 +27,6 @@ This turns on:
27
27
  | --------------------------- | -------- | ------------------------------------------------------------------- |
28
28
  | `unslop/no-special-unicode` | error | Catches smart quotes, invisible spaces, and other unicode impostors |
29
29
  | `unslop/no-unicode-escape` | error | Prefers `"©"` over `"\u00A9"` |
30
- | `unslop/no-deep-imports` | error | Prevents importing too deep within the same top-level folder |
31
30
 
32
31
  The remaining rules need explicit configuration:
33
32
 
@@ -86,37 +85,55 @@ const copyright = '© 2025'
86
85
  const arrow = '→'
87
86
  ```
88
87
 
89
- ### `unslop/no-deep-imports`
88
+ ### `unslop/import-control`
90
89
 
91
- **Recommended**
90
+ Think of this as customs control for your modules — you declare which modules are allowed to import from which, and anything undeclared gets turned away at the border.
92
91
 
93
- Forbids importing more than one level deeper than the current file within the same top-level folder. If `features/auth/login.ts` imports from `features/auth/validators/internal/format.ts`, that's reaching too deep into implementation details. This rule nudges you toward flatter structures and proper module boundaries.
92
+ The rule reads from a shared policy in `settings.unslop.architecture`. It's deny-by-default for cross-module imports, which means forgetting to declare a dependency is a loud error rather than a silent free-for-all. It also enforces:
94
93
 
95
- Only triggers for imports within the same top-level folder. External packages and imports into other top-level folders are ignored.
94
+ - cross-module imports must arrive through the public gate (`index.ts` or `types.ts`)
95
+ - same-module relative imports can only go one level deeper — no tunnelling into internals
96
+ - files that don't match any declared module are denied (fail-closed, not fail-silently)
96
97
 
97
- #### Options
98
+ #### Configuration
98
99
 
99
100
  ```js
100
- ;['error', { sourceRoot: 'src' }]
101
- ```
102
-
103
- | Option | Type | Default | Description |
104
- | ------------ | -------- | ------------- | ----------------------------------------- |
105
- | `sourceRoot` | `string` | auto-detected | Source directory relative to project root |
106
-
107
- #### Examples
101
+ // eslint.config.mjs
102
+ import unslop from 'eslint-plugin-unslop'
108
103
 
109
- Given a project with `sourceRoot: 'src'`:
104
+ export default [
105
+ {
106
+ settings: {
107
+ unslop: {
108
+ sourceRoot: 'src',
109
+ architecture: {
110
+ utils: { shared: true },
111
+ 'repository/*': {
112
+ imports: ['utils', 'models/*'],
113
+ exports: ['^create\\w+Repo$', '^Repository[A-Z]\\w+$'],
114
+ },
115
+ 'models/*': {
116
+ imports: ['utils'],
117
+ },
118
+ app: {
119
+ imports: ['*'],
120
+ },
121
+ },
122
+ },
123
+ },
124
+ rules: {
125
+ 'unslop/import-control': 'error',
126
+ 'unslop/export-control': 'error',
127
+ },
128
+ },
129
+ ]
130
+ ```
110
131
 
111
- ```js
112
- // File: src/features/auth/login.ts
132
+ ### `unslop/export-control`
113
133
 
114
- // OK one level deep, same folder
115
- import { validate } from './validators/email.js'
134
+ The customs declaration form for the other direction: what are you actually exporting from your module's public entrypoints?
116
135
 
117
- // Badtwo levels deep into same top-level folder
118
- import { format } from './validators/internal/format.js'
119
- ```
136
+ When a module defines `exports` regex patterns in `settings.unslop.architecture`, every symbol exported from that module's `index.ts` or `types.ts` must match at least one pattern otherwise it's stopped at the gate with an error at the export site. Modules without `exports` are waved through by default, so you can adopt this gradually.
120
137
 
121
138
  ### `unslop/no-false-sharing`
122
139
 
@@ -273,6 +290,58 @@ Yes, a fair amount of this was vibe-coded with LLM assistance — which is fitti
273
290
 
274
291
  The project also dogfoods itself: `eslint-plugin-unslop` is linted using `eslint-plugin-unslop`.
275
292
 
293
+ ## Maintainer: Main Branch Protection
294
+
295
+ This repository treats `main` as a protected branch with pull-request-only merges.
296
+
297
+ Baseline policy:
298
+
299
+ - Require pull requests before merge
300
+ - Require at least 1 approving review
301
+ - Dismiss stale approvals when new commits are pushed
302
+ - Require branch to be up to date before merge
303
+ - Require status check: `PR Gate`
304
+ - Apply restrictions to admins too (`enforce_admins`)
305
+
306
+ The required check is produced by `.github/workflows/test.yml` (workflow/job name: `PR Gate`) and runs:
307
+
308
+ 1. `npm run verify`
309
+ 2. `npm run test`
310
+
311
+ ### Safe Workflow Renames
312
+
313
+ If you rename the workflow or job that produces `PR Gate`, update branch protection required checks immediately to match the new check context.
314
+
315
+ Recommended update command:
316
+
317
+ ```bash
318
+ gh api -X PUT repos/skhoroshavin/eslint-plugin-unslop/branches/main/protection \
319
+ -H "Accept: application/vnd.github+json" \
320
+ -F 'required_status_checks[strict]=true' \
321
+ -F 'required_status_checks[contexts][]=PR Gate' \
322
+ -F 'enforce_admins=true' \
323
+ -F 'required_pull_request_reviews[dismiss_stale_reviews]=true' \
324
+ -F 'required_pull_request_reviews[require_code_owner_reviews]=false' \
325
+ -F 'required_pull_request_reviews[required_approving_review_count]=1' \
326
+ -F 'restrictions=null'
327
+ ```
328
+
329
+ ### Branch Protection Audit
330
+
331
+ Run these checks periodically:
332
+
333
+ ```bash
334
+ gh api repos/skhoroshavin/eslint-plugin-unslop/branches/main/protection
335
+ gh run list --workflow "PR Gate" --limit 5
336
+ ```
337
+
338
+ Expected audit outcomes:
339
+
340
+ - `required_status_checks.contexts` includes `PR Gate`
341
+ - `required_pull_request_reviews.required_approving_review_count` is `1` or greater
342
+ - `required_pull_request_reviews.dismiss_stale_reviews` is `true`
343
+ - `enforce_admins.enabled` is `true`
344
+
276
345
  ## Contributing
277
346
 
278
347
  See [AGENTS.md](./AGENTS.md) for development setup and guidelines.