@pjts/eslint-style-rules 0.0.14 → 0.0.16
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 +9 -3
- package/dist/index.d.ts +9 -0
- package/dist/index.js +36 -2
- package/dist/index.js.map +1 -1
- package/dist/lib/ports.d.ts +17 -0
- package/dist/lib/ports.js +101 -0
- package/dist/lib/ports.js.map +1 -0
- package/dist/rules/auth-access.js +14 -1
- package/dist/rules/auth-access.js.map +1 -1
- package/dist/rules/config-provider-only.js +11 -1
- package/dist/rules/config-provider-only.js.map +1 -1
- package/dist/rules/no-comments.d.ts +2 -0
- package/dist/rules/no-comments.js +58 -0
- package/dist/rules/no-comments.js.map +1 -0
- package/dist/rules/no-duplicate-sdk-types.d.ts +1 -4
- package/dist/rules/no-duplicate-sdk-types.js +84 -17
- package/dist/rules/no-duplicate-sdk-types.js.map +1 -1
- package/dist/rules/no-module-state.d.ts +2 -0
- package/dist/rules/no-module-state.js +96 -0
- package/dist/rules/no-module-state.js.map +1 -0
- package/dist/rules/owner-first-ports.d.ts +2 -0
- package/dist/rules/owner-first-ports.js +65 -0
- package/dist/rules/owner-first-ports.js.map +1 -0
- package/dist/rules/pipe-shape.d.ts +2 -0
- package/dist/rules/pipe-shape.js +68 -0
- package/dist/rules/pipe-shape.js.map +1 -0
- package/dist/rules/port-signatures.d.ts +2 -0
- package/dist/rules/port-signatures.js +78 -0
- package/dist/rules/port-signatures.js.map +1 -0
- package/dist/rules/public-endpoints.d.ts +2 -0
- package/dist/rules/public-endpoints.js +70 -0
- package/dist/rules/public-endpoints.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -121,7 +121,8 @@ package or generic type it is accepted, otherwise plain.
|
|
|
121
121
|
| `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) |
|
|
122
122
|
| `save-contract` | `save()`'s result is never used; `save` on `…RepositoryPort` interfaces and repositories (`…Repository` or implementing a `…RepositoryPort`, never `@AppService`) returns `Promise<void>` |
|
|
123
123
|
| `no-entity-mutation-outside-domain` | a loaded entity (`await this.findOne(…)` / `await this.<repo>.find…(…)`) changes through its methods, not `entity.field = …` |
|
|
124
|
-
| `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 |
|
|
124
|
+
| `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. `allowUnread` (opt-in): an unread `_authToken` is reported unless its `Service.method` is listed (capability-authorized endpoints); listed endpoints that read the token are reported as stale |
|
|
125
|
+
| `public-endpoints` | (on with `authAccess`) an `@AppService` endpoint without an `AuthToken` parameter lives in a class matching `publicClassPattern` (`^Public\|Public(View\|Service)$`) or is listed in `allow` (`Service.method`, or `Service` for the whole class); stale entries (the endpoint takes a token, or the class is already public by name) are reported. Preset option `publicEndpoints: { allow }` |
|
|
125
126
|
|
|
126
127
|
### Messages
|
|
127
128
|
|
|
@@ -159,6 +160,8 @@ package or generic type it is accepted, otherwise plain.
|
|
|
159
160
|
| `subclass-declares-constructor` | app and infrastructure classes that `extends` something declare their own constructor (`ignoreBases` for `RepositoryBase` & co.) |
|
|
160
161
|
| `port-file` | ports live in `app/ports/<Name>Port.ts`, one exported interface per file named like it; only types; no `…Port` elsewhere |
|
|
161
162
|
| `port-has-adapters` | every `XPort` in `app/ports/` resolves to exactly one adapter per storage profile the way the container does: `implements` anywhere under `src/modules/**` / `src/common/**` (a prefixed `…XRepository` counts for repository ports), `pg` vs `memory` storage, a composite taking `XPort[]` wins, `@Adapter({ profile })` adapters are left to the profile |
|
|
163
|
+
| `port-signatures` | a class that `implements XPort` declares each port method's parameters in the port's order and under the port's names (`_` prefix allowed, destructured and rest parameters skipped); dropping one is reported — TypeScript accepts a shorter list, so a port that gains a leading owner id would otherwise read it as the entity id. Ports are read from `<src>/modules/**/…Port.ts` and `<src>/common/**`, inherited methods included; overloaded methods are skipped |
|
|
164
|
+
| `owner-first-ports` | in `app/ports/`, a port method taking an owner id (`ownerParams`: `therapistId`, `ownerUserId`, `ownerId`, `userId`) takes it first; `required` (`{ Port: [methods] }`) lists owner-scoped methods that must start with an owner id — a missing method is reported. Preset option `ownerFirst: { ownerParams, required }` |
|
|
162
165
|
| `test-location` | `<TestedFile>.<optional-suffix>.test.ts` sits next to `<TestedFile>.ts`; no `__tests__/` |
|
|
163
166
|
|
|
164
167
|
### Cross-cutting
|
|
@@ -166,10 +169,13 @@ package or generic type it is accepted, otherwise plain.
|
|
|
166
169
|
| Rule | What it checks |
|
|
167
170
|
|---|---|
|
|
168
171
|
| `no-manual-wiring` | no `new X(...)` of an app class (`…Service/View/Handler` from an `app/` path), an adapter (`infrastructure/` path, `Pg…`, `InMemory…`), a module/group class or an application-provided infra class (`JetStreamMessagePublisher`, …) — outside `domain/`, `testing/`, `deployments/`, tests |
|
|
169
|
-
| `
|
|
172
|
+
| `no-comments` | no comments in sources or tests — names, types and small functions explain the code; facts about external systems live in `docs/`. Allowed: tool directives (`eslint-*`, `global`, `@ts-expect-error`/`@ts-ignore`/`@ts-nocheck`, `/// <reference>`, `@vite-ignore`, `#__PURE__`, `prettier-ignore`, `istanbul`/`c8 ignore`, `webpackChunkName`, `@jsx` pragmas) and, with `markers` (default on), a one-line `// FIXME: <decision>` or a bare `// docs/<file>` reference. `allow`: extra patterns |
|
|
173
|
+
| `config-provider-only` | `config.pick/pickMaybe/has` and `process.env` (`processEnv`, default on) only in static config methods of a `…Module`/`…MessageHandlers`/`…Workers` class, under `common/config/` or `deployments/` (`allow`, `moduleStaticMethods`) |
|
|
174
|
+
| `no-module-state` | no process-wide mutable state at module level: top-level `let`/`var`, and top-level `const`s holding a `new Map/Set/WeakMap/WeakSet/Array` or an array literal that is mutated (`push`, `splice`, …). Keep it in an injected class or a private static of the owning class. `collections`: constructor names counted as shared collections. The preset skips `testing/` |
|
|
175
|
+
| `pipe-shape` | pipes are `…Pipe` classes: a class implementing `GlobalPipe` is named `…Pipe`, and `@Pipe(...)` takes exactly `new XPipe(…).pipe` — no inline or curried pipe functions. Options `decorator`, `globalInterfaces`, `suffix`, `property` |
|
|
170
176
|
| `throw-app-error` | only `throw AppError.x(...)` / `throw new AppError(...)` from `@pjts/core`; rethrowing the caught error is allowed |
|
|
171
177
|
| `import-only-in` | a package is imported only under given path fragments (`uuid` → `/domain/`) |
|
|
172
|
-
| `no-duplicate-sdk-types` | frontend: no local type named like one in the generated client's `types.d.ts` |
|
|
178
|
+
| `no-duplicate-sdk-types` | frontend: no local type named like one in the generated client's `types.d.ts`; with `structural` (`true` or `{ minProperties }`, default 3) also no local interface / object type alias whose field names are exactly an SDK type's (a renamed mirror) — the message names every matching SDK type. Interfaces with `extends` are skipped; `allow`: local names exempt (coincidental shapes) |
|
|
173
179
|
| `no-abbreviated-dependencies` | a constructor parameter typed `XyzPort` is named `xyz` — the type name minus a `suffixes` entry (`Port`), lower camel case with leading acronyms lowered (`OfferRepositoryPort` → `offerRepository`, `SMSSenderPort` → `smsSender`); arrays of ports (`XPort[]`, `readonly XPort[]`, `Array<XPort>`) take the plural (`postRegistrationHooks`). A leading `_` is accepted; a type taken more than once may add a qualifier (`sourceOfferRepository`). `keepSuffixes` checks other types keeping the suffix (`Config` → `clinicLimitsConfig: ClinicLimitsConfig`); `allow`: exempt type names. **Auto-fixable** for private parameter properties and plain parameters (renames `this.x` in the class) unless the name is taken; `protected`/`public` ones are reported only |
|
|
174
180
|
|
|
175
181
|
## Limits
|
package/dist/index.d.ts
CHANGED
|
@@ -19,6 +19,15 @@ interface DddConfigOptions {
|
|
|
19
19
|
rightPattern?: string;
|
|
20
20
|
decorator?: string;
|
|
21
21
|
checkParamName?: boolean;
|
|
22
|
+
allowUnread?: string[];
|
|
23
|
+
};
|
|
24
|
+
publicEndpoints?: {
|
|
25
|
+
allow?: string[];
|
|
26
|
+
publicClassPattern?: string;
|
|
27
|
+
};
|
|
28
|
+
ownerFirst?: {
|
|
29
|
+
ownerParams?: string[];
|
|
30
|
+
required?: Record<string, string[]>;
|
|
22
31
|
};
|
|
23
32
|
/** Storage folders of `infrastructure/repositories/<storage>/`, their prefixes and import signatures. */
|
|
24
33
|
storages?: Record<string, {
|
package/dist/index.js
CHANGED
|
@@ -40,6 +40,12 @@ const no_reconstitute_1 = tslib_1.__importDefault(require("./rules/no-reconstitu
|
|
|
40
40
|
const one_class_per_file_1 = tslib_1.__importDefault(require("./rules/one-class-per-file"));
|
|
41
41
|
const port_file_1 = tslib_1.__importDefault(require("./rules/port-file"));
|
|
42
42
|
const port_has_adapters_1 = tslib_1.__importDefault(require("./rules/port-has-adapters"));
|
|
43
|
+
const no_comments_1 = tslib_1.__importDefault(require("./rules/no-comments"));
|
|
44
|
+
const no_module_state_1 = tslib_1.__importDefault(require("./rules/no-module-state"));
|
|
45
|
+
const pipe_shape_1 = tslib_1.__importDefault(require("./rules/pipe-shape"));
|
|
46
|
+
const port_signatures_1 = tslib_1.__importDefault(require("./rules/port-signatures"));
|
|
47
|
+
const owner_first_ports_1 = tslib_1.__importDefault(require("./rules/owner-first-ports"));
|
|
48
|
+
const public_endpoints_1 = tslib_1.__importDefault(require("./rules/public-endpoints"));
|
|
43
49
|
const repository_naming_1 = tslib_1.__importDefault(require("./rules/repository-naming"));
|
|
44
50
|
const repository_return_types_1 = tslib_1.__importDefault(require("./rules/repository-return-types"));
|
|
45
51
|
const repository_serialization_1 = tslib_1.__importDefault(require("./rules/repository-serialization"));
|
|
@@ -88,6 +94,12 @@ const rules = {
|
|
|
88
94
|
'one-class-per-file': one_class_per_file_1.default,
|
|
89
95
|
'port-file': port_file_1.default,
|
|
90
96
|
'port-has-adapters': port_has_adapters_1.default,
|
|
97
|
+
'no-comments': no_comments_1.default,
|
|
98
|
+
'no-module-state': no_module_state_1.default,
|
|
99
|
+
'pipe-shape': pipe_shape_1.default,
|
|
100
|
+
'port-signatures': port_signatures_1.default,
|
|
101
|
+
'owner-first-ports': owner_first_ports_1.default,
|
|
102
|
+
'public-endpoints': public_endpoints_1.default,
|
|
91
103
|
'repository-naming': repository_naming_1.default,
|
|
92
104
|
'repository-return-types': repository_return_types_1.default,
|
|
93
105
|
'repository-serialization': repository_serialization_1.default,
|
|
@@ -103,7 +115,7 @@ const rules = {
|
|
|
103
115
|
const createDddConfig = (options = {}) => {
|
|
104
116
|
// typescript-eslint is a peer dependency: only needed when the preset is used.
|
|
105
117
|
const tseslint = require('typescript-eslint');
|
|
106
|
-
const { src = 'src', modules = 'src/modules', exclude = [`${src}/infrastructure/database/**`, `${src}/deployments/**`], uuidPaths = ['/domain/', `/${src}/common/values/`], messages = `${src}/common/messages`, authAccess = false, storages = {
|
|
118
|
+
const { src = 'src', modules = 'src/modules', exclude = [`${src}/infrastructure/database/**`, `${src}/deployments/**`], uuidPaths = ['/domain/', `/${src}/common/values/`], messages = `${src}/common/messages`, authAccess = false, publicEndpoints = {}, ownerFirst = {}, storages = {
|
|
107
119
|
pg: { prefix: 'Pg', imports: ['@pjts/infra#PostgresDbClient', 'knex', 'pg'] },
|
|
108
120
|
nats: { prefix: 'Nats', imports: ['nats', '@nats-io/*'] },
|
|
109
121
|
memory: { prefix: 'InMemory' },
|
|
@@ -147,6 +159,8 @@ const createDddConfig = (options = {}) => {
|
|
|
147
159
|
'pjts/db-writes-in-repositories': 'error',
|
|
148
160
|
// Environment is read in module static config methods and common/config/ only.
|
|
149
161
|
'pjts/config-provider-only': 'error',
|
|
162
|
+
// Pipes are …Pipe classes: global ones implement GlobalPipe, @Pipe(new XPipe(…).pipe) per endpoint.
|
|
163
|
+
'pjts/pipe-shape': 'error',
|
|
150
164
|
// Class names key the generated wiring and the route registry.
|
|
151
165
|
'pjts/unique-class-names': 'error',
|
|
152
166
|
// Class kinds live in their layer: …Provider classes in infrastructure (app = services, handlers, workers).
|
|
@@ -164,6 +178,10 @@ const createDddConfig = (options = {}) => {
|
|
|
164
178
|
// A port dependency is named after its port: offerRepository: OfferRepositoryPort. Fixable.
|
|
165
179
|
'pjts/no-abbreviated-dependencies': 'error',
|
|
166
180
|
...(authAccess ? { 'pjts/auth-access': ['error', authAccess] } : {}),
|
|
181
|
+
// Endpoints without the caller's token: public classes (Public…, …PublicView) or the allowlist.
|
|
182
|
+
...(authAccess ? { 'pjts/public-endpoints': ['error', publicEndpoints] } : {}),
|
|
183
|
+
// An implementation keeps its port's parameters, names and order (no silently dropped owner id).
|
|
184
|
+
'pjts/port-signatures': 'error',
|
|
167
185
|
},
|
|
168
186
|
},
|
|
169
187
|
{
|
|
@@ -177,6 +195,12 @@ const createDddConfig = (options = {}) => {
|
|
|
177
195
|
'pjts/domain-primitive-properties': ['error', { allowTypesFrom: [messages] }],
|
|
178
196
|
},
|
|
179
197
|
},
|
|
198
|
+
{
|
|
199
|
+
// No process-wide mutable state at module level (top-level let/var, shared Map/Set/arrays).
|
|
200
|
+
files: [`${src}/**/*.ts`],
|
|
201
|
+
ignores: [...exclude, `${module}/testing/**`, `${src}/testing/**`],
|
|
202
|
+
rules: { 'pjts/no-module-state': 'error' },
|
|
203
|
+
},
|
|
180
204
|
{
|
|
181
205
|
// One exported class per file, the file named after it. DTO bundles (app/dto) may group request shapes.
|
|
182
206
|
files: [`${src}/**/*.ts`],
|
|
@@ -269,7 +293,11 @@ const createDddConfig = (options = {}) => {
|
|
|
269
293
|
},
|
|
270
294
|
{
|
|
271
295
|
files: [`${module}/app/ports/*.ts`],
|
|
272
|
-
rules: {
|
|
296
|
+
rules: {
|
|
297
|
+
'pjts/port-has-adapters': 'error',
|
|
298
|
+
// Owner-scoped methods take the owner id first.
|
|
299
|
+
'pjts/owner-first-ports': ['error', ownerFirst],
|
|
300
|
+
},
|
|
273
301
|
},
|
|
274
302
|
{
|
|
275
303
|
// Repositories and their ports return domain classes (UpdateResult for guarded updates), never rows or primitives.
|
|
@@ -309,6 +337,12 @@ const createDddConfig = (options = {}) => {
|
|
|
309
337
|
'pjts/test-location': 'error',
|
|
310
338
|
},
|
|
311
339
|
},
|
|
340
|
+
{
|
|
341
|
+
// No comments in sources or tests: the code explains itself; facts about external systems live in docs/.
|
|
342
|
+
files: [`${src}/**/*.ts`],
|
|
343
|
+
ignores: exclude,
|
|
344
|
+
rules: { 'pjts/no-comments': 'error' },
|
|
345
|
+
},
|
|
312
346
|
];
|
|
313
347
|
};
|
|
314
348
|
const plugin = {
|
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,iFAAgF;AAChF,sGAAoE;AACpE,gFAA+C;AAC/C,sFAAqD;AACrD,oGAAkE;AAClE,kFAAiD;AACjD,0HAAsF;AACtF,oIAAgG;AAChG,gGAA+D;AAC/D,+FAA8F;AAC9F,gGAA8D;AAC9D,0GAAuE;AACvE,sGAAoE;AACpE,8GAA4E;AAC5E,wGAAsE;AACtE,sGAAmE;AACnE,gGAA8D;AAC9D,sGAAoE;AACpE,sFAAoD;AACpD,kGAAgE;AAChE,oFAAkD;AAClD,4EAA2C;AAC3C,kFAAiD;AACjD,oGAAkE;AAClE,gFAA+C;AAC/C,wFAAsD;AACtD,gGAA8D;AAC9D,4FAA0D;AAC1D,kHAAgF;AAChF,4FAAyD;AACzD,4GAAwE;AACxE,8GAA4E;AAC5E,oGAAiE;AACjE,0GAAsE;AACtE,sFAAqD;AACrD,4FAAyD;AACzD,0EAAyC;AACzC,0FAAwD;AACxD,0FAAyD;AACzD,sGAAoE;AACpE,wGAAuE;AACvE,sFAAqD;AACrD,kFAAiD;AACjD,kFAAiD;AACjD,sFAAoD;AAEpD,MAAM,KAAK,GAAG;IACZ,aAAa,EAAE,qBAAU;IACzB,gBAAgB,EAAE,wBAAa;IAC/B,yBAAyB,EAAE,iCAAqB;IAChD,cAAc,EAAE,sBAAW;IAC3B,iBAAiB,EAAE,yBAAc;IACjC,wBAAwB,EAAE,gCAAoB;IAC9C,eAAe,EAAE,uBAAY;IAC7B,mCAAmC,EAAE,2CAA6B;IAClE,wCAAwC,EAAE,gDAAkC;IAC5E,sBAAsB,EAAE,8BAAmB;IAC3C,kBAAkB,EAAE,0BAAc;IAClC,uBAAuB,EAAE,+BAAmB;IAC5C,sBAAsB,EAAE,8BAAkB;IAC1C,2BAA2B,EAAE,mCAAsB;IACnD,0BAA0B,EAAE,kCAAsB;IAClD,yBAAyB,EAAE,iCAAoB;IAC/C,yBAAyB,EAAE,iCAAqB;IAChD,6BAA6B,EAAE,qCAAyB;IACxD,sBAAsB,EAAE,8BAAkB;IAC1C,yBAAyB,EAAE,iCAAqB;IAChD,iBAAiB,EAAE,yBAAa;IAChC,uBAAuB,EAAE,+BAAmB;IAC5C,gBAAgB,EAAE,wBAAY;IAC9B,YAAY,EAAE,oBAAS;IACvB,eAAe,EAAE,uBAAY;IAC7B,wBAAwB,EAAE,gCAAoB;IAC9C,cAAc,EAAE,sBAAW;IAC3B,kBAAkB,EAAE,0BAAc;IAClC,sBAAsB,EAAE,8BAAkB;IAC1C,oBAAoB,EAAE,4BAAgB;IACtC,+BAA+B,EAAE,uCAA2B;IAC5D,oBAAoB,EAAE,4BAAe;IACrC,4BAA4B,EAAE,oCAAsB;IACpD,6BAA6B,EAAE,qCAAyB;IACxD,wBAAwB,EAAE,gCAAmB;IAC7C,2BAA2B,EAAE,mCAAqB;IAClD,iBAAiB,EAAE,yBAAc;IACjC,oBAAoB,EAAE,4BAAe;IACrC,WAAW,EAAE,mBAAQ;IACrB,mBAAmB,EAAE,2BAAe;IACpC,mBAAmB,EAAE,2BAAgB;IACrC,yBAAyB,EAAE,iCAAqB;IAChD,0BAA0B,EAAE,kCAAuB;IACnD,iBAAiB,EAAE,yBAAc;IACjC,eAAe,EAAE,uBAAY;IAC7B,eAAe,EAAE,uBAAY;IAC7B,iBAAiB,EAAE,yBAAa;CACjC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { TSESTree } from '@typescript-eslint/utils';
|
|
2
|
+
export interface PortParameter {
|
|
3
|
+
name: string | null;
|
|
4
|
+
optional: boolean;
|
|
5
|
+
rest: boolean;
|
|
6
|
+
}
|
|
7
|
+
export interface ScannedPort {
|
|
8
|
+
name: string;
|
|
9
|
+
file: string;
|
|
10
|
+
extends: string[];
|
|
11
|
+
methods: Map<string, PortParameter[][]>;
|
|
12
|
+
}
|
|
13
|
+
export declare const parameterOf: (param: TSESTree.Parameter) => PortParameter;
|
|
14
|
+
export declare const portOf: (declaration: TSESTree.TSInterfaceDeclaration, file: string) => ScannedPort;
|
|
15
|
+
export declare const scanPorts: (src: string) => Map<string, ScannedPort>;
|
|
16
|
+
export declare const resetPortScans: () => void;
|
|
17
|
+
export declare const portMethods: (ports: Map<string, ScannedPort>, name: string, seen?: Set<string>) => Map<string, PortParameter[][]>;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.portMethods = exports.resetPortScans = exports.scanPorts = exports.portOf = exports.parameterOf = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const node_fs_1 = tslib_1.__importDefault(require("node:fs"));
|
|
6
|
+
const node_path_1 = tslib_1.__importDefault(require("node:path"));
|
|
7
|
+
const parameterOf = (param) => {
|
|
8
|
+
const node = param.type === 'TSParameterProperty' ? param.parameter : param;
|
|
9
|
+
if (node.type === 'RestElement')
|
|
10
|
+
return { name: node.argument.type === 'Identifier' ? node.argument.name : null, optional: true, rest: true };
|
|
11
|
+
if (node.type === 'AssignmentPattern')
|
|
12
|
+
return { name: node.left.type === 'Identifier' ? node.left.name : null, optional: true, rest: false };
|
|
13
|
+
if (node.type === 'Identifier')
|
|
14
|
+
return { name: node.name, optional: !!node.optional, rest: false };
|
|
15
|
+
return { name: null, optional: false, rest: false };
|
|
16
|
+
};
|
|
17
|
+
exports.parameterOf = parameterOf;
|
|
18
|
+
const signatureParams = (member) => {
|
|
19
|
+
const key = 'key' in member && member.key.type === 'Identifier' && !member.computed ? member.key.name : null;
|
|
20
|
+
if (!key)
|
|
21
|
+
return null;
|
|
22
|
+
if (member.type === 'TSMethodSignature')
|
|
23
|
+
return { name: key, params: member.params };
|
|
24
|
+
if (member.type === 'TSPropertySignature' && member.typeAnnotation?.typeAnnotation.type === 'TSFunctionType') {
|
|
25
|
+
return { name: key, params: member.typeAnnotation.typeAnnotation.params };
|
|
26
|
+
}
|
|
27
|
+
return null;
|
|
28
|
+
};
|
|
29
|
+
const portOf = (declaration, file) => {
|
|
30
|
+
const methods = new Map();
|
|
31
|
+
for (const member of declaration.body.body) {
|
|
32
|
+
const signature = signatureParams(member);
|
|
33
|
+
if (!signature)
|
|
34
|
+
continue;
|
|
35
|
+
methods.set(signature.name, [...(methods.get(signature.name) ?? []), signature.params.map(exports.parameterOf)]);
|
|
36
|
+
}
|
|
37
|
+
const heritage = (declaration.extends ?? [])
|
|
38
|
+
.map((clause) => (clause.expression.type === 'Identifier' ? clause.expression.name : null))
|
|
39
|
+
.filter((name) => name !== null);
|
|
40
|
+
return { name: declaration.id.name, file, extends: heritage, methods };
|
|
41
|
+
};
|
|
42
|
+
exports.portOf = portOf;
|
|
43
|
+
const scans = new Map();
|
|
44
|
+
const scanPorts = (src) => {
|
|
45
|
+
const cached = scans.get(src);
|
|
46
|
+
if (cached)
|
|
47
|
+
return cached;
|
|
48
|
+
const { parser } = require('typescript-eslint');
|
|
49
|
+
const ports = new Map();
|
|
50
|
+
const walk = (current) => {
|
|
51
|
+
if (!node_fs_1.default.existsSync(current))
|
|
52
|
+
return;
|
|
53
|
+
for (const entry of node_fs_1.default.readdirSync(current, { withFileTypes: true })) {
|
|
54
|
+
const full = node_path_1.default.join(current, entry.name);
|
|
55
|
+
if (entry.isDirectory()) {
|
|
56
|
+
if (!/^(__tests?__|test|testing|node_modules)$/.test(entry.name))
|
|
57
|
+
walk(full);
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (!/Port\.ts$/.test(entry.name) || /\.(test|spec|d)\.ts$/.test(entry.name))
|
|
61
|
+
continue;
|
|
62
|
+
const file = full.split(node_path_1.default.sep).join('/');
|
|
63
|
+
let program;
|
|
64
|
+
try {
|
|
65
|
+
program = parser.parseForESLint(node_fs_1.default.readFileSync(full, 'utf8'), { range: true, loc: false }).ast;
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
for (const statement of program.body) {
|
|
71
|
+
const declaration = statement.type === 'ExportNamedDeclaration' ? statement.declaration : statement;
|
|
72
|
+
if (declaration?.type === 'TSInterfaceDeclaration' && /Port$/.test(declaration.id.name)) {
|
|
73
|
+
ports.set(declaration.id.name, (0, exports.portOf)(declaration, file));
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
walk(node_path_1.default.join(src, 'modules'));
|
|
79
|
+
walk(node_path_1.default.join(src, 'common'));
|
|
80
|
+
scans.set(src, ports);
|
|
81
|
+
return ports;
|
|
82
|
+
};
|
|
83
|
+
exports.scanPorts = scanPorts;
|
|
84
|
+
const resetPortScans = () => scans.clear();
|
|
85
|
+
exports.resetPortScans = resetPortScans;
|
|
86
|
+
const portMethods = (ports, name, seen = new Set()) => {
|
|
87
|
+
const port = ports.get(name);
|
|
88
|
+
if (!port || seen.has(name))
|
|
89
|
+
return new Map();
|
|
90
|
+
seen.add(name);
|
|
91
|
+
const methods = new Map();
|
|
92
|
+
for (const parent of port.extends) {
|
|
93
|
+
for (const [method, signatures] of (0, exports.portMethods)(ports, parent, seen))
|
|
94
|
+
methods.set(method, signatures);
|
|
95
|
+
}
|
|
96
|
+
for (const [method, signatures] of port.methods)
|
|
97
|
+
methods.set(method, signatures);
|
|
98
|
+
return methods;
|
|
99
|
+
};
|
|
100
|
+
exports.portMethods = portMethods;
|
|
101
|
+
//# sourceMappingURL=ports.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ports.js","sourceRoot":"","sources":["../../src/lib/ports.ts"],"names":[],"mappings":"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"}
|
|
@@ -31,6 +31,8 @@ exports.default = (0, rule_1.defineRule)({
|
|
|
31
31
|
dynamicRight: 'Access rights are string literals so they can be audited — not `{{text}}`.',
|
|
32
32
|
paramName: 'Name the {{tokenType}} parameter `{{expected}}`.',
|
|
33
33
|
stale: '"{{entry}}" is in the plain-@Auth allowlist but already uses @{{decorator}} — remove it from the list.',
|
|
34
|
+
unread: '`{{method}}` takes the caller\'s {{tokenType}} but never reads it — an endpoint that ignores who calls it cannot check ownership. Read it, or list a capability-authorized endpoint in `allowUnread`.',
|
|
35
|
+
staleUnread: '"{{entry}}" is in `allowUnread` but reads its {{tokenType}} — remove it from the list.',
|
|
34
36
|
},
|
|
35
37
|
schema: [{
|
|
36
38
|
type: 'object',
|
|
@@ -42,12 +44,13 @@ exports.default = (0, rule_1.defineRule)({
|
|
|
42
44
|
rightPattern: { type: 'string' },
|
|
43
45
|
allow: { type: 'array', items: { type: 'string' } },
|
|
44
46
|
checkParamName: { type: 'boolean' },
|
|
47
|
+
allowUnread: { type: 'array', items: { type: 'string' } },
|
|
45
48
|
},
|
|
46
49
|
additionalProperties: false,
|
|
47
50
|
}],
|
|
48
51
|
},
|
|
49
52
|
create(context) {
|
|
50
|
-
const { decorator = 'AuthAccess', plainDecorators = ['Auth'], tokenType = 'AuthToken', serviceDecorators = ['AppService'], rightPattern = '^[a-z][a-z0-9-]*:(read|write)$', allow = [], checkParamName = true, } = context.options[0] ?? {};
|
|
53
|
+
const { decorator = 'AuthAccess', plainDecorators = ['Auth'], tokenType = 'AuthToken', serviceDecorators = ['AppService'], rightPattern = '^[a-z][a-z0-9-]*:(read|write)$', allow = [], checkParamName = true, allowUnread, } = context.options[0] ?? {};
|
|
51
54
|
const pattern = new RegExp(rightPattern);
|
|
52
55
|
const readsParam = (body, name) => {
|
|
53
56
|
let found = false;
|
|
@@ -109,6 +112,16 @@ exports.default = (0, rule_1.defineRule)({
|
|
|
109
112
|
else if (plain && !allowed) {
|
|
110
113
|
context.report({ node: param, messageId: 'plainAuth', data: { method: entry, decorator, tokenType, found: plain.name } });
|
|
111
114
|
}
|
|
115
|
+
if (binding.type === 'Identifier' && (access || plain)) {
|
|
116
|
+
const reads = readsParam(member.value.body, binding.name);
|
|
117
|
+
if (Array.isArray(allowUnread)) {
|
|
118
|
+
const listed = allowUnread.includes(entry) || allowUnread.includes(`${fileBase}.${method}`);
|
|
119
|
+
if (!reads && !listed)
|
|
120
|
+
context.report({ node: binding, messageId: 'unread', data: { method: entry, tokenType } });
|
|
121
|
+
if (reads && listed)
|
|
122
|
+
context.report({ node: binding, messageId: 'staleUnread', data: { entry, tokenType } });
|
|
123
|
+
}
|
|
124
|
+
}
|
|
112
125
|
if (checkParamName && binding.type === 'Identifier' && (access || plain)) {
|
|
113
126
|
const expected = readsParam(member.value.body, binding.name) ? 'authToken' : '_authToken';
|
|
114
127
|
if (binding.name !== expected)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth-access.js","sourceRoot":"","sources":["../../src/rules/auth-access.ts"],"names":[],"mappings":";;AACA,sCAAyC;AACzC,oCAAuE;AACvE,kCAAyC;AAEzC,4CAA4C;AAC5C,MAAM,aAAa,GAAG,CAAC,SAA6B,EAAE,EAAE,CAAC,CAAC;IACxD,IAAI,EAAE,IAAA,mBAAa,EAAC,SAAS,CAAC;IAC9B,IAAI,EAAE,SAAS,CAAC,UAAU,CAAC,IAAI,KAAK,gBAAgB,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE;CAC3F,CAAC,CAAC;AAEH;;;;;;;;;;;GAWG;AACH,kBAAe,IAAA,iBAAU,EAAC;IACxB,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE,EAAE,WAAW,EAAE,yDAAyD,EAAE,GAAG,EAAE,wFAAwF,EAAE;QAC/K,QAAQ,EAAE;YACR,SAAS,EAAE,uHAAuH;YAClI,QAAQ,EAAE,+EAA+E;YACzF,QAAQ,EAAE,gDAAgD;YAC1D,YAAY,EAAE,4EAA4E;YAC1F,SAAS,EAAE,kDAAkD;YAC7D,KAAK,EAAE,wGAAwG;
|
|
1
|
+
{"version":3,"file":"auth-access.js","sourceRoot":"","sources":["../../src/rules/auth-access.ts"],"names":[],"mappings":"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"}
|
|
@@ -11,9 +11,10 @@ const rule_1 = require("../lib/rule");
|
|
|
11
11
|
exports.default = (0, rule_1.defineRule)({
|
|
12
12
|
meta: {
|
|
13
13
|
type: 'suggestion',
|
|
14
|
-
docs: { description: 'config.pick / pickMaybe / has only in config providers', url: 'https://github.com/PiotrJozefow/pjx/tree/master/modules/eslint-style-rules#config-provider-only' },
|
|
14
|
+
docs: { description: 'config.pick / pickMaybe / has and process.env only in config providers', url: 'https://github.com/PiotrJozefow/pjx/tree/master/modules/eslint-style-rules#config-provider-only' },
|
|
15
15
|
messages: {
|
|
16
16
|
outside: '`{{object}}.{{method}}(...)` is allowed only in {{where}} — declare the `…Config` object as a constructor dependency instead.',
|
|
17
|
+
processEnv: '`process.env` is read only in {{where}} — add the variable to the config map and declare the `…Config` object as a constructor dependency instead.',
|
|
17
18
|
},
|
|
18
19
|
schema: [{
|
|
19
20
|
type: 'object',
|
|
@@ -22,6 +23,7 @@ exports.default = (0, rule_1.defineRule)({
|
|
|
22
23
|
methods: { type: 'array', items: { type: 'string' } },
|
|
23
24
|
allow: { type: 'array', items: { type: 'string' } },
|
|
24
25
|
moduleStaticMethods: { type: 'boolean' },
|
|
26
|
+
processEnv: { type: 'boolean' },
|
|
25
27
|
},
|
|
26
28
|
additionalProperties: false,
|
|
27
29
|
}],
|
|
@@ -31,6 +33,7 @@ exports.default = (0, rule_1.defineRule)({
|
|
|
31
33
|
const methods = context.options[0]?.methods ?? ['pick', 'pickMaybe', 'has'];
|
|
32
34
|
const allow = context.options[0]?.allow ?? ['/common/config/', '/deployments/'];
|
|
33
35
|
const moduleStaticMethods = context.options[0]?.moduleStaticMethods ?? true;
|
|
36
|
+
const processEnv = context.options[0]?.processEnv ?? true;
|
|
34
37
|
const file = (0, ast_1.filePath)(context);
|
|
35
38
|
if (allow.some((fragment) => file.includes(fragment)))
|
|
36
39
|
return {};
|
|
@@ -55,6 +58,13 @@ exports.default = (0, rule_1.defineRule)({
|
|
|
55
58
|
return;
|
|
56
59
|
context.report({ node, messageId: 'outside', data: { object, method, where } });
|
|
57
60
|
},
|
|
61
|
+
'MemberExpression[object.type="Identifier"][object.name="process"]'(node) {
|
|
62
|
+
if (!processEnv || (0, ast_1.keyName)(node.property) !== 'env' || node.computed)
|
|
63
|
+
return;
|
|
64
|
+
if (moduleStaticMethods && inModuleStaticMethod(node))
|
|
65
|
+
return;
|
|
66
|
+
context.report({ node, messageId: 'processEnv', data: { where } });
|
|
67
|
+
},
|
|
58
68
|
};
|
|
59
69
|
},
|
|
60
70
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-provider-only.js","sourceRoot":"","sources":["../../src/rules/config-provider-only.ts"],"names":[],"mappings":";;AACA,oCAA+C;AAC/C,sCAAyC;AAEzC;;;;;GAKG;AACH,kBAAe,IAAA,iBAAU,EAAC;IACxB,IAAI,EAAE;QACJ,IAAI,EAAE,YAAY;QAClB,IAAI,EAAE,EAAE,WAAW,EAAE,
|
|
1
|
+
{"version":3,"file":"config-provider-only.js","sourceRoot":"","sources":["../../src/rules/config-provider-only.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const rule_1 = require("../lib/rule");
|
|
4
|
+
const DIRECTIVES = [
|
|
5
|
+
'^\\s*eslint(-disable|-enable|-disable-line|-disable-next-line)?(\\s|$)',
|
|
6
|
+
'^\\s*(global|globals|exported)\\s',
|
|
7
|
+
'^\\s*@ts-(expect-error|ignore|nocheck|check)\\b',
|
|
8
|
+
'^/\\s*<(reference|amd-module|amd-dependency)\\b',
|
|
9
|
+
'^\\s*@vite-ignore\\s*$',
|
|
10
|
+
'^\\s*[#@]__(PURE|NO_SIDE_EFFECTS)__\\s*$',
|
|
11
|
+
'^\\s*prettier-ignore\\b',
|
|
12
|
+
'^\\s*(istanbul|c8|v8) ignore\\b',
|
|
13
|
+
'^\\s*webpack[A-Z]\\w*:',
|
|
14
|
+
'^\\s*@jsx(ImportSource|Frag|Runtime)?\\s',
|
|
15
|
+
'^\\s*@refresh reset\\s*$',
|
|
16
|
+
];
|
|
17
|
+
const MARKERS = [
|
|
18
|
+
'^\\s*FIXME: [^\\n]+$',
|
|
19
|
+
'^\\s*(see )?docs/[\\w./#-]+\\s*$',
|
|
20
|
+
];
|
|
21
|
+
exports.default = (0, rule_1.defineRule)({
|
|
22
|
+
meta: {
|
|
23
|
+
type: 'suggestion',
|
|
24
|
+
docs: {
|
|
25
|
+
description: 'No comments: code explains itself; facts about external systems live in docs/',
|
|
26
|
+
url: 'https://github.com/PiotrJozefow/pjx/tree/master/modules/eslint-style-rules#no-comments',
|
|
27
|
+
},
|
|
28
|
+
messages: {
|
|
29
|
+
comment: 'No comments in code — make the code say it (names, types, a smaller function), or move a fact about an external system to docs/ and reference it (`// docs/<file>.md`).',
|
|
30
|
+
},
|
|
31
|
+
schema: [{
|
|
32
|
+
type: 'object',
|
|
33
|
+
properties: {
|
|
34
|
+
allow: { type: 'array', items: { type: 'string' } },
|
|
35
|
+
markers: { type: 'boolean' },
|
|
36
|
+
},
|
|
37
|
+
additionalProperties: false,
|
|
38
|
+
}],
|
|
39
|
+
},
|
|
40
|
+
create(context) {
|
|
41
|
+
const markers = context.options[0]?.markers ?? true;
|
|
42
|
+
const patterns = [...DIRECTIVES, ...(markers ? MARKERS : []), ...(context.options[0]?.allow ?? [])].map((pattern) => new RegExp(pattern));
|
|
43
|
+
const allowed = (comment) => {
|
|
44
|
+
const text = comment.type === 'Block' ? comment.value.replace(/^\*/, '') : comment.value;
|
|
45
|
+
return patterns.some((pattern) => pattern.test(text));
|
|
46
|
+
};
|
|
47
|
+
return {
|
|
48
|
+
Program() {
|
|
49
|
+
for (const comment of context.sourceCode.getAllComments()) {
|
|
50
|
+
if (comment.type === 'Shebang' || allowed(comment))
|
|
51
|
+
continue;
|
|
52
|
+
context.report({ loc: comment.loc, messageId: 'comment' });
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
//# sourceMappingURL=no-comments.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-comments.js","sourceRoot":"","sources":["../../src/rules/no-comments.ts"],"names":[],"mappings":";;AACA,sCAAyC;AAEzC,MAAM,UAAU,GAAG;IACjB,wEAAwE;IACxE,mCAAmC;IACnC,iDAAiD;IACjD,iDAAiD;IACjD,wBAAwB;IACxB,0CAA0C;IAC1C,yBAAyB;IACzB,iCAAiC;IACjC,wBAAwB;IACxB,0CAA0C;IAC1C,0BAA0B;CAC3B,CAAC;AAEF,MAAM,OAAO,GAAG;IACd,sBAAsB;IACtB,kCAAkC;CACnC,CAAC;AAEF,kBAAe,IAAA,iBAAU,EAAC;IACxB,IAAI,EAAE;QACJ,IAAI,EAAE,YAAY;QAClB,IAAI,EAAE;YACJ,WAAW,EAAE,+EAA+E;YAC5F,GAAG,EAAE,wFAAwF;SAC9F;QACD,QAAQ,EAAE;YACR,OAAO,EAAE,yKAAyK;SACnL;QACD,MAAM,EAAE,CAAC;gBACP,IAAI,EAAE,QAAQ;gBACd,UAAU,EAAE;oBACV,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;oBACnD,OAAO,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;iBAC7B;gBACD,oBAAoB,EAAE,KAAK;aAC5B,CAAC;KACH;IACD,MAAM,CAAC,OAAO;QACZ,MAAM,OAAO,GAAY,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,IAAI,IAAI,CAAC;QAC7D,MAAM,QAAQ,GAAG,CAAC,GAAG,UAAU,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;QAE1I,MAAM,OAAO,GAAG,CAAC,OAAyB,EAAW,EAAE;YACrD,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;YACzF,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QACxD,CAAC,CAAC;QAEF,OAAO;YACL,OAAO;gBACL,KAAK,MAAM,OAAO,IAAI,OAAO,CAAC,UAAU,CAAC,cAAc,EAAE,EAAE,CAAC;oBAC1D,IAAK,OAAO,CAAC,IAAe,KAAK,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC;wBAAE,SAAS;oBACzE,OAAO,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC,CAAC;gBAC7D,CAAC;YACH,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
* the frontend imports wire types from the generated SDK (`api/client/types.d.ts`)
|
|
3
|
-
* instead of re-declaring them. Matches by name, so a renamed hand-written mirror slips through.
|
|
4
|
-
*/
|
|
1
|
+
export declare const resetSdkIndexes: () => void;
|
|
5
2
|
declare const _default: import("@typescript-eslint/utils/dist/ts-eslint").RuleModule<string, any[], unknown, import("@typescript-eslint/utils/dist/ts-eslint").RuleListener>;
|
|
6
3
|
export default _default;
|
|
@@ -1,38 +1,105 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resetSdkIndexes = void 0;
|
|
3
4
|
const tslib_1 = require("tslib");
|
|
4
5
|
const node_fs_1 = tslib_1.__importDefault(require("node:fs"));
|
|
5
6
|
const rule_1 = require("../lib/rule");
|
|
6
|
-
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
const indexes = new Map();
|
|
8
|
+
const memberNames = (members) => {
|
|
9
|
+
const names = [];
|
|
10
|
+
for (const member of members) {
|
|
11
|
+
if (member.type !== 'TSPropertySignature' && member.type !== 'TSMethodSignature')
|
|
12
|
+
return null;
|
|
13
|
+
if (member.computed)
|
|
14
|
+
return null;
|
|
15
|
+
if (member.key.type === 'Identifier')
|
|
16
|
+
names.push(member.key.name);
|
|
17
|
+
else if (member.key.type === 'Literal' && typeof member.key.value === 'string')
|
|
18
|
+
names.push(member.key.value);
|
|
19
|
+
else
|
|
20
|
+
return null;
|
|
12
21
|
}
|
|
13
|
-
return
|
|
22
|
+
return names;
|
|
14
23
|
};
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
24
|
+
const shapeOf = (node) => {
|
|
25
|
+
if (node.type === 'TSInterfaceDeclaration')
|
|
26
|
+
return node.extends?.length ? null : memberNames(node.body.body);
|
|
27
|
+
if (node.type === 'TSTypeAliasDeclaration' && node.typeAnnotation.type === 'TSTypeLiteral')
|
|
28
|
+
return memberNames(node.typeAnnotation.members);
|
|
29
|
+
return null;
|
|
30
|
+
};
|
|
31
|
+
const shapeKey = (names) => [...new Set(names)].sort().join(',');
|
|
32
|
+
const indexOf = (typesFile) => {
|
|
33
|
+
const cached = indexes.get(typesFile);
|
|
34
|
+
if (cached)
|
|
35
|
+
return cached;
|
|
36
|
+
const { parser } = require('typescript-eslint');
|
|
37
|
+
const program = parser.parseForESLint(node_fs_1.default.readFileSync(typesFile, 'utf8'), { range: true, loc: false }).ast;
|
|
38
|
+
const index = { names: new Set(), shapes: new Map() };
|
|
39
|
+
for (const statement of program.body) {
|
|
40
|
+
const declaration = statement.type === 'ExportNamedDeclaration' ? statement.declaration : statement;
|
|
41
|
+
if (!declaration || !('id' in declaration) || declaration.id?.type !== 'Identifier')
|
|
42
|
+
continue;
|
|
43
|
+
if (declaration.type !== 'TSInterfaceDeclaration' && declaration.type !== 'TSTypeAliasDeclaration' && declaration.type !== 'TSEnumDeclaration')
|
|
44
|
+
continue;
|
|
45
|
+
index.names.add(declaration.id.name);
|
|
46
|
+
const shape = shapeOf(declaration);
|
|
47
|
+
if (!shape || shape.length === 0)
|
|
48
|
+
continue;
|
|
49
|
+
const key = shapeKey(shape);
|
|
50
|
+
index.shapes.set(key, [...(index.shapes.get(key) ?? []), declaration.id.name]);
|
|
51
|
+
}
|
|
52
|
+
indexes.set(typesFile, index);
|
|
53
|
+
return index;
|
|
54
|
+
};
|
|
55
|
+
const resetSdkIndexes = () => indexes.clear();
|
|
56
|
+
exports.resetSdkIndexes = resetSdkIndexes;
|
|
19
57
|
exports.default = (0, rule_1.defineRule)({
|
|
20
58
|
meta: {
|
|
21
59
|
type: 'problem',
|
|
22
|
-
docs: { description: 'Forbid re-declaring types that exist in the generated SDK', url: 'https://github.com/PiotrJozefow/pjx/tree/master/modules/eslint-style-rules#no-duplicate-sdk-types' },
|
|
23
|
-
messages: {
|
|
60
|
+
docs: { description: 'Forbid re-declaring types that exist in the generated SDK, by name or by shape', url: 'https://github.com/PiotrJozefow/pjx/tree/master/modules/eslint-style-rules#no-duplicate-sdk-types' },
|
|
61
|
+
messages: {
|
|
62
|
+
duplicate: '"{{name}}" already exists in the generated SDK — import it from api/client/types.',
|
|
63
|
+
structural: '"{{name}}" has exactly the fields of the SDK\'s {{matches}} — import it from api/client/types instead of mirroring it.',
|
|
64
|
+
},
|
|
24
65
|
schema: [{
|
|
25
66
|
type: 'object',
|
|
26
|
-
properties: {
|
|
67
|
+
properties: {
|
|
68
|
+
typesFile: { type: 'string' },
|
|
69
|
+
structural: {
|
|
70
|
+
anyOf: [
|
|
71
|
+
{ type: 'boolean' },
|
|
72
|
+
{ type: 'object', properties: { minProperties: { type: 'integer', minimum: 1 } }, additionalProperties: false },
|
|
73
|
+
],
|
|
74
|
+
},
|
|
75
|
+
allow: { type: 'array', items: { type: 'string' } },
|
|
76
|
+
},
|
|
27
77
|
required: ['typesFile'],
|
|
28
78
|
additionalProperties: false,
|
|
29
79
|
}],
|
|
30
80
|
},
|
|
31
81
|
create(context) {
|
|
32
|
-
const
|
|
82
|
+
const options = context.options[0];
|
|
83
|
+
const index = indexOf(options.typesFile);
|
|
84
|
+
const structural = options.structural;
|
|
85
|
+
const minProperties = typeof structural === 'object' ? structural.minProperties ?? 3 : 3;
|
|
86
|
+
const allow = new Set(options.allow ?? []);
|
|
33
87
|
const check = (node) => {
|
|
34
|
-
|
|
35
|
-
|
|
88
|
+
const name = node.id.name;
|
|
89
|
+
if (allow.has(name))
|
|
90
|
+
return;
|
|
91
|
+
if (index.names.has(name)) {
|
|
92
|
+
context.report({ node: node.id, messageId: 'duplicate', data: { name } });
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
if (!structural || node.type === 'TSEnumDeclaration')
|
|
96
|
+
return;
|
|
97
|
+
const shape = shapeOf(node);
|
|
98
|
+
if (!shape || new Set(shape).size < minProperties)
|
|
99
|
+
return;
|
|
100
|
+
const matches = index.shapes.get(shapeKey(shape));
|
|
101
|
+
if (matches)
|
|
102
|
+
context.report({ node: node.id, messageId: 'structural', data: { name, matches: matches.map((match) => `\`${match}\``).join(' / ') } });
|
|
36
103
|
};
|
|
37
104
|
return { TSInterfaceDeclaration: check, TSTypeAliasDeclaration: check, TSEnumDeclaration: check };
|
|
38
105
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"no-duplicate-sdk-types.js","sourceRoot":"","sources":["../../src/rules/no-duplicate-sdk-types.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"no-duplicate-sdk-types.js","sourceRoot":"","sources":["../../src/rules/no-duplicate-sdk-types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const rule_1 = require("../lib/rule");
|
|
4
|
+
exports.default = (0, rule_1.defineRule)({
|
|
5
|
+
meta: {
|
|
6
|
+
type: 'problem',
|
|
7
|
+
docs: {
|
|
8
|
+
description: 'No mutable module-level state: no top-level let/var and no top-level Map/Set/array instances',
|
|
9
|
+
url: 'https://github.com/PiotrJozefow/pjx/tree/master/modules/eslint-style-rules#no-module-state',
|
|
10
|
+
},
|
|
11
|
+
messages: {
|
|
12
|
+
reassignable: 'Top-level `{{kind}} {{name}}` is process-wide mutable state — keep it in an injected class (or a private static of the class that owns it).',
|
|
13
|
+
collection: 'Top-level `{{name}}` holds a shared `{{type}}` — keep it in an injected class (or a private static of the class that owns it).',
|
|
14
|
+
},
|
|
15
|
+
schema: [{
|
|
16
|
+
type: 'object',
|
|
17
|
+
properties: { collections: { type: 'array', items: { type: 'string' } } },
|
|
18
|
+
additionalProperties: false,
|
|
19
|
+
}],
|
|
20
|
+
},
|
|
21
|
+
create(context) {
|
|
22
|
+
const collections = new Set(context.options[0]?.collections ?? ['Map', 'Set', 'WeakMap', 'WeakSet', 'Array']);
|
|
23
|
+
const label = (declarator) => declarator.id.type === 'Identifier' ? declarator.id.name : context.sourceCode.getText(declarator.id);
|
|
24
|
+
const collectionType = (init) => {
|
|
25
|
+
if (!init)
|
|
26
|
+
return null;
|
|
27
|
+
if (init.type === 'ArrayExpression')
|
|
28
|
+
return 'Array';
|
|
29
|
+
if (init.type === 'NewExpression' && init.callee.type === 'Identifier' && collections.has(init.callee.name))
|
|
30
|
+
return init.callee.name;
|
|
31
|
+
return null;
|
|
32
|
+
};
|
|
33
|
+
const check = (declaration, exported) => {
|
|
34
|
+
if (declaration.declare)
|
|
35
|
+
return;
|
|
36
|
+
for (const declarator of declaration.declarations) {
|
|
37
|
+
if (declaration.kind === 'let' || declaration.kind === 'var') {
|
|
38
|
+
context.report({ node: declarator, messageId: 'reassignable', data: { kind: declaration.kind, name: label(declarator) } });
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
const type = collectionType(declarator.init);
|
|
42
|
+
if (type && isShared(declarator, type, exported)) {
|
|
43
|
+
context.report({ node: declarator, messageId: 'collection', data: { name: label(declarator), type } });
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
const READ_ONLY = {
|
|
48
|
+
collection: new Set(['has', 'get', 'size', 'keys', 'values', 'entries', 'forEach']),
|
|
49
|
+
array: new Set(['length', 'map', 'filter', 'find', 'findIndex', 'some', 'every', 'includes', 'indexOf', 'join', 'slice', 'forEach', 'reduce', 'flatMap', 'concat', 'at', 'entries', 'keys', 'values', 'toSorted']),
|
|
50
|
+
};
|
|
51
|
+
const MUTATORS = new Set(['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse', 'fill', 'copyWithin']);
|
|
52
|
+
const assigned = (member) => (member.parent?.type === 'AssignmentExpression' && member.parent.left === member) || member.parent?.type === 'UpdateExpression';
|
|
53
|
+
const isShared = (declarator, type, exported) => {
|
|
54
|
+
if (declarator.id.type !== 'Identifier')
|
|
55
|
+
return true;
|
|
56
|
+
const literal = type === 'Array' && declarator.init?.type === 'ArrayExpression';
|
|
57
|
+
if (exported && !literal)
|
|
58
|
+
return true;
|
|
59
|
+
const name = declarator.id.name;
|
|
60
|
+
const variable = context.sourceCode.getDeclaredVariables(declarator).find((candidate) => candidate.name === name);
|
|
61
|
+
const references = (variable?.references ?? []).filter((reference) => reference.identifier !== declarator.id);
|
|
62
|
+
if (literal) {
|
|
63
|
+
return references.some((reference) => {
|
|
64
|
+
const parent = reference.identifier.parent;
|
|
65
|
+
if (parent?.type !== 'MemberExpression' || parent.object !== reference.identifier)
|
|
66
|
+
return false;
|
|
67
|
+
return assigned(parent) || (parent.property.type === 'Identifier' && MUTATORS.has(parent.property.name));
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
const allowed = type === 'Array' ? READ_ONLY.array : READ_ONLY.collection;
|
|
71
|
+
return references.some((reference) => {
|
|
72
|
+
const parent = reference.identifier.parent;
|
|
73
|
+
if (parent?.type === 'MemberExpression' && parent.object === reference.identifier) {
|
|
74
|
+
if (assigned(parent))
|
|
75
|
+
return true;
|
|
76
|
+
return parent.computed ? type !== 'Array' : !(parent.property.type === 'Identifier' && allowed.has(parent.property.name));
|
|
77
|
+
}
|
|
78
|
+
if (parent?.type === 'ForOfStatement' && parent.right === reference.identifier)
|
|
79
|
+
return false;
|
|
80
|
+
if (parent?.type === 'SpreadElement')
|
|
81
|
+
return false;
|
|
82
|
+
return true;
|
|
83
|
+
});
|
|
84
|
+
};
|
|
85
|
+
return {
|
|
86
|
+
Program(program) {
|
|
87
|
+
for (const statement of program.body) {
|
|
88
|
+
const declaration = statement.type === 'ExportNamedDeclaration' ? statement.declaration : statement;
|
|
89
|
+
if (declaration?.type === 'VariableDeclaration')
|
|
90
|
+
check(declaration, statement.type === 'ExportNamedDeclaration');
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
//# sourceMappingURL=no-module-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-module-state.js","sourceRoot":"","sources":["../../src/rules/no-module-state.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const rule_1 = require("../lib/rule");
|
|
4
|
+
const ports_1 = require("../lib/ports");
|
|
5
|
+
const ast_1 = require("../lib/ast");
|
|
6
|
+
exports.default = (0, rule_1.defineRule)({
|
|
7
|
+
meta: {
|
|
8
|
+
type: 'problem',
|
|
9
|
+
docs: {
|
|
10
|
+
description: 'Owner-scoped port methods take the owner id as their first parameter',
|
|
11
|
+
url: 'https://github.com/PiotrJozefow/pjx/tree/master/modules/eslint-style-rules#owner-first-ports',
|
|
12
|
+
},
|
|
13
|
+
messages: {
|
|
14
|
+
notFirst: '`{{port}}.{{method}}({{params}})` — the owner `{{owner}}` comes first, so an implementation can\'t read it as the entity id.',
|
|
15
|
+
notOwnerScoped: '`{{port}}.{{method}}({{params}})` is listed as owner-scoped — its first parameter must be an owner id ({{owners}}).',
|
|
16
|
+
missingMethod: '`{{port}}.{{method}}` is listed as owner-scoped but the port has no such method — update the `required` list.',
|
|
17
|
+
},
|
|
18
|
+
schema: [{
|
|
19
|
+
type: 'object',
|
|
20
|
+
properties: {
|
|
21
|
+
ownerParams: { type: 'array', items: { type: 'string' } },
|
|
22
|
+
required: { type: 'object', additionalProperties: { type: 'array', items: { type: 'string' } } },
|
|
23
|
+
suffix: { type: 'string' },
|
|
24
|
+
},
|
|
25
|
+
additionalProperties: false,
|
|
26
|
+
}],
|
|
27
|
+
},
|
|
28
|
+
create(context) {
|
|
29
|
+
const owners = new Set(context.options[0]?.ownerParams ?? ['therapistId', 'ownerUserId', 'ownerId', 'userId']);
|
|
30
|
+
const required = context.options[0]?.required ?? {};
|
|
31
|
+
const suffix = context.options[0]?.suffix ?? 'Port';
|
|
32
|
+
const ownerList = [...owners].map((owner) => `\`${owner}\``).join(', ');
|
|
33
|
+
return {
|
|
34
|
+
TSInterfaceDeclaration(declaration) {
|
|
35
|
+
if (!declaration.id.name.endsWith(suffix))
|
|
36
|
+
return;
|
|
37
|
+
const port = (0, ports_1.portOf)(declaration, (0, ast_1.filePath)(context));
|
|
38
|
+
const listedMethods = new Set(required[port.name] ?? []);
|
|
39
|
+
const nodes = new Map();
|
|
40
|
+
for (const member of declaration.body.body) {
|
|
41
|
+
if ('key' in member && member.key.type === 'Identifier' && !nodes.has(member.key.name))
|
|
42
|
+
nodes.set(member.key.name, member);
|
|
43
|
+
}
|
|
44
|
+
for (const [method, signatures] of port.methods) {
|
|
45
|
+
for (const params of signatures) {
|
|
46
|
+
const names = params.map((param) => param.name?.replace(/^_+/, '') ?? null);
|
|
47
|
+
const text = params.map((param) => param.name ?? '{…}').join(', ');
|
|
48
|
+
const ownerIndex = names.findIndex((name) => name !== null && owners.has(name));
|
|
49
|
+
if (ownerIndex > 0) {
|
|
50
|
+
context.report({ node: nodes.get(method), messageId: 'notFirst', data: { port: port.name, method, params: text, owner: params[ownerIndex].name } });
|
|
51
|
+
}
|
|
52
|
+
else if (listedMethods.has(method) && ownerIndex !== 0) {
|
|
53
|
+
context.report({ node: nodes.get(method), messageId: 'notOwnerScoped', data: { port: port.name, method, params: text, owners: ownerList } });
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
for (const method of listedMethods) {
|
|
58
|
+
if (!port.methods.has(method))
|
|
59
|
+
context.report({ node: declaration.id, messageId: 'missingMethod', data: { port: port.name, method } });
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
//# sourceMappingURL=owner-first-ports.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"owner-first-ports.js","sourceRoot":"","sources":["../../src/rules/owner-first-ports.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const rule_1 = require("../lib/rule");
|
|
4
|
+
const ast_1 = require("../lib/ast");
|
|
5
|
+
exports.default = (0, rule_1.defineRule)({
|
|
6
|
+
meta: {
|
|
7
|
+
type: 'suggestion',
|
|
8
|
+
docs: {
|
|
9
|
+
description: 'Pipes are `…Pipe` classes: global pipes implement GlobalPipe, `@Pipe(...)` takes `new XPipe(…).pipe`',
|
|
10
|
+
url: 'https://github.com/PiotrJozefow/pjx/tree/master/modules/eslint-style-rules#pipe-shape',
|
|
11
|
+
},
|
|
12
|
+
messages: {
|
|
13
|
+
globalName: '`{{name}}` implements `{{interface}}` — name it `…{{suffix}}`.',
|
|
14
|
+
decoratorArgument: '`@{{decorator}}(...)` takes a pipe class instance\'s `pipe`: `@{{decorator}}(new X{{suffix}}(…).pipe)` — not `{{text}}`.',
|
|
15
|
+
},
|
|
16
|
+
schema: [{
|
|
17
|
+
type: 'object',
|
|
18
|
+
properties: {
|
|
19
|
+
decorator: { type: 'string' },
|
|
20
|
+
globalInterfaces: { type: 'array', items: { type: 'string' } },
|
|
21
|
+
suffix: { type: 'string' },
|
|
22
|
+
property: { type: 'string' },
|
|
23
|
+
},
|
|
24
|
+
additionalProperties: false,
|
|
25
|
+
}],
|
|
26
|
+
},
|
|
27
|
+
create(context) {
|
|
28
|
+
const decorator = context.options[0]?.decorator ?? 'Pipe';
|
|
29
|
+
const globalInterfaces = new Set(context.options[0]?.globalInterfaces ?? ['GlobalPipe']);
|
|
30
|
+
const suffix = context.options[0]?.suffix ?? 'Pipe';
|
|
31
|
+
const property = context.options[0]?.property ?? 'pipe';
|
|
32
|
+
const isPipeInstance = (argument) => argument.type === 'MemberExpression'
|
|
33
|
+
&& !argument.computed
|
|
34
|
+
&& argument.property.type === 'Identifier'
|
|
35
|
+
&& argument.property.name === property
|
|
36
|
+
&& argument.object.type === 'NewExpression'
|
|
37
|
+
&& argument.object.callee.type === 'Identifier'
|
|
38
|
+
&& argument.object.callee.name.endsWith(suffix);
|
|
39
|
+
const checkClass = (classNode) => {
|
|
40
|
+
if (!classNode.id)
|
|
41
|
+
return;
|
|
42
|
+
const name = classNode.id.name;
|
|
43
|
+
for (const clause of classNode.implements ?? []) {
|
|
44
|
+
if (clause.expression.type !== 'Identifier' || !globalInterfaces.has(clause.expression.name))
|
|
45
|
+
continue;
|
|
46
|
+
if (!name.endsWith(suffix))
|
|
47
|
+
context.report({ node: classNode.id, messageId: 'globalName', data: { name, interface: clause.expression.name, suffix } });
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
return {
|
|
51
|
+
ClassDeclaration: checkClass,
|
|
52
|
+
ClassExpression: checkClass,
|
|
53
|
+
Decorator(node) {
|
|
54
|
+
if ((0, ast_1.decoratorName)(node) !== decorator || node.expression.type !== 'CallExpression')
|
|
55
|
+
return;
|
|
56
|
+
const [argument] = node.expression.arguments;
|
|
57
|
+
if (argument && node.expression.arguments.length === 1 && isPipeInstance(argument))
|
|
58
|
+
return;
|
|
59
|
+
context.report({
|
|
60
|
+
node: node.expression,
|
|
61
|
+
messageId: 'decoratorArgument',
|
|
62
|
+
data: { decorator, suffix, text: context.sourceCode.getText(node.expression) },
|
|
63
|
+
});
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
//# sourceMappingURL=pipe-shape.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipe-shape.js","sourceRoot":"","sources":["../../src/rules/pipe-shape.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const rule_1 = require("../lib/rule");
|
|
4
|
+
const ast_1 = require("../lib/ast");
|
|
5
|
+
const ports_1 = require("../lib/ports");
|
|
6
|
+
const wiring_1 = require("../lib/wiring");
|
|
7
|
+
const bare = (name) => (name === null ? null : name.replace(/^_+/, ''));
|
|
8
|
+
const listed = (params) => params.map((param) => param.name ?? '{…}').join(', ');
|
|
9
|
+
exports.default = (0, rule_1.defineRule)({
|
|
10
|
+
meta: {
|
|
11
|
+
type: 'problem',
|
|
12
|
+
docs: {
|
|
13
|
+
description: 'An implementation of a port declares the port method\'s parameters, in order and by name',
|
|
14
|
+
url: 'https://github.com/PiotrJozefow/pjx/tree/master/modules/eslint-style-rules#port-signatures',
|
|
15
|
+
},
|
|
16
|
+
messages: {
|
|
17
|
+
missing: '`{{method}}({{actual}})` drops {{dropped}} of `{{port}}.{{name}}({{expected}})` — declare every port parameter (`_` prefix when unused), so a reordered port signature fails here.',
|
|
18
|
+
renamed: '`{{method}}` names parameter {{position}} `{{actual}}`, `{{port}}.{{name}}` names it `{{expected}}` — keep the port\'s names and order.',
|
|
19
|
+
},
|
|
20
|
+
schema: [{
|
|
21
|
+
type: 'object',
|
|
22
|
+
properties: { suffix: { type: 'string' } },
|
|
23
|
+
additionalProperties: false,
|
|
24
|
+
}],
|
|
25
|
+
},
|
|
26
|
+
create(context) {
|
|
27
|
+
const suffix = context.options[0]?.suffix ?? 'Port';
|
|
28
|
+
const src = (0, wiring_1.srcRoot)(context);
|
|
29
|
+
if (!src)
|
|
30
|
+
return {};
|
|
31
|
+
const check = (classNode) => {
|
|
32
|
+
const implemented = (classNode.implements ?? [])
|
|
33
|
+
.map((clause) => (clause.expression.type === 'Identifier' ? clause.expression.name : null))
|
|
34
|
+
.filter((name) => name !== null && name.endsWith(suffix));
|
|
35
|
+
if (implemented.length === 0)
|
|
36
|
+
return;
|
|
37
|
+
const ports = (0, ports_1.scanPorts)(src);
|
|
38
|
+
const className = classNode.id?.name ?? 'class';
|
|
39
|
+
for (const port of implemented) {
|
|
40
|
+
const methods = (0, ports_1.portMethods)(ports, port);
|
|
41
|
+
for (const member of classNode.body.body) {
|
|
42
|
+
if (member.type !== 'MethodDefinition' || member.kind !== 'method' || member.static)
|
|
43
|
+
continue;
|
|
44
|
+
const name = (0, ast_1.memberName)(member);
|
|
45
|
+
const signatures = name ? methods.get(name) : undefined;
|
|
46
|
+
if (!name || !signatures || signatures.length !== 1)
|
|
47
|
+
continue;
|
|
48
|
+
const expected = signatures[0];
|
|
49
|
+
const actual = member.value.params.map(ports_1.parameterOf);
|
|
50
|
+
const method = `${className}.${name}`;
|
|
51
|
+
const required = expected.filter((param) => !param.rest);
|
|
52
|
+
if (actual.filter((param) => !param.rest).length < required.length && !actual.some((param) => param.rest)) {
|
|
53
|
+
const dropped = required.slice(actual.length).map((param) => `\`${param.name ?? '{…}'}\``).join(', ');
|
|
54
|
+
context.report({
|
|
55
|
+
node: member.key,
|
|
56
|
+
messageId: 'missing',
|
|
57
|
+
data: { method, actual: listed(actual), dropped, port, name, expected: listed(expected) },
|
|
58
|
+
});
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
for (let index = 0; index < Math.min(actual.length, expected.length); index++) {
|
|
62
|
+
const want = bare(expected[index].name);
|
|
63
|
+
const have = bare(actual[index].name);
|
|
64
|
+
if (want === null || have === null || want === have || actual[index].rest || expected[index].rest)
|
|
65
|
+
continue;
|
|
66
|
+
context.report({
|
|
67
|
+
node: member.value.params[index],
|
|
68
|
+
messageId: 'renamed',
|
|
69
|
+
data: { method, position: String(index + 1), actual: actual[index].name, port, name, expected: expected[index].name },
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
return { ClassDeclaration: check, ClassExpression: check };
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
//# sourceMappingURL=port-signatures.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"port-signatures.js","sourceRoot":"","sources":["../../src/rules/port-signatures.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const rule_1 = require("../lib/rule");
|
|
4
|
+
const ast_1 = require("../lib/ast");
|
|
5
|
+
const db_1 = require("../lib/db");
|
|
6
|
+
exports.default = (0, rule_1.defineRule)({
|
|
7
|
+
meta: {
|
|
8
|
+
type: 'problem',
|
|
9
|
+
docs: {
|
|
10
|
+
description: 'An endpoint without the caller\'s token lives in a public class or is listed as public',
|
|
11
|
+
url: 'https://github.com/PiotrJozefow/pjx/tree/master/modules/eslint-style-rules#public-endpoints',
|
|
12
|
+
},
|
|
13
|
+
messages: {
|
|
14
|
+
unauthenticated: '`{{endpoint}}` takes no `{{tokenType}}` — anyone can call it. Authenticate it, move it to a public class ({{pattern}}), or list it in `allow`.',
|
|
15
|
+
stale: '"{{entry}}" is in the public-endpoint allowlist but {{reason}} — remove it from the list.',
|
|
16
|
+
},
|
|
17
|
+
schema: [{
|
|
18
|
+
type: 'object',
|
|
19
|
+
properties: {
|
|
20
|
+
tokenType: { type: 'string' },
|
|
21
|
+
serviceDecorators: { type: 'array', items: { type: 'string' } },
|
|
22
|
+
publicClassPattern: { type: 'string' },
|
|
23
|
+
allow: { type: 'array', items: { type: 'string' } },
|
|
24
|
+
},
|
|
25
|
+
additionalProperties: false,
|
|
26
|
+
}],
|
|
27
|
+
},
|
|
28
|
+
create(context) {
|
|
29
|
+
const { tokenType = 'AuthToken', serviceDecorators = ['AppService'], publicClassPattern = '^Public|Public(View|Service)$', allow = [], } = context.options[0] ?? {};
|
|
30
|
+
const pattern = new RegExp(publicClassPattern);
|
|
31
|
+
const allowed = new Set(allow);
|
|
32
|
+
const takesToken = (method) => method.value.params.some((param) => {
|
|
33
|
+
const binding = (0, db_1.paramBinding)(param);
|
|
34
|
+
const type = 'typeAnnotation' in binding ? binding.typeAnnotation?.typeAnnotation : undefined;
|
|
35
|
+
return type?.type === 'TSTypeReference' && type.typeName.type === 'Identifier' && type.typeName.name === tokenType;
|
|
36
|
+
});
|
|
37
|
+
return {
|
|
38
|
+
ClassDeclaration(classNode) {
|
|
39
|
+
if (!classNode.id || !(0, ast_1.decoratorNames)(classNode).some((name) => serviceDecorators.includes(name)))
|
|
40
|
+
return;
|
|
41
|
+
const service = classNode.id.name;
|
|
42
|
+
const publicClass = pattern.test(service);
|
|
43
|
+
const endpoints = classNode.body.body.filter((member) => member.type === 'MethodDefinition' && member.kind === 'method' && !member.static && member.accessibility !== 'private' && member.accessibility !== 'protected' && member.key.type !== 'PrivateIdentifier');
|
|
44
|
+
let unauthenticated = 0;
|
|
45
|
+
for (const endpoint of endpoints) {
|
|
46
|
+
const method = (0, ast_1.memberName)(endpoint) ?? '';
|
|
47
|
+
const entry = `${service}.${method}`;
|
|
48
|
+
if (takesToken(endpoint)) {
|
|
49
|
+
if (allowed.has(entry))
|
|
50
|
+
context.report({ node: endpoint.key, messageId: 'stale', data: { entry, reason: `it takes a \`${tokenType}\`` } });
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
unauthenticated++;
|
|
54
|
+
if (publicClass) {
|
|
55
|
+
if (allowed.has(entry))
|
|
56
|
+
context.report({ node: endpoint.key, messageId: 'stale', data: { entry, reason: `\`${service}\` is already public by name` } });
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
if (allowed.has(entry) || allowed.has(service))
|
|
60
|
+
continue;
|
|
61
|
+
context.report({ node: endpoint.key, messageId: 'unauthenticated', data: { endpoint: entry, tokenType, pattern: `/${publicClassPattern}/` } });
|
|
62
|
+
}
|
|
63
|
+
if (allowed.has(service) && (publicClass || unauthenticated === 0)) {
|
|
64
|
+
context.report({ node: classNode.id, messageId: 'stale', data: { entry: service, reason: publicClass ? 'it is already public by name' : `every endpoint takes a \`${tokenType}\`` } });
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
//# sourceMappingURL=public-endpoints.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"public-endpoints.js","sourceRoot":"","sources":["../../src/rules/public-endpoints.ts"],"names":[],"mappings":"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"}
|