@pjts/eslint-style-rules 0.0.8 → 0.0.9
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 +21 -0
- package/README.md +38 -8
- package/dist/index.js +35 -4
- package/dist/index.js.map +1 -1
- package/dist/lib/ast.d.ts +27 -13
- package/dist/lib/ast.js +33 -7
- package/dist/lib/ast.js.map +1 -1
- package/dist/lib/db.d.ts +5 -4
- package/dist/lib/db.js +2 -2
- package/dist/lib/db.js.map +1 -1
- package/dist/lib/rule.d.ts +8 -6
- package/dist/lib/rule.js +3 -3
- package/dist/lib/rule.js.map +1 -1
- package/dist/lib/types.d.ts +69 -0
- package/dist/lib/types.js +270 -0
- package/dist/lib/types.js.map +1 -0
- package/dist/lib/wiring.d.ts +5 -3
- package/dist/lib/wiring.js +8 -4
- package/dist/lib/wiring.js.map +1 -1
- package/dist/rules/app-class-suffix.d.ts +1 -1
- package/dist/rules/app-class-suffix.js +1 -1
- package/dist/rules/app-class-suffix.js.map +1 -1
- package/dist/rules/app-service-endpoints.d.ts +3 -1
- package/dist/rules/app-service-endpoints.js +9 -8
- package/dist/rules/app-service-endpoints.js.map +1 -1
- package/dist/rules/auth-access.d.ts +2 -2
- package/dist/rules/auth-access.js +11 -10
- package/dist/rules/auth-access.js.map +1 -1
- package/dist/rules/config-provider-only.d.ts +1 -1
- package/dist/rules/config-provider-only.js +5 -3
- package/dist/rules/config-provider-only.js.map +1 -1
- package/dist/rules/db-client-dependency.d.ts +1 -1
- package/dist/rules/db-client-dependency.js +11 -7
- package/dist/rules/db-client-dependency.js.map +1 -1
- package/dist/rules/db-writes-in-repositories.d.ts +1 -1
- package/dist/rules/db-writes-in-repositories.js +12 -8
- package/dist/rules/db-writes-in-repositories.js.map +1 -1
- package/dist/rules/decorated-class-contract.d.ts +1 -1
- package/dist/rules/decorated-class-contract.js +1 -1
- package/dist/rules/decorated-class-contract.js.map +1 -1
- package/dist/rules/domain-primitive-params.d.ts +17 -0
- package/dist/rules/domain-primitive-params.js +116 -0
- package/dist/rules/domain-primitive-params.js.map +1 -0
- package/dist/rules/entity-constructor-data.d.ts +1 -1
- package/dist/rules/entity-constructor-data.js +4 -3
- package/dist/rules/entity-constructor-data.js.map +1 -1
- package/dist/rules/event-sourced-aggregate.d.ts +2 -2
- package/dist/rules/event-sourced-aggregate.js +8 -8
- package/dist/rules/event-sourced-aggregate.js.map +1 -1
- package/dist/rules/find-one-naming.d.ts +3 -2
- package/dist/rules/find-one-naming.js +35 -8
- package/dist/rules/find-one-naming.js.map +1 -1
- package/dist/rules/implements-ports-only.d.ts +10 -0
- package/dist/rules/implements-ports-only.js +74 -0
- package/dist/rules/implements-ports-only.js.map +1 -0
- package/dist/rules/import-only-in.d.ts +1 -1
- package/dist/rules/import-only-in.js +7 -3
- package/dist/rules/import-only-in.js.map +1 -1
- package/dist/rules/knex-first.d.ts +2 -1
- package/dist/rules/knex-first.js +11 -4
- package/dist/rules/knex-first.js.map +1 -1
- package/dist/rules/message-file.d.ts +1 -1
- package/dist/rules/message-file.js +3 -2
- package/dist/rules/message-file.js.map +1 -1
- package/dist/rules/message-handler.d.ts +1 -1
- package/dist/rules/message-handler.js +7 -6
- package/dist/rules/message-handler.js.map +1 -1
- package/dist/rules/message-name-reference.d.ts +2 -1
- package/dist/rules/message-name-reference.js +24 -5
- package/dist/rules/message-name-reference.js.map +1 -1
- package/dist/rules/message-names.d.ts +1 -1
- package/dist/rules/message-names.js +2 -2
- package/dist/rules/message-names.js.map +1 -1
- package/dist/rules/module-layout.d.ts +1 -1
- package/dist/rules/module-layout.js +1 -1
- package/dist/rules/module-layout.js.map +1 -1
- package/dist/rules/module-service-getters.d.ts +1 -1
- package/dist/rules/module-service-getters.js +11 -9
- package/dist/rules/module-service-getters.js.map +1 -1
- package/dist/rules/module-shape.d.ts +1 -1
- package/dist/rules/module-shape.js +6 -7
- package/dist/rules/module-shape.js.map +1 -1
- package/dist/rules/no-async-in-domain.d.ts +1 -1
- package/dist/rules/no-async-in-domain.js +2 -2
- package/dist/rules/no-async-in-domain.js.map +1 -1
- package/dist/rules/no-duplicate-sdk-types.d.ts +1 -1
- package/dist/rules/no-duplicate-sdk-types.js +1 -1
- package/dist/rules/no-duplicate-sdk-types.js.map +1 -1
- package/dist/rules/no-entity-assembly-in-app.d.ts +4 -2
- package/dist/rules/no-entity-assembly-in-app.js +24 -8
- package/dist/rules/no-entity-assembly-in-app.js.map +1 -1
- package/dist/rules/no-entity-mutation-outside-domain.d.ts +1 -1
- package/dist/rules/no-entity-mutation-outside-domain.js +1 -1
- package/dist/rules/no-entity-mutation-outside-domain.js.map +1 -1
- package/dist/rules/no-manual-wiring.d.ts +1 -1
- package/dist/rules/no-manual-wiring.js +5 -2
- package/dist/rules/no-manual-wiring.js.map +1 -1
- package/dist/rules/no-message-construction-outside-domain.d.ts +1 -1
- package/dist/rules/no-message-construction-outside-domain.js +1 -1
- package/dist/rules/no-message-construction-outside-domain.js.map +1 -1
- package/dist/rules/no-reconstitute.d.ts +1 -1
- package/dist/rules/no-reconstitute.js +1 -1
- package/dist/rules/no-reconstitute.js.map +1 -1
- package/dist/rules/one-class-per-file.d.ts +7 -0
- package/dist/rules/one-class-per-file.js +55 -0
- package/dist/rules/one-class-per-file.js.map +1 -0
- package/dist/rules/port-file.d.ts +1 -1
- package/dist/rules/port-file.js +3 -2
- package/dist/rules/port-file.js.map +1 -1
- package/dist/rules/port-has-adapters.d.ts +1 -1
- package/dist/rules/port-has-adapters.js +1 -1
- package/dist/rules/port-has-adapters.js.map +1 -1
- package/dist/rules/repository-naming.d.ts +1 -1
- package/dist/rules/repository-naming.js +2 -2
- package/dist/rules/repository-naming.js.map +1 -1
- package/dist/rules/repository-return-types.d.ts +10 -0
- package/dist/rules/repository-return-types.js +67 -0
- package/dist/rules/repository-return-types.js.map +1 -0
- package/dist/rules/repository-serialization.d.ts +13 -3
- package/dist/rules/repository-serialization.js +108 -12
- package/dist/rules/repository-serialization.js.map +1 -1
- package/dist/rules/return-entities.d.ts +1 -1
- package/dist/rules/return-entities.js +3 -3
- package/dist/rules/return-entities.js.map +1 -1
- package/dist/rules/save-contract.d.ts +5 -3
- package/dist/rules/save-contract.js +18 -5
- package/dist/rules/save-contract.js.map +1 -1
- package/dist/rules/subclass-declares-constructor.d.ts +1 -1
- package/dist/rules/subclass-declares-constructor.js +1 -1
- package/dist/rules/subclass-declares-constructor.js.map +1 -1
- package/dist/rules/test-location.d.ts +1 -1
- package/dist/rules/test-location.js +1 -1
- package/dist/rules/test-location.js.map +1 -1
- package/dist/rules/throw-app-error.d.ts +1 -1
- package/dist/rules/throw-app-error.js +4 -3
- package/dist/rules/throw-app-error.js.map +1 -1
- package/dist/rules/trackable-repository.d.ts +1 -1
- package/dist/rules/trackable-repository.js +4 -4
- package/dist/rules/trackable-repository.js.map +1 -1
- package/dist/rules/unique-class-names.d.ts +1 -1
- package/dist/rules/unique-class-names.js +5 -4
- package/dist/rules/unique-class-names.js.map +1 -1
- package/package.json +18 -6
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023-2026 Piotr Józefów
|
|
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
CHANGED
|
@@ -31,7 +31,7 @@ Different paths:
|
|
|
31
31
|
exclude: ['src/infrastructure/database/**', 'src/deployments/**'], // migrations, composition root
|
|
32
32
|
uuidPaths: ['/domain/', '/src/common/values/'],
|
|
33
33
|
messages: 'src/common/messages', // one <Name>.ts per message + index.ts (MessageNames)
|
|
34
|
-
authAccess: { allow: ['NewsletterService.findMany'] }, // opt-in: @AuthAccess('scope:level') on every AuthToken param
|
|
34
|
+
authAccess: { allow: ['NewsletterService.findMany'] }, // opt-in: @AuthAccess('scope:level') on every AuthToken param (also a binding decorator for app-service-endpoints)
|
|
35
35
|
storages: {
|
|
36
36
|
pg: { prefix: 'Pg', imports: ['@pjts/infra#PostgresDbClient', 'knex', 'pg'] },
|
|
37
37
|
nats: { prefix: 'Nats', imports: ['nats', '@nats-io/*'] },
|
|
@@ -67,6 +67,31 @@ exception is an inline disable with a reason:
|
|
|
67
67
|
| `decorated-class-contract` | classes with a configured decorator implement the listed methods (`@StringDomainPrimitive` → `toJSON`) |
|
|
68
68
|
| `no-reconstitute` | no `reconstitute` definition or call — repositories deserialize, services call `existing.update()` |
|
|
69
69
|
|
|
70
|
+
### Domain primitives
|
|
71
|
+
|
|
72
|
+
Primitives live only in domain-primitive classes (`…/values/`), in `…Record` row types and in
|
|
73
|
+
infrastructure code while (de)serializing; everything crossing a function boundary is a domain class.
|
|
74
|
+
Both rules classify types without a type checker: a name is resolved through the file's own
|
|
75
|
+
declarations and its relative / path-alias imports (following `export *` and `export { X } from`
|
|
76
|
+
re-exports). A class is accepted; an `interface`, a `type` alias of an object / literal / primitive and
|
|
77
|
+
an `enum` are plain. Names that resolve to no project file (package types, globals other than
|
|
78
|
+
`nativeTypes`) are accepted.
|
|
79
|
+
|
|
80
|
+
| Rule | What it checks |
|
|
81
|
+
|---|---|
|
|
82
|
+
| `domain-primitive-params` | parameters of methods, constructors (incl. parameter properties), class-field arrows, function declarations, module-level function constants and interface method signatures are not `string`/`number`/`boolean`/`bigint`, literals, literal unions, inline object types, `Date`, `Record<…>` & co. (`nativeTypes`), plain interfaces/type aliases/enums — nor arrays/unions of those. A literal default without annotation (`limit = 10`) counts as its primitive. Exempt: constructors and static methods of classes under `…/values/` (`valuesFolder`), private `deserialize…` methods under `infrastructure/`, callbacks/arrows inside function bodies. Accepted: classes, generics, function types, `allowTypeSuffixes` (`Port`, `Config`, `Data`), types declared under `allowTypesFrom` (`src/common/messages`: message bodies, `MessageNames`) |
|
|
83
|
+
| `repository-return-types` | public methods of `…Repository` classes (`classPattern`) and method signatures of `…RepositoryPort` interfaces (`interfacePattern`) declare a return type, and it is a domain class: `Promise<>`, arrays and `\| null` / `\| undefined` are unwrapped, `void` and classes (`UpdateResult` for guarded updates) pass; primitives, literals, inline objects, plain interfaces/type aliases (`…Record`, `…Row`), enums and `any`/`unknown` don't |
|
|
84
|
+
|
|
85
|
+
Type-classification options (both rules):
|
|
86
|
+
|
|
87
|
+
| Option | Default | Meaning |
|
|
88
|
+
|---|---|---|
|
|
89
|
+
| `allowTypeSuffixes` | `['Port', 'Config', 'Data']` (params), `[]` (returns) | type names accepted by suffix |
|
|
90
|
+
| `allowTypesFrom` | `['src/common/messages']` | path fragments, relative to the project root (the folder holding `src/`), whose declarations are accepted |
|
|
91
|
+
| `pathAliases` | `{ '@modules/*': 'src/modules/*', '@common/*': 'src/common/*' }` | tsconfig-like path aliases, relative to the project root |
|
|
92
|
+
| `nativeTypes` | `Date`, `Record`, `Partial`, `Pick`, `Omit`, `Required`, `Map`, `Set`, `ReadonlyMap`, `ReadonlySet`, `Object`, `String`, `Number`, `Boolean`, `BigInt` | global names that are plain |
|
|
93
|
+
| `checkAny` | `false` (params), `true` (returns) | report `any` / `unknown` / `object` too |
|
|
94
|
+
|
|
70
95
|
### Application
|
|
71
96
|
|
|
72
97
|
| Rule | What it checks |
|
|
@@ -74,9 +99,9 @@ exception is an inline disable with a reason:
|
|
|
74
99
|
| `app-class-suffix` | app-layer classes end with `Service` \| `Handler` \| `View` |
|
|
75
100
|
| `app-service-endpoints` | every public method of an `@AppService` has exactly one `@Get`/`@Post`/`@Put`/`@Patch`/`@Delete` and every parameter a request-binding decorator (`@Auth`, `@Body`, `@UrlParam`, `@QueryParam(s)`, `@Header`, `@Ip`, `@File`); non-public methods carry none |
|
|
76
101
|
| `return-entities` | no `.toJSON()` and no `Promise<…ResponseDto/Response/JSON>` — return entities, the framework serializes |
|
|
77
|
-
| `no-entity-assembly-in-app` | no `new Entity({...})` / `Entity.create({...})` from domain imports — use `Entity.fromDTO(...)` |
|
|
78
|
-
| `find-one-naming` | the private owner-scoped fetch helper (`AuthToken` first,
|
|
79
|
-
| `save-contract` | `save()`'s result is never used; `save` returns `Promise<void>` |
|
|
102
|
+
| `no-entity-assembly-in-app` | no `new Entity({...})` / `Entity.create({...})` from domain imports (classes declared in `domain/values` or `domain/views` exempt, index re-exports resolved) — use `Entity.fromDTO(...)` |
|
|
103
|
+
| `find-one-naming` | the private owner-scoped fetch helper (`AuthToken` first, returns `Promise<Entity>`, every `throw` is `AppError.notFound` — other throws mark a guard) is `findOne` (rename suggestion) |
|
|
104
|
+
| `save-contract` | `save()`'s result is never used; `save` on `…RepositoryPort` interfaces and repositories (`…Repository` or implementing a `…RepositoryPort`, never `@AppService`) returns `Promise<void>` |
|
|
80
105
|
| `no-entity-mutation-outside-domain` | a loaded entity (`await this.findOne(…)` / `await this.<repo>.find…(…)`) changes through its methods, not `entity.field = …` |
|
|
81
106
|
| `auth-access` | (opt-in) every `AuthToken` parameter of an `@AppService` uses `@AuthAccess('scope:read', …)` with literal rights; plain `@Auth` only for `allow`ed `Service.method` / `File.method` (stale entries reported); `authToken`, or `_authToken` when unread |
|
|
82
107
|
|
|
@@ -87,7 +112,7 @@ exception is an inline disable with a reason:
|
|
|
87
112
|
| `message-file` | one message per file: an exported interface named like the file, extending `Message` (or a `…Base`), `name: MessageNames.<FileName>`; helper payload types may stay |
|
|
88
113
|
| `message-names` | `MessageNames` in the messages `index.ts`: every key has a file, every message file has a key and a re-export, values are the key in SCREAMING_SNAKE_CASE |
|
|
89
114
|
| `no-message-construction-outside-domain` | an object literal pinning `name: MessageNames.X` exists only under `domain/` — aggregates return or emit message bodies, the app layer passes them on |
|
|
90
|
-
| `message-name-reference` | message names through the enum — no `'CALENDAR_BOOKED'` in `name:`, `case` of a `switch (x.name)`, or a handler's `super([...])` |
|
|
115
|
+
| `message-name-reference` | message names through the enum — no `'CALENDAR_BOOKED'` in `name:`, `case` of a `switch (x.name)`, or a handler's `super([...])` (fixable when `MessageNames` is imported or declared in the file) |
|
|
91
116
|
| `message-handler` | `MessageHandlerBase` subclasses: `…Handler` in `app/`, `super([MessageNames.X, …])`, subscribed names = handled `case`s, protected typed `handleMessage`, depends only on ports or app classes (`allowedTypes` for e.g. `MessageInbox`) |
|
|
92
117
|
|
|
93
118
|
### Infrastructure & database
|
|
@@ -95,8 +120,9 @@ exception is an inline disable with a reason:
|
|
|
95
120
|
| Rule | What it checks |
|
|
96
121
|
|---|---|
|
|
97
122
|
| `repository-naming` | repositories live in `infrastructure/repositories/<storage>/` (several: `pg+nats/`), prefixed after it (`Pg`, `PgNats`, `InMemory`); the folder matches the file's imports; one repository per file, named after it |
|
|
98
|
-
| `repository-serialization` | `Pg*Repository`
|
|
99
|
-
| `
|
|
123
|
+
| `repository-serialization` | `Pg*Repository` (`classPattern`) maps rows through `deserialize` and writes through `serialize`, each required only for the direction it uses: `deserialize` when a public method declares a return type other than `void` / `UpdateResult` (`ignoreReturnTypes`, `Promise<>` unwrapped), `serialize` when a public method takes a class-typed parameter declared outside `…/values/` and the class writes (`writeMethods`: `insert`/`upsert`/`update`); `serialize…`/`deserialize…` variants count; `deserialize` returns `new Entity(...)`; no `toDomain`/`toRow`/`fromRow`/… (rename suggestion) |
|
|
124
|
+
| `implements-ports-only` | in `infrastructure/`, every `implements` name ends with `portSuffix` (`Port`) — interfaces imported from packages (`OnBoot` from `@pjts/server`) are skipped (`ignorePackageTypes`, `pathAliases` decide what is a package); a non-abstract `…Repository` class (`repositoryPattern`) implements at least one port — a `…RepositoryPort` with `requireRepositoryPort` (off by default: lookup repositories implement `…DirectoryPort` & co.) |
|
|
125
|
+
| `knex-first` | single-record reads end with `.first()`, not `const [row] = await this.db(…)` (fixable) |
|
|
100
126
|
| `trackable-repository` | repositories on pjx `RepositoryBase` / `OutboxRepository`: every `deserialize…` is `@reconstitute` (else `save()` inserts a duplicate); an event-sourced aggregate's repository extends `…OutboxRepository` |
|
|
101
127
|
| `db-client-dependency` | only `…Pg…Repository` classes (Pg anywhere in the prefix) take `PostgresDbClient` / knex / pg as a dependency |
|
|
102
128
|
| `db-writes-in-repositories` | insert/update/delete (+ truncate, upsert, increment, decrement, onConflict, transactions, writing raw SQL) happen only in a `…Pg…Repository` under `infrastructure/` |
|
|
@@ -107,7 +133,8 @@ exception is an inline disable with a reason:
|
|
|
107
133
|
|---|---|
|
|
108
134
|
| `module-layout` | only `rootFiles` at a module root (`<Module>Module.ts`, `<Module>MessageHandlers.ts`, `index.ts`); allowed top-level and `app/` subfolders; required entries exist |
|
|
109
135
|
| `module-shape` | `…Module` = `@HttpModule` + `static readonly services`, `…MessageHandlers` = `@MessageHandlers` + `static readonly handlers`, `…Workers` = `@Workers` + `static readonly workers`; entries are classes from the module's own `./app/`; static methods with a return type are config providers; nothing else (no context, fields, getters, setters) |
|
|
110
|
-
| `module-service-getters` | (
|
|
136
|
+
| `module-service-getters` | **deprecated** (hand-wired modules predate the container; not in `configs.ddd`, removed in a future major) a hand-wired `…Module`'s public getters return only `new X(...)` of a class from its own `./app/`, named `x` (camelCase) |
|
|
137
|
+
| `one-class-per-file` | at most one exported class per file (`export class`, `export default class`, `export { LocalClass }`); non-exported helpers don't count; tests skipped (`ignoreTests`, default `true`); the preset leaves `app/dto/**` out |
|
|
111
138
|
| `unique-class-names` | a class name is declared once under `src/modules/**` + `src/common/**` — class names key the wiring and the route registry |
|
|
112
139
|
| `subclass-declares-constructor` | app and infrastructure classes that `extends` something declare their own constructor (`ignoreBases` for `RepositoryBase` & co.) |
|
|
113
140
|
| `port-file` | ports live in `app/ports/<Name>Port.ts`, one exported interface per file named like it; only types; no `…Port` elsewhere |
|
|
@@ -131,6 +158,9 @@ exception is an inline disable with a reason:
|
|
|
131
158
|
sibling files from disk, so in an editor they refresh only when the reporting file is re-linted;
|
|
132
159
|
the CLI is always accurate. Don't use `eslint --cache` with them.
|
|
133
160
|
- `no-entity-assembly-in-app` and `no-duplicate-sdk-types` are name-based heuristics.
|
|
161
|
+
- `domain-primitive-params` and `repository-return-types` read the declaring files of imported
|
|
162
|
+
types from disk (cached per file modification time); an editor re-checks them when the linted file
|
|
163
|
+
changes.
|
|
134
164
|
|
|
135
165
|
## Development
|
|
136
166
|
|
package/dist/index.js
CHANGED
|
@@ -10,12 +10,14 @@ const message_names_1 = tslib_1.__importDefault(require("./rules/message-names")
|
|
|
10
10
|
const no_entity_mutation_outside_domain_1 = tslib_1.__importDefault(require("./rules/no-entity-mutation-outside-domain"));
|
|
11
11
|
const no_message_construction_outside_domain_1 = tslib_1.__importDefault(require("./rules/no-message-construction-outside-domain"));
|
|
12
12
|
const trackable_repository_1 = tslib_1.__importDefault(require("./rules/trackable-repository"));
|
|
13
|
-
const app_service_endpoints_1 = tslib_1.
|
|
13
|
+
const app_service_endpoints_1 = tslib_1.__importStar(require("./rules/app-service-endpoints"));
|
|
14
14
|
const db_client_dependency_1 = tslib_1.__importDefault(require("./rules/db-client-dependency"));
|
|
15
15
|
const db_writes_in_repositories_1 = tslib_1.__importDefault(require("./rules/db-writes-in-repositories"));
|
|
16
|
+
const domain_primitive_params_1 = tslib_1.__importDefault(require("./rules/domain-primitive-params"));
|
|
16
17
|
const decorated_class_contract_1 = tslib_1.__importDefault(require("./rules/decorated-class-contract"));
|
|
17
18
|
const entity_constructor_data_1 = tslib_1.__importDefault(require("./rules/entity-constructor-data"));
|
|
18
19
|
const find_one_naming_1 = tslib_1.__importDefault(require("./rules/find-one-naming"));
|
|
20
|
+
const implements_ports_only_1 = tslib_1.__importDefault(require("./rules/implements-ports-only"));
|
|
19
21
|
const import_only_in_1 = tslib_1.__importDefault(require("./rules/import-only-in"));
|
|
20
22
|
const knex_first_1 = tslib_1.__importDefault(require("./rules/knex-first"));
|
|
21
23
|
const module_layout_1 = tslib_1.__importDefault(require("./rules/module-layout"));
|
|
@@ -29,9 +31,11 @@ const no_async_in_domain_1 = tslib_1.__importDefault(require("./rules/no-async-i
|
|
|
29
31
|
const no_duplicate_sdk_types_1 = tslib_1.__importDefault(require("./rules/no-duplicate-sdk-types"));
|
|
30
32
|
const no_entity_assembly_in_app_1 = tslib_1.__importDefault(require("./rules/no-entity-assembly-in-app"));
|
|
31
33
|
const no_reconstitute_1 = tslib_1.__importDefault(require("./rules/no-reconstitute"));
|
|
34
|
+
const one_class_per_file_1 = tslib_1.__importDefault(require("./rules/one-class-per-file"));
|
|
32
35
|
const port_file_1 = tslib_1.__importDefault(require("./rules/port-file"));
|
|
33
36
|
const port_has_adapters_1 = tslib_1.__importDefault(require("./rules/port-has-adapters"));
|
|
34
37
|
const repository_naming_1 = tslib_1.__importDefault(require("./rules/repository-naming"));
|
|
38
|
+
const repository_return_types_1 = tslib_1.__importDefault(require("./rules/repository-return-types"));
|
|
35
39
|
const repository_serialization_1 = tslib_1.__importDefault(require("./rules/repository-serialization"));
|
|
36
40
|
const return_entities_1 = tslib_1.__importDefault(require("./rules/return-entities"));
|
|
37
41
|
const save_contract_1 = tslib_1.__importDefault(require("./rules/save-contract"));
|
|
@@ -52,8 +56,10 @@ const rules = {
|
|
|
52
56
|
'db-client-dependency': db_client_dependency_1.default,
|
|
53
57
|
'db-writes-in-repositories': db_writes_in_repositories_1.default,
|
|
54
58
|
'decorated-class-contract': decorated_class_contract_1.default,
|
|
59
|
+
'domain-primitive-params': domain_primitive_params_1.default,
|
|
55
60
|
'entity-constructor-data': entity_constructor_data_1.default,
|
|
56
61
|
'find-one-naming': find_one_naming_1.default,
|
|
62
|
+
'implements-ports-only': implements_ports_only_1.default,
|
|
57
63
|
'import-only-in': import_only_in_1.default,
|
|
58
64
|
'knex-first': knex_first_1.default,
|
|
59
65
|
'module-layout': module_layout_1.default,
|
|
@@ -67,9 +73,11 @@ const rules = {
|
|
|
67
73
|
'no-duplicate-sdk-types': no_duplicate_sdk_types_1.default,
|
|
68
74
|
'no-entity-assembly-in-app': no_entity_assembly_in_app_1.default,
|
|
69
75
|
'no-reconstitute': no_reconstitute_1.default,
|
|
76
|
+
'one-class-per-file': one_class_per_file_1.default,
|
|
70
77
|
'port-file': port_file_1.default,
|
|
71
78
|
'port-has-adapters': port_has_adapters_1.default,
|
|
72
79
|
'repository-naming': repository_naming_1.default,
|
|
80
|
+
'repository-return-types': repository_return_types_1.default,
|
|
73
81
|
'repository-serialization': repository_serialization_1.default,
|
|
74
82
|
'return-entities': return_entities_1.default,
|
|
75
83
|
'save-contract': save_contract_1.default,
|
|
@@ -97,8 +105,11 @@ const createDddConfig = (options = {}) => {
|
|
|
97
105
|
plugins: { pjts: plugin, '@typescript-eslint': tseslint.plugin },
|
|
98
106
|
rules: {
|
|
99
107
|
'pjts/no-reconstitute': 'error',
|
|
100
|
-
// @AppService public methods are endpoints: one HTTP decorator, every parameter request-bound
|
|
101
|
-
|
|
108
|
+
// @AppService public methods are endpoints: one HTTP decorator, every parameter request-bound
|
|
109
|
+
// (with authAccess, `@AuthAccess(...)` binds the AuthToken).
|
|
110
|
+
'pjts/app-service-endpoints': authAccess
|
|
111
|
+
? ['error', { paramDecorators: [...app_service_endpoints_1.DEFAULT_PARAM_DECORATORS, authAccess.decorator ?? 'AuthAccess'] }]
|
|
112
|
+
: 'error',
|
|
102
113
|
// Fields, constructor, static factories (`fromDTO`, `create`), then instance methods.
|
|
103
114
|
'@typescript-eslint/member-ordering': ['error', { default: ['field', 'constructor', 'static-method', 'instance-method'] }],
|
|
104
115
|
},
|
|
@@ -133,6 +144,19 @@ const createDddConfig = (options = {}) => {
|
|
|
133
144
|
...(authAccess ? { 'pjts/auth-access': ['error', authAccess] } : {}),
|
|
134
145
|
},
|
|
135
146
|
},
|
|
147
|
+
{
|
|
148
|
+
// Everything crossing a function boundary is a domain class: primitives live in …/values/,
|
|
149
|
+
// …Record types and (de)serializing infrastructure code. DTOs bind the HTTP payload.
|
|
150
|
+
files: [`${module}/app/**/*.ts`, `${module}/domain/**/*.ts`, `${module}/infrastructure/**/*.ts`, `${src}/common/**/*.ts`],
|
|
151
|
+
ignores: [...exclude, `${module}/app/dto/**`, `${module}/testing/**`, `${src}/testing/**`],
|
|
152
|
+
rules: { 'pjts/domain-primitive-params': ['error', { allowTypesFrom: [messages] }] },
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
// One exported class per file, the file named after it. DTO bundles (app/dto) may group request shapes.
|
|
156
|
+
files: [`${src}/**/*.ts`],
|
|
157
|
+
ignores: [...exclude, `${module}/app/dto/**`],
|
|
158
|
+
rules: { 'pjts/one-class-per-file': 'error' },
|
|
159
|
+
},
|
|
136
160
|
{
|
|
137
161
|
// Nobody builds app classes, adapters or modules by hand: the IoC container does, from the wiring.
|
|
138
162
|
files: [`${src}/**/*.ts`],
|
|
@@ -214,6 +238,11 @@ const createDddConfig = (options = {}) => {
|
|
|
214
238
|
files: [`${module}/app/ports/*.ts`],
|
|
215
239
|
rules: { 'pjts/port-has-adapters': 'error' },
|
|
216
240
|
},
|
|
241
|
+
{
|
|
242
|
+
// Repositories and their ports return domain classes (UpdateResult for guarded updates), never rows or primitives.
|
|
243
|
+
files: [`${module}/app/ports/**/*.ts`, `${module}/infrastructure/**/*.ts`],
|
|
244
|
+
rules: { 'pjts/repository-return-types': ['error', { allowTypesFrom: [messages] }] },
|
|
245
|
+
},
|
|
217
246
|
{
|
|
218
247
|
// Subclasses declare the dependencies they take; the wiring is derived from constructors.
|
|
219
248
|
files: [`${module}/app/*.ts`, `${module}/infrastructure/**/*.ts`],
|
|
@@ -231,6 +260,8 @@ const createDddConfig = (options = {}) => {
|
|
|
231
260
|
'pjts/repository-naming': ['error', { storages, requireImplementationFolder: true, fileNameMatchesClass: true }],
|
|
232
261
|
'pjts/repository-serialization': ['error', { classPattern: '^Pg\\w*Repository$' }],
|
|
233
262
|
'pjts/knex-first': 'error',
|
|
263
|
+
// Adapters implement ports (framework interfaces from packages aside); repositories their …RepositoryPort.
|
|
264
|
+
'pjts/implements-ports-only': 'error',
|
|
234
265
|
// RepositoryBase/OutboxRepository: @reconstitute on deserialize, event-sourced → OutboxRepository.
|
|
235
266
|
'pjts/trackable-repository': 'error',
|
|
236
267
|
},
|
|
@@ -248,7 +279,7 @@ const createDddConfig = (options = {}) => {
|
|
|
248
279
|
];
|
|
249
280
|
};
|
|
250
281
|
const plugin = {
|
|
251
|
-
meta: { name: '@pjts/eslint-style-rules' },
|
|
282
|
+
meta: { name: '@pjts/eslint-style-rules', version: require('../package.json').version },
|
|
252
283
|
rules,
|
|
253
284
|
configs: {},
|
|
254
285
|
createDddConfig,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;AACA,wFAAsD;AACtD,8EAA6C;AAC7C,sGAAoE;AACpE,gFAA+C;AAC/C,sFAAqD;AACrD,oGAAkE;AAClE,kFAAiD;AACjD,0HAAsF;AACtF,oIAAgG;AAChG,gGAA+D;AAC/D
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/ast.d.ts
CHANGED
|
@@ -1,27 +1,41 @@
|
|
|
1
|
+
import type { TSESTree } from '@typescript-eslint/utils';
|
|
2
|
+
import type { RuleContext } from './rule';
|
|
1
3
|
/** Forward-slash path of the file being linted. */
|
|
2
|
-
export declare const filePath: (context:
|
|
4
|
+
export declare const filePath: (context: RuleContext) => string;
|
|
3
5
|
/** `apps/api/src/modules/<module>/<rest>` → `{ module, rest: ['app', 'TaskService.ts'] }`, or null. */
|
|
4
|
-
export declare const moduleLocation: (context:
|
|
5
|
-
module:
|
|
6
|
-
rest:
|
|
6
|
+
export declare const moduleLocation: (context: RuleContext) => {
|
|
7
|
+
module: string;
|
|
8
|
+
rest: string[];
|
|
7
9
|
root: string;
|
|
8
10
|
} | null;
|
|
9
|
-
export
|
|
10
|
-
export
|
|
11
|
-
export declare const
|
|
11
|
+
export type ClassNode = TSESTree.ClassDeclaration | TSESTree.ClassExpression;
|
|
12
|
+
export type FunctionNode = TSESTree.FunctionDeclaration | TSESTree.FunctionExpression | TSESTree.ArrowFunctionExpression;
|
|
13
|
+
export declare const methods: (classNode: ClassNode) => TSESTree.MethodDefinition[];
|
|
14
|
+
/** Name of an identifier, private name or literal key (`foo`, `#foo`, `'foo'`); null for anything else. */
|
|
15
|
+
export declare const keyName: (key: TSESTree.Node | null | undefined) => string | null;
|
|
16
|
+
/** The key of a class member or object property, when it has one. */
|
|
17
|
+
export declare const memberKey: (member: TSESTree.Node) => TSESTree.Node | null;
|
|
18
|
+
export declare const memberName: (member: TSESTree.Node) => string | null;
|
|
19
|
+
export declare const findMethod: (classNode: ClassNode, name: string, isStatic?: boolean) => TSESTree.MethodDefinition | undefined;
|
|
20
|
+
/** `@Foo` and `@Foo(...)` → 'Foo'; null for computed or member decorators (`@a.b`). */
|
|
21
|
+
export declare const decoratorName: (decorator: TSESTree.Decorator) => string | null;
|
|
12
22
|
/** Decorator names on a class: `@Foo` and `@Foo()` both give `Foo`. */
|
|
13
|
-
export declare const decoratorNames: (classNode:
|
|
23
|
+
export declare const decoratorNames: (classNode: ClassNode) => string[];
|
|
24
|
+
/** `import { type X }` — a specifier that brings in a type only (the clause-level `import type` is on the declaration). */
|
|
25
|
+
export declare const isTypeOnlySpecifier: (specifier: TSESTree.ImportClause) => boolean;
|
|
26
|
+
/** An import source inside the module's own app layer, excluding its DTOs and ports: `./app`, `./app/TaskService`. */
|
|
27
|
+
export declare const isAppSource: (source: string) => boolean;
|
|
14
28
|
/** Type name of an annotation such as `data: TaskData` → `TaskData`. */
|
|
15
|
-
export declare const annotationTypeName: (annotation:
|
|
29
|
+
export declare const annotationTypeName: (annotation: TSESTree.TSTypeAnnotation | TSESTree.TypeNode | null | undefined) => string | null;
|
|
16
30
|
/**
|
|
17
31
|
* `Promise<X>` return annotation → the X node; `undefined` when the annotation is not a Promise
|
|
18
32
|
* (or missing), so callers can tell "not async-typed" from "Promise of nothing".
|
|
19
33
|
*/
|
|
20
|
-
export declare const promiseTypeArgument: (returnType:
|
|
34
|
+
export declare const promiseTypeArgument: (returnType: TSESTree.TSTypeAnnotation | undefined) => TSESTree.TypeNode | null | undefined;
|
|
21
35
|
/** `foo.bar(...)` → 'bar'. */
|
|
22
|
-
export declare const calledMethodName: (call:
|
|
23
|
-
export declare const unwrapAwait: (node:
|
|
36
|
+
export declare const calledMethodName: (call: TSESTree.Node | null | undefined) => string | null;
|
|
37
|
+
export declare const unwrapAwait: <T extends TSESTree.Node>(node: T | TSESTree.AwaitExpression | null | undefined) => T | TSESTree.Expression | null | undefined;
|
|
24
38
|
/** `kebab-case` → `PascalCase`. */
|
|
25
|
-
export declare const pascalCase: (kebab:
|
|
39
|
+
export declare const pascalCase: (kebab: string) => string;
|
|
26
40
|
/** `Array.prototype.findLast` (ES2023) for the ES2021 target. */
|
|
27
41
|
export declare const findLast: <T>(items: readonly T[], predicate: (item: T) => boolean) => T | undefined;
|
package/dist/lib/ast.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.findLast = exports.pascalCase = exports.unwrapAwait = exports.calledMethodName = exports.promiseTypeArgument = exports.annotationTypeName = exports.decoratorNames = exports.findMethod = exports.memberName = exports.methods = exports.moduleLocation = exports.filePath = void 0;
|
|
3
|
+
exports.findLast = exports.pascalCase = exports.unwrapAwait = exports.calledMethodName = exports.promiseTypeArgument = exports.annotationTypeName = exports.isAppSource = exports.isTypeOnlySpecifier = exports.decoratorNames = exports.decoratorName = exports.findMethod = exports.memberName = exports.memberKey = exports.keyName = exports.methods = exports.moduleLocation = exports.filePath = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const node_path_1 = tslib_1.__importDefault(require("node:path"));
|
|
6
6
|
/** Forward-slash path of the file being linted. */
|
|
@@ -14,16 +14,42 @@ const moduleLocation = (context) => {
|
|
|
14
14
|
exports.moduleLocation = moduleLocation;
|
|
15
15
|
const methods = (classNode) => classNode.body.body.filter((member) => member.type === 'MethodDefinition');
|
|
16
16
|
exports.methods = methods;
|
|
17
|
-
|
|
17
|
+
/** Name of an identifier, private name or literal key (`foo`, `#foo`, `'foo'`); null for anything else. */
|
|
18
|
+
const keyName = (key) => {
|
|
19
|
+
if (!key)
|
|
20
|
+
return null;
|
|
21
|
+
if (key.type === 'Identifier' || key.type === 'PrivateIdentifier')
|
|
22
|
+
return key.name;
|
|
23
|
+
if (key.type === 'Literal')
|
|
24
|
+
return typeof key.value === 'string' ? key.value : String(key.value);
|
|
25
|
+
return null;
|
|
26
|
+
};
|
|
27
|
+
exports.keyName = keyName;
|
|
28
|
+
/** The key of a class member or object property, when it has one. */
|
|
29
|
+
const memberKey = (member) => 'key' in member && member.key && typeof member.key === 'object' ? member.key : null;
|
|
30
|
+
exports.memberKey = memberKey;
|
|
31
|
+
const memberName = (member) => (0, exports.keyName)((0, exports.memberKey)(member));
|
|
18
32
|
exports.memberName = memberName;
|
|
19
33
|
const findMethod = (classNode, name, isStatic) => (0, exports.methods)(classNode).find((m) => (0, exports.memberName)(m) === name && (isStatic === undefined || m.static === isStatic));
|
|
20
34
|
exports.findMethod = findMethod;
|
|
35
|
+
/** `@Foo` and `@Foo(...)` → 'Foo'; null for computed or member decorators (`@a.b`). */
|
|
36
|
+
const decoratorName = (decorator) => {
|
|
37
|
+
const expression = decorator.expression.type === 'CallExpression' ? decorator.expression.callee : decorator.expression;
|
|
38
|
+
return expression.type === 'Identifier' ? expression.name : null;
|
|
39
|
+
};
|
|
40
|
+
exports.decoratorName = decoratorName;
|
|
21
41
|
/** Decorator names on a class: `@Foo` and `@Foo()` both give `Foo`. */
|
|
22
|
-
const decoratorNames = (classNode) => (classNode.decorators ?? []).map((
|
|
42
|
+
const decoratorNames = (classNode) => (classNode.decorators ?? []).map(exports.decoratorName).filter((name) => name !== null);
|
|
23
43
|
exports.decoratorNames = decoratorNames;
|
|
44
|
+
/** `import { type X }` — a specifier that brings in a type only (the clause-level `import type` is on the declaration). */
|
|
45
|
+
const isTypeOnlySpecifier = (specifier) => specifier.type === 'ImportSpecifier' && specifier.importKind === 'type';
|
|
46
|
+
exports.isTypeOnlySpecifier = isTypeOnlySpecifier;
|
|
47
|
+
/** An import source inside the module's own app layer, excluding its DTOs and ports: `./app`, `./app/TaskService`. */
|
|
48
|
+
const isAppSource = (source) => /^\.\/app(\/|$)/.test(source) && !/^\.\/app\/(dto|ports)(\/|$)/.test(source);
|
|
49
|
+
exports.isAppSource = isAppSource;
|
|
24
50
|
/** Type name of an annotation such as `data: TaskData` → `TaskData`. */
|
|
25
51
|
const annotationTypeName = (annotation) => {
|
|
26
|
-
const type = annotation?.typeAnnotation
|
|
52
|
+
const type = annotation?.type === 'TSTypeAnnotation' ? annotation.typeAnnotation : annotation;
|
|
27
53
|
return type?.type === 'TSTypeReference' && type.typeName.type === 'Identifier' ? type.typeName.name : null;
|
|
28
54
|
};
|
|
29
55
|
exports.annotationTypeName = annotationTypeName;
|
|
@@ -33,17 +59,17 @@ exports.annotationTypeName = annotationTypeName;
|
|
|
33
59
|
*/
|
|
34
60
|
const promiseTypeArgument = (returnType) => {
|
|
35
61
|
const type = returnType?.typeAnnotation;
|
|
36
|
-
if (type?.type !== 'TSTypeReference' || type.typeName.name !== 'Promise')
|
|
62
|
+
if (type?.type !== 'TSTypeReference' || type.typeName.type !== 'Identifier' || type.typeName.name !== 'Promise')
|
|
37
63
|
return undefined;
|
|
38
64
|
return type.typeArguments?.params?.[0] ?? null;
|
|
39
65
|
};
|
|
40
66
|
exports.promiseTypeArgument = promiseTypeArgument;
|
|
41
67
|
/** `foo.bar(...)` → 'bar'. */
|
|
42
68
|
const calledMethodName = (call) => call?.type === 'CallExpression' && call.callee.type === 'MemberExpression' && !call.callee.computed
|
|
43
|
-
? call.callee.property
|
|
69
|
+
? (0, exports.keyName)(call.callee.property)
|
|
44
70
|
: null;
|
|
45
71
|
exports.calledMethodName = calledMethodName;
|
|
46
|
-
const unwrapAwait = (node) =>
|
|
72
|
+
const unwrapAwait = (node) => node?.type === 'AwaitExpression' ? node.argument : node;
|
|
47
73
|
exports.unwrapAwait = unwrapAwait;
|
|
48
74
|
/** `kebab-case` → `PascalCase`. */
|
|
49
75
|
const pascalCase = (kebab) => kebab.split('-').map((part) => part[0].toUpperCase() + part.slice(1)).join('');
|
package/dist/lib/ast.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ast.js","sourceRoot":"","sources":["../../src/lib/ast.ts"],"names":[],"mappings":";;;;AAAA,kEAA6B;
|
|
1
|
+
{"version":3,"file":"ast.js","sourceRoot":"","sources":["../../src/lib/ast.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/db.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { TSESTree } from '@typescript-eslint/utils';
|
|
1
2
|
/** Default DB client types: `module#ImportedName` specs (see `clientTypeTracker`). */
|
|
2
3
|
export declare const DEFAULT_CLIENTS: string[];
|
|
3
4
|
/**
|
|
@@ -5,9 +6,9 @@ export declare const DEFAULT_CLIENTS: string[];
|
|
|
5
6
|
* type annotation uses one (`PostgresDbClient`, `Knex`, `Knex.Transaction`, `PostgresDbClient | null`).
|
|
6
7
|
*/
|
|
7
8
|
export declare const clientTypeTracker: (clients?: string[]) => {
|
|
8
|
-
names: Set<
|
|
9
|
-
onImport(node:
|
|
10
|
-
usesClient: (type:
|
|
9
|
+
names: Set<string>;
|
|
10
|
+
onImport(node: TSESTree.ImportDeclaration): void;
|
|
11
|
+
usesClient: (type: TSESTree.TSTypeAnnotation | TSESTree.TypeNode | null | undefined) => boolean;
|
|
11
12
|
};
|
|
12
13
|
/** `param`, `private readonly param`, `param = x` → the binding node carrying the annotation. */
|
|
13
|
-
export declare const paramBinding: (param:
|
|
14
|
+
export declare const paramBinding: (param: TSESTree.Parameter) => TSESTree.BindingName | TSESTree.RestElement | TSESTree.Expression;
|
package/dist/lib/db.js
CHANGED
|
@@ -22,7 +22,7 @@ const clientTypeTracker = (clients = exports.DEFAULT_CLIENTS) => {
|
|
|
22
22
|
let name = type.typeName;
|
|
23
23
|
while (name.type === 'TSQualifiedName')
|
|
24
24
|
name = name.left;
|
|
25
|
-
return names.has(name.name);
|
|
25
|
+
return name.type === 'Identifier' && names.has(name.name);
|
|
26
26
|
}
|
|
27
27
|
if (type.type === 'TSUnionType' || type.type === 'TSIntersectionType')
|
|
28
28
|
return type.types.some(usesClient);
|
|
@@ -32,7 +32,7 @@ const clientTypeTracker = (clients = exports.DEFAULT_CLIENTS) => {
|
|
|
32
32
|
names,
|
|
33
33
|
onImport(node) {
|
|
34
34
|
for (const specifier of node.specifiers) {
|
|
35
|
-
const imported = specifier.imported
|
|
35
|
+
const imported = specifier.type === 'ImportSpecifier' ? (specifier.imported.type === 'Identifier' ? specifier.imported.name : specifier.imported.value) : specifier.local.name;
|
|
36
36
|
if (clients.some((spec) => matchesSpec(spec, node.source.value, imported)))
|
|
37
37
|
names.add(specifier.local.name);
|
|
38
38
|
}
|
package/dist/lib/db.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"db.js","sourceRoot":"","sources":["../../src/lib/db.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"db.js","sourceRoot":"","sources":["../../src/lib/db.ts"],"names":[],"mappings":";;;AAEA,sFAAsF;AACzE,QAAA,eAAe,GAAG,CAAC,8BAA8B,EAAE,WAAW,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,CAAC,CAAC;AAEtH,MAAM,WAAW,GAAG,CAAC,IAAY,EAAE,MAAc,EAAE,YAAoB,EAAE,EAAE;IACzE,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACvC,OAAO,MAAM,KAAK,MAAM,IAAI,CAAC,CAAC,IAAI,IAAI,YAAY,KAAK,IAAI,CAAC,CAAC;AAC/D,CAAC,CAAC;AAEF;;;GAGG;AACI,MAAM,iBAAiB,GAAG,CAAC,OAAO,GAAG,uBAAe,EAAE,EAAE;IAC7D,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;IAChC,MAAM,UAAU,GAAG,CAAC,IAAsE,EAAW,EAAE;QACrG,IAAI,CAAC,IAAI;YAAE,OAAO,KAAK,CAAC;QACxB,IAAI,IAAI,CAAC,IAAI,KAAK,kBAAkB;YAAE,OAAO,UAAU,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAC7E,IAAI,IAAI,CAAC,IAAI,KAAK,iBAAiB,EAAE,CAAC;YACpC,IAAI,IAAI,GAAwB,IAAI,CAAC,QAAQ,CAAC;YAC9C,OAAO,IAAI,CAAC,IAAI,KAAK,iBAAiB;gBAAE,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;YACzD,OAAO,IAAI,CAAC,IAAI,KAAK,YAAY,IAAI,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC5D,CAAC;QACD,IAAI,IAAI,CAAC,IAAI,KAAK,aAAa,IAAI,IAAI,CAAC,IAAI,KAAK,oBAAoB;YAAE,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC1G,OAAO,KAAK,CAAC;IACf,CAAC,CAAC;IACF,OAAO;QACL,KAAK;QACL,QAAQ,CAAC,IAAgC;YACvC,KAAK,MAAM,SAAS,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;gBACxC,MAAM,QAAQ,GAAG,SAAS,CAAC,IAAI,KAAK,iBAAiB,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,KAAK,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC;gBAC/K,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;oBAAE,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAC9G,CAAC;QACH,CAAC;QACD,UAAU;KACX,CAAC;AACJ,CAAC,CAAC;AAvBW,QAAA,iBAAiB,qBAuB5B;AAEF,iGAAiG;AAC1F,MAAM,YAAY,GAAG,CAAC,KAAyB,EAAqE,EAAE;IAC3H,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,KAAK,qBAAqB,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC;IAC5E,OAAO,IAAI,CAAC,IAAI,KAAK,mBAAmB,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AAC9D,CAAC,CAAC;AAHW,QAAA,YAAY,gBAGvB"}
|
package/dist/lib/rule.d.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { TSESLint } from '@typescript-eslint/utils';
|
|
2
|
+
/** The rule context every pjts rule receives: untyped options (validated by the rule's own schema). */
|
|
3
|
+
export type RuleContext = TSESLint.RuleContext<string, any[]>;
|
|
2
4
|
/**
|
|
3
|
-
* Types a rule for ESLint
|
|
4
|
-
* fields (decorators, type annotations, accessibility)
|
|
5
|
+
* Types a rule for ESLint with typescript-eslint's AST types, so visitor nodes carry the
|
|
6
|
+
* TypeScript-specific fields (decorators, type annotations, accessibility) the rules read.
|
|
5
7
|
*/
|
|
6
8
|
export declare const defineRule: (rule: {
|
|
7
|
-
meta:
|
|
8
|
-
create: (context:
|
|
9
|
-
}) =>
|
|
9
|
+
meta: TSESLint.RuleMetaData<string, unknown>;
|
|
10
|
+
create: (context: RuleContext) => TSESLint.RuleListener;
|
|
11
|
+
}) => TSESLint.RuleModule<string, any[]>;
|
package/dist/lib/rule.js
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.defineRule = void 0;
|
|
4
4
|
/**
|
|
5
|
-
* Types a rule for ESLint
|
|
6
|
-
* fields (decorators, type annotations, accessibility)
|
|
5
|
+
* Types a rule for ESLint with typescript-eslint's AST types, so visitor nodes carry the
|
|
6
|
+
* TypeScript-specific fields (decorators, type annotations, accessibility) the rules read.
|
|
7
7
|
*/
|
|
8
|
-
const defineRule = (rule) => rule;
|
|
8
|
+
const defineRule = (rule) => ({ ...rule, defaultOptions: [] });
|
|
9
9
|
exports.defineRule = defineRule;
|
|
10
10
|
//# sourceMappingURL=rule.js.map
|
package/dist/lib/rule.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rule.js","sourceRoot":"","sources":["../../src/lib/rule.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"rule.js","sourceRoot":"","sources":["../../src/lib/rule.ts"],"names":[],"mappings":";;;AAKA;;;GAGG;AACI,MAAM,UAAU,GAAG,CAAC,IAG1B,EAAsC,EAAE,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,cAAc,EAAE,EAAE,EAAE,CAAC,CAAC;AAH/D,QAAA,UAAU,cAGqD"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { JSONSchema } from '@typescript-eslint/utils';
|
|
2
|
+
/**
|
|
3
|
+
* Syntactic + file-system type classification shared by the domain-primitive rules: tells whether a
|
|
4
|
+
* type annotation is a "plain" type (native, literal, inline object, plain interface/type alias/enum)
|
|
5
|
+
* or something the rules accept (a class, a port, a generic, an unresolvable package type, …).
|
|
6
|
+
* No type checker: names are resolved through the file's own declarations and its relative /
|
|
7
|
+
* path-alias imports, following `export *` and `export { X } from` re-exports.
|
|
8
|
+
*/
|
|
9
|
+
export interface TypePolicy {
|
|
10
|
+
/** Names ending with one of these are accepted wherever they are declared. */
|
|
11
|
+
allowTypeSuffixes: string[];
|
|
12
|
+
/** Path fragments (relative to the project root, e.g. `src/common/messages`): types declared there are accepted. */
|
|
13
|
+
allowTypesFrom: string[];
|
|
14
|
+
/** tsconfig-like aliases, relative to the project root (the folder holding `src/`): `{ '@modules/*': 'src/modules/*' }`. */
|
|
15
|
+
pathAliases: Record<string, string>;
|
|
16
|
+
/** Global type names that are plain (`Date`, `Record`, `Partial`, …). */
|
|
17
|
+
nativeTypes: string[];
|
|
18
|
+
/** Report `any` / `unknown` / `object` as well. */
|
|
19
|
+
checkAny: boolean;
|
|
20
|
+
}
|
|
21
|
+
export declare const DEFAULT_PATH_ALIASES: Record<string, string>;
|
|
22
|
+
export declare const DEFAULT_NATIVE_TYPES: string[];
|
|
23
|
+
export declare const typePolicySchema: Record<string, JSONSchema.JSONSchema4>;
|
|
24
|
+
type DeclarationKind = 'class' | 'interface' | 'alias' | 'enum';
|
|
25
|
+
interface Declaration {
|
|
26
|
+
kind: DeclarationKind;
|
|
27
|
+
node: any;
|
|
28
|
+
index: FileIndex;
|
|
29
|
+
}
|
|
30
|
+
export interface FileIndex {
|
|
31
|
+
file: string;
|
|
32
|
+
declarations: Map<string, {
|
|
33
|
+
kind: DeclarationKind;
|
|
34
|
+
node: any;
|
|
35
|
+
}>;
|
|
36
|
+
imports: Map<string, {
|
|
37
|
+
source: string;
|
|
38
|
+
imported: string;
|
|
39
|
+
}>;
|
|
40
|
+
/** `export { local as exported }` without a source. */
|
|
41
|
+
localExports: Map<string, string>;
|
|
42
|
+
/** `export { imported as exported } from 'source'`. */
|
|
43
|
+
namedReexports: Map<string, {
|
|
44
|
+
source: string;
|
|
45
|
+
imported: string;
|
|
46
|
+
}>;
|
|
47
|
+
/** `export * from 'source'`. */
|
|
48
|
+
starReexports: string[];
|
|
49
|
+
}
|
|
50
|
+
/** Top-level declarations, imports and re-exports of a parsed `Program`. */
|
|
51
|
+
export declare const indexProgram: (program: any, file: string) => FileIndex;
|
|
52
|
+
/** Test hook. */
|
|
53
|
+
export declare const resetParsedFiles: () => void;
|
|
54
|
+
/** `<…>/src/<rest>` → `<…>` (the folder holding `src/`), or null. */
|
|
55
|
+
export declare const projectRootOf: (file: string) => string | null;
|
|
56
|
+
/** Resolves an import source to a `.ts` file, or null for packages and missing files. */
|
|
57
|
+
export declare const resolveModule: (source: string, fromFile: string, aliases: Record<string, string>) => string | null;
|
|
58
|
+
export interface TypeClassifier {
|
|
59
|
+
/** Why `type` is plain (`string`, `TaskFilters`, `{ … }`), or null when it is acceptable. */
|
|
60
|
+
plainReason: (type: any) => string | null;
|
|
61
|
+
/** The declaration a type name refers to, seen from the linted file. */
|
|
62
|
+
resolve: (name: string) => Declaration | null;
|
|
63
|
+
/** True when the declaration lives under one of `allowTypesFrom`. */
|
|
64
|
+
isAllowedLocation: (file: string) => boolean;
|
|
65
|
+
}
|
|
66
|
+
export declare const typePolicy: (options: Partial<TypePolicy> | undefined, defaults?: Partial<TypePolicy>) => TypePolicy;
|
|
67
|
+
/** A classifier for the file being linted (its own declarations come from `context.sourceCode.ast`). */
|
|
68
|
+
export declare const createTypeClassifier: (context: any, policy: TypePolicy) => TypeClassifier;
|
|
69
|
+
export {};
|