@pjts/eslint-style-rules 0.0.14 → 0.0.15
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 +4 -1
- package/dist/index.d.ts +9 -0
- package/dist/index.js +16 -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/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/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
|
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,9 @@ 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 port_signatures_1 = tslib_1.__importDefault(require("./rules/port-signatures"));
|
|
44
|
+
const owner_first_ports_1 = tslib_1.__importDefault(require("./rules/owner-first-ports"));
|
|
45
|
+
const public_endpoints_1 = tslib_1.__importDefault(require("./rules/public-endpoints"));
|
|
43
46
|
const repository_naming_1 = tslib_1.__importDefault(require("./rules/repository-naming"));
|
|
44
47
|
const repository_return_types_1 = tslib_1.__importDefault(require("./rules/repository-return-types"));
|
|
45
48
|
const repository_serialization_1 = tslib_1.__importDefault(require("./rules/repository-serialization"));
|
|
@@ -88,6 +91,9 @@ const rules = {
|
|
|
88
91
|
'one-class-per-file': one_class_per_file_1.default,
|
|
89
92
|
'port-file': port_file_1.default,
|
|
90
93
|
'port-has-adapters': port_has_adapters_1.default,
|
|
94
|
+
'port-signatures': port_signatures_1.default,
|
|
95
|
+
'owner-first-ports': owner_first_ports_1.default,
|
|
96
|
+
'public-endpoints': public_endpoints_1.default,
|
|
91
97
|
'repository-naming': repository_naming_1.default,
|
|
92
98
|
'repository-return-types': repository_return_types_1.default,
|
|
93
99
|
'repository-serialization': repository_serialization_1.default,
|
|
@@ -103,7 +109,7 @@ const rules = {
|
|
|
103
109
|
const createDddConfig = (options = {}) => {
|
|
104
110
|
// typescript-eslint is a peer dependency: only needed when the preset is used.
|
|
105
111
|
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 = {
|
|
112
|
+
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
113
|
pg: { prefix: 'Pg', imports: ['@pjts/infra#PostgresDbClient', 'knex', 'pg'] },
|
|
108
114
|
nats: { prefix: 'Nats', imports: ['nats', '@nats-io/*'] },
|
|
109
115
|
memory: { prefix: 'InMemory' },
|
|
@@ -164,6 +170,10 @@ const createDddConfig = (options = {}) => {
|
|
|
164
170
|
// A port dependency is named after its port: offerRepository: OfferRepositoryPort. Fixable.
|
|
165
171
|
'pjts/no-abbreviated-dependencies': 'error',
|
|
166
172
|
...(authAccess ? { 'pjts/auth-access': ['error', authAccess] } : {}),
|
|
173
|
+
// Endpoints without the caller's token: public classes (Public…, …PublicView) or the allowlist.
|
|
174
|
+
...(authAccess ? { 'pjts/public-endpoints': ['error', publicEndpoints] } : {}),
|
|
175
|
+
// An implementation keeps its port's parameters, names and order (no silently dropped owner id).
|
|
176
|
+
'pjts/port-signatures': 'error',
|
|
167
177
|
},
|
|
168
178
|
},
|
|
169
179
|
{
|
|
@@ -269,7 +279,11 @@ const createDddConfig = (options = {}) => {
|
|
|
269
279
|
},
|
|
270
280
|
{
|
|
271
281
|
files: [`${module}/app/ports/*.ts`],
|
|
272
|
-
rules: {
|
|
282
|
+
rules: {
|
|
283
|
+
'pjts/port-has-adapters': 'error',
|
|
284
|
+
// Owner-scoped methods take the owner id first.
|
|
285
|
+
'pjts/owner-first-ports': ['error', ownerFirst],
|
|
286
|
+
},
|
|
273
287
|
},
|
|
274
288
|
{
|
|
275
289
|
// Repositories and their ports return domain classes (UpdateResult for guarded updates), never rows or primitives.
|
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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"}
|
|
@@ -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,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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"}
|