pipework 0.270.0 → 0.271.0

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/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.271.0
4
+
5
+ - **Added: the doctrine rules run in eslint** (#947). `define/prefer-pipe-define`, `define/no-raw-pgTable`, `define/brand-primary-key` and `define/use-traits` are now ESLint rules in the lint preset, on at `error`, with the same ids, lines and messages `pipework check`'s doctrine step reports, from one shared implementation. `pipework lint`, editors and plain `eslint` with the generated config see them per file; test files and `.d.ts` are not judged. Turn one off through `lint.extra` rules like any preset rule. `check` keeps its doctrine step, so a finding in a linted file may appear in both steps.
6
+
3
7
  ## 0.270.0
4
8
 
5
9
  - **Added: check's steps run on their own, with JSON per violation** (#946). `pipework doctrine`, `pipework flow`, `pipework cardinality` and `pipework startup` each run one step of `check`, with `--format json` (a record of `rule`, `file`, `line`, `message` per violation and one entry per scanned file), `--output-file <path>`, the scope flags, and for the first three explicit file paths. `pipework check` gains `--format json` (one record per step) and `--only` / `--skip` by step name; a step not selected is reported as skipped, never passed. Each record's `reads` and REFERENCE.md say what a verdict depends on: doctrine and flow read only the file; cardinality cycles and the derived cap read every scanned file.
package/REFERENCE.md CHANGED
@@ -605,6 +605,8 @@ Thrown for configuration problems — includes a suggestion for how to fix.
605
605
 
606
606
  Generated module manifests declare `"lint": "pipework lint"` and `"type-check": "tsc --noEmit -p tsconfig.check.json"` (the config `check` type-checks with, which resolves sibling packages from source), so `pnpm -C <module> run lint --format json --output-file r.json <file>` gives `check`'s verdict for that file. `test` stays `vitest run`: `pipework test` provisions test databases and project filters that a bare `vitest run` in a module does not. Run `pipework sync` (or `pipework install`) to regenerate the manifests and `eslint.config.js`.
607
607
 
608
+ The lint preset also carries the four doctrine rules at `error`: `define/prefer-pipe-define`, `define/no-raw-pgTable`, `define/brand-primary-key` and `define/use-traits`. They are the same scans `pipework check`'s doctrine step runs (one implementation, same file, line and message), skip test files and `.d.ts`, and can be turned off through `lint.extra` rules like any preset rule. `check` keeps its doctrine step for files outside the lint globs, so a finding in a linted file can appear in both steps.
609
+
608
610
  `lint.modules.<path>` overrides apply per file: the root `eslint.config.js` carries each module's `rules` and `configs` with their `files` and `ignores` globs prefixed by the module's path, so plain `eslint <file>` from the workspace root or a module directory agrees with `pipework check`.
609
611
 
610
612
  ### `pipework check` steps
@@ -9,6 +9,10 @@ export declare const rules: {
9
9
  readonly '@typescript-eslint/no-unnecessary-condition': "error";
10
10
  readonly '@typescript-eslint/strict-boolean-expressions': "error";
11
11
  readonly 'pipework/no-reexports': "error";
12
+ readonly 'define/prefer-pipe-define': "error";
13
+ readonly 'define/no-raw-pgTable': "error";
14
+ readonly 'define/brand-primary-key': "error";
15
+ readonly 'define/use-traits': "error";
12
16
  };
13
17
  export interface LintOptions {
14
18
  readonly tsconfigRootDir?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lint/config.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,KAAK;;;;;;;;;;;CASR,CAAA;AAEV,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAA;IACjC,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACpC,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACpC,QAAQ,CAAC,UAAU,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;IACvD,QAAQ,CAAC,YAAY,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;IACzD,QAAQ,CAAC,YAAY,CAAC,EAAE,SAAS,OAAO,EAAE,CAAA;CAC3C;AAED,wBAAgB,gBAAgB,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,EAAE,CA+BhE"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lint/config.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,KAAK;;;;;;;;;;;;;;;CAaR,CAAA;AAEV,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAA;IACjC,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACpC,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACpC,QAAQ,CAAC,UAAU,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;IACvD,QAAQ,CAAC,YAAY,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;IACzD,QAAQ,CAAC,YAAY,CAAC,EAAE,SAAS,OAAO,EAAE,CAAA;CAC3C;AAED,wBAAgB,gBAAgB,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,EAAE,CAgChE"}
@@ -1,6 +1,7 @@
1
1
  import tseslint from '@typescript-eslint/eslint-plugin';
2
2
  import tsparser from '@typescript-eslint/parser';
3
3
  import { noReexports } from './rules/no-reexports.js';
4
+ import { doctrineRules } from './rules/doctrine.js';
4
5
  export const rules = {
5
6
  '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
6
7
  '@typescript-eslint/no-explicit-any': 'error',
@@ -10,6 +11,10 @@ export const rules = {
10
11
  '@typescript-eslint/no-unnecessary-condition': 'error',
11
12
  '@typescript-eslint/strict-boolean-expressions': 'error',
12
13
  'pipework/no-reexports': 'error',
14
+ 'define/prefer-pipe-define': 'error',
15
+ 'define/no-raw-pgTable': 'error',
16
+ 'define/brand-primary-key': 'error',
17
+ 'define/use-traits': 'error',
13
18
  };
14
19
  export function createLintConfig(config) {
15
20
  const files = config?.include ?? ['src/**/*.ts', 'src/**/*.tsx'];
@@ -21,6 +26,7 @@ export function createLintConfig(config) {
21
26
  const appliedPlugins = {
22
27
  '@typescript-eslint': tseslint,
23
28
  'pipework': { rules: { 'no-reexports': noReexports } },
29
+ 'define': { rules: doctrineRules },
24
30
  ...config?.extraPlugins,
25
31
  };
26
32
  const blocks = [
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lint/config.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,kCAAkC,CAAA;AACvD,OAAO,QAAQ,MAAM,2BAA2B,CAAA;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAErD,MAAM,CAAC,MAAM,KAAK,GAAG;IACnB,mCAAmC,EAAE,CAAC,OAAO,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE,CAAC;IAC3E,oCAAoC,EAAE,OAAO;IAC7C,yCAAyC,EAAE,OAAO;IAClD,wCAAwC,EAAE,OAAO;IACjD,kCAAkC,EAAE,OAAO;IAC3C,6CAA6C,EAAE,OAAO;IACtD,+CAA+C,EAAE,OAAO;IACxD,uBAAuB,EAAE,OAAO;CACxB,CAAA;AAWV,MAAM,UAAU,gBAAgB,CAAC,MAAoB;IACnD,MAAM,KAAK,GAAG,MAAM,EAAE,OAAO,IAAI,CAAC,aAAa,EAAE,cAAc,CAAC,CAAA;IAChE,MAAM,aAAa,GAA4B,EAAE,cAAc,EAAE,IAAI,EAAE,CAAA;IACvE,IAAI,MAAM,EAAE,eAAe,KAAK,SAAS,EAAE,CAAC;QAC1C,aAAa,CAAC,iBAAiB,CAAC,GAAG,MAAM,CAAC,eAAe,CAAA;IAC3D,CAAC;IAED,MAAM,YAAY,GAAG,EAAE,GAAG,KAAK,EAAE,GAAG,MAAM,EAAE,UAAU,EAAE,CAAA;IACxD,MAAM,cAAc,GAA4B;QAC9C,oBAAoB,EAAE,QAAQ;QAC9B,UAAU,EAAE,EAAE,KAAK,EAAE,EAAE,cAAc,EAAE,WAAW,EAAE,EAAE;QACtD,GAAG,MAAM,EAAE,YAAY;KACxB,CAAA;IAED,MAAM,MAAM,GAAc;QACxB;YACE,KAAK,EAAE,CAAC,GAAG,KAAK,CAAC;YACjB,eAAe,EAAE;gBACf,MAAM,EAAE,QAAQ;gBAChB,aAAa;aACd;YACD,OAAO,EAAE,cAAc;YACvB,KAAK,EAAE,YAAY;SACpB;QACD,GAAG,CAAC,MAAM,EAAE,YAAY,IAAI,EAAE,CAAC;QAC/B;YACE,OAAO,EAAE,CAAC,OAAO,EAAE,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,IAAI,EAAE,CAAC,CAAC;SAChE;KACF,CAAA;IAED,OAAO,MAAM,CAAA;AACf,CAAC"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lint/config.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,kCAAkC,CAAA;AACvD,OAAO,QAAQ,MAAM,2BAA2B,CAAA;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAEnD,MAAM,CAAC,MAAM,KAAK,GAAG;IACnB,mCAAmC,EAAE,CAAC,OAAO,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE,CAAC;IAC3E,oCAAoC,EAAE,OAAO;IAC7C,yCAAyC,EAAE,OAAO;IAClD,wCAAwC,EAAE,OAAO;IACjD,kCAAkC,EAAE,OAAO;IAC3C,6CAA6C,EAAE,OAAO;IACtD,+CAA+C,EAAE,OAAO;IACxD,uBAAuB,EAAE,OAAO;IAChC,2BAA2B,EAAE,OAAO;IACpC,uBAAuB,EAAE,OAAO;IAChC,0BAA0B,EAAE,OAAO;IACnC,mBAAmB,EAAE,OAAO;CACpB,CAAA;AAWV,MAAM,UAAU,gBAAgB,CAAC,MAAoB;IACnD,MAAM,KAAK,GAAG,MAAM,EAAE,OAAO,IAAI,CAAC,aAAa,EAAE,cAAc,CAAC,CAAA;IAChE,MAAM,aAAa,GAA4B,EAAE,cAAc,EAAE,IAAI,EAAE,CAAA;IACvE,IAAI,MAAM,EAAE,eAAe,KAAK,SAAS,EAAE,CAAC;QAC1C,aAAa,CAAC,iBAAiB,CAAC,GAAG,MAAM,CAAC,eAAe,CAAA;IAC3D,CAAC;IAED,MAAM,YAAY,GAAG,EAAE,GAAG,KAAK,EAAE,GAAG,MAAM,EAAE,UAAU,EAAE,CAAA;IACxD,MAAM,cAAc,GAA4B;QAC9C,oBAAoB,EAAE,QAAQ;QAC9B,UAAU,EAAE,EAAE,KAAK,EAAE,EAAE,cAAc,EAAE,WAAW,EAAE,EAAE;QACtD,QAAQ,EAAE,EAAE,KAAK,EAAE,aAAa,EAAE;QAClC,GAAG,MAAM,EAAE,YAAY;KACxB,CAAA;IAED,MAAM,MAAM,GAAc;QACxB;YACE,KAAK,EAAE,CAAC,GAAG,KAAK,CAAC;YACjB,eAAe,EAAE;gBACf,MAAM,EAAE,QAAQ;gBAChB,aAAa;aACd;YACD,OAAO,EAAE,cAAc;YACvB,KAAK,EAAE,YAAY;SACpB;QACD,GAAG,CAAC,MAAM,EAAE,YAAY,IAAI,EAAE,CAAC;QAC/B;YACE,OAAO,EAAE,CAAC,OAAO,EAAE,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,IAAI,EAAE,CAAC,CAAC;SAChE;KACF,CAAA;IAED,OAAO,MAAM,CAAA;AACf,CAAC"}
@@ -11,6 +11,8 @@ export interface DoctrineResult {
11
11
  readonly scannedFiles: readonly string[];
12
12
  }
13
13
  export declare function validateDoctrine(cwd: string, sourceFiles: readonly string[]): DoctrineResult;
14
+ /** The four doctrine scans over one file's text; shared by `check` and the eslint rules. */
15
+ export declare function doctrineViolations(file: string, content: string): DoctrineViolation[];
14
16
  export declare function findSourceFiles(cwd: string, modulePaths: readonly string[]): string[];
15
17
  /** A `.ts` or `.tsx` source: not a test file, not a declaration file. */
16
18
  export declare function isSourceFileName(name: string): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"doctrine.d.ts","sourceRoot":"","sources":["../../src/lint/doctrine.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CACzB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,UAAU,EAAE,SAAS,iBAAiB,EAAE,CAAA;IACjD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,qEAAqE;IACrE,QAAQ,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAA;CACzC;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS,MAAM,EAAE,GAAG,cAAc,CAqB5F;AAiGD,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,EAAE,CAUrF;AAED,yEAAyE;AACzE,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAItD"}
1
+ {"version":3,"file":"doctrine.d.ts","sourceRoot":"","sources":["../../src/lint/doctrine.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CACzB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,UAAU,EAAE,SAAS,iBAAiB,EAAE,CAAA;IACjD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,qEAAqE;IACrE,QAAQ,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAA;CACzC;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS,MAAM,EAAE,GAAG,cAAc,CAe5F;AAED,4FAA4F;AAC5F,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,iBAAiB,EAAE,CAQrF;AAiGD,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,EAAE,CAUrF;AAED,yEAAyE;AACzE,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAItD"}
@@ -8,17 +8,22 @@ export function validateDoctrine(cwd, sourceFiles) {
8
8
  const abs = join(cwd, file);
9
9
  if (!existsSync(abs))
10
10
  continue;
11
- const content = readFileSync(abs, 'utf-8');
12
- const lines = content.split('\n');
13
11
  scanned++;
14
12
  scannedFiles.push(file);
15
- checkSchemaTableUsage(file, lines, violations);
16
- checkRawPgTableImport(file, lines, violations);
17
- checkUnbrandedPrimaryKeys(file, lines, violations);
18
- checkHandWrittenTraitFields(file, lines, violations);
13
+ violations.push(...doctrineViolations(file, readFileSync(abs, 'utf-8')));
19
14
  }
20
15
  return { violations, scanned, scannedFiles };
21
16
  }
17
+ /** The four doctrine scans over one file's text; shared by `check` and the eslint rules. */
18
+ export function doctrineViolations(file, content) {
19
+ const lines = content.split('\n');
20
+ const violations = [];
21
+ checkSchemaTableUsage(file, lines, violations);
22
+ checkRawPgTableImport(file, lines, violations);
23
+ checkUnbrandedPrimaryKeys(file, lines, violations);
24
+ checkHandWrittenTraitFields(file, lines, violations);
25
+ return violations;
26
+ }
22
27
  const SCHEMA_TABLE_PATTERN = /\bschema\.table\s*\(/;
23
28
  const PIPE_DEFINE_FILE_PATTERN = /\bpipe\.define\s*\(/;
24
29
  function checkSchemaTableUsage(file, lines, violations) {
@@ -1 +1 @@
1
- {"version":3,"file":"doctrine.js","sourceRoot":"","sources":["../../src/lint/doctrine.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"doctrine.js","sourceRoot":"","sources":["../../src/lint/doctrine.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { Rule } from 'eslint';
2
+ export declare const doctrineRules: Record<string, Rule.RuleModule>;
3
+ //# sourceMappingURL=doctrine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctrine.d.ts","sourceRoot":"","sources":["../../../src/lint/rules/doctrine.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA;AA2BlC,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,UAAU,CAEzD,CAAA"}
@@ -0,0 +1,28 @@
1
+ import { basename } from 'node:path';
2
+ import { doctrineViolations, isSourceFileName } from '../doctrine.js';
3
+ const RULES = ['prefer-pipe-define', 'no-raw-pgTable', 'brand-primary-key', 'use-traits'];
4
+ function doctrineRule(name) {
5
+ const id = `define/${name}`;
6
+ return {
7
+ meta: {
8
+ type: 'problem',
9
+ docs: { description: `Doctrine rule ${id}; same scan as the doctrine step of pipework check.` },
10
+ schema: [],
11
+ },
12
+ create(context) {
13
+ return {
14
+ 'Program:exit'() {
15
+ if (!isSourceFileName(basename(context.filename)))
16
+ return;
17
+ for (const v of doctrineViolations(context.filename, context.sourceCode.text)) {
18
+ if (v.rule !== id)
19
+ continue;
20
+ context.report({ loc: { line: v.line, column: 0 }, message: v.message });
21
+ }
22
+ },
23
+ };
24
+ },
25
+ };
26
+ }
27
+ export const doctrineRules = Object.fromEntries(RULES.map(name => [name, doctrineRule(name)]));
28
+ //# sourceMappingURL=doctrine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctrine.js","sourceRoot":"","sources":["../../../src/lint/rules/doctrine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AAEpC,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AAErE,MAAM,KAAK,GAAG,CAAC,oBAAoB,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,YAAY,CAAU,CAAA;AAElG,SAAS,YAAY,CAAC,IAAY;IAChC,MAAM,EAAE,GAAG,UAAU,IAAI,EAAE,CAAA;IAC3B,OAAO;QACL,IAAI,EAAE;YACJ,IAAI,EAAE,SAAS;YACf,IAAI,EAAE,EAAE,WAAW,EAAE,iBAAiB,EAAE,qDAAqD,EAAE;YAC/F,MAAM,EAAE,EAAE;SACX;QACD,MAAM,CAAC,OAAO;YACZ,OAAO;gBACL,cAAc;oBACZ,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;wBAAE,OAAM;oBACzD,KAAK,MAAM,CAAC,IAAI,kBAAkB,CAAC,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;wBAC9E,IAAI,CAAC,CAAC,IAAI,KAAK,EAAE;4BAAE,SAAQ;wBAC3B,OAAO,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAA;oBAC1E,CAAC;gBACH,CAAC;aACF,CAAA;QACH,CAAC;KACF,CAAA;AACH,CAAC;AAED,MAAM,CAAC,MAAM,aAAa,GAAoC,MAAM,CAAC,WAAW,CAC9E,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAC9C,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pipework",
3
- "version": "0.270.0",
3
+ "version": "0.271.0",
4
4
  "description": "TypeScript framework for multi-tenant SaaS applications. PostgreSQL-only.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -1,6 +1,7 @@
1
1
  import tseslint from '@typescript-eslint/eslint-plugin'
2
2
  import tsparser from '@typescript-eslint/parser'
3
3
  import { noReexports } from './rules/no-reexports.js'
4
+ import { doctrineRules } from './rules/doctrine.js'
4
5
 
5
6
  export const rules = {
6
7
  '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
@@ -11,6 +12,10 @@ export const rules = {
11
12
  '@typescript-eslint/no-unnecessary-condition': 'error',
12
13
  '@typescript-eslint/strict-boolean-expressions': 'error',
13
14
  'pipework/no-reexports': 'error',
15
+ 'define/prefer-pipe-define': 'error',
16
+ 'define/no-raw-pgTable': 'error',
17
+ 'define/brand-primary-key': 'error',
18
+ 'define/use-traits': 'error',
14
19
  } as const
15
20
 
16
21
  export interface LintOptions {
@@ -33,6 +38,7 @@ export function createLintConfig(config?: LintOptions): unknown[] {
33
38
  const appliedPlugins: Record<string, unknown> = {
34
39
  '@typescript-eslint': tseslint,
35
40
  'pipework': { rules: { 'no-reexports': noReexports } },
41
+ 'define': { rules: doctrineRules },
36
42
  ...config?.extraPlugins,
37
43
  }
38
44
 
@@ -24,20 +24,25 @@ export function validateDoctrine(cwd: string, sourceFiles: readonly string[]): D
24
24
  const abs = join(cwd, file)
25
25
  if (!existsSync(abs)) continue
26
26
 
27
- const content = readFileSync(abs, 'utf-8')
28
- const lines = content.split('\n')
29
27
  scanned++
30
28
  scannedFiles.push(file)
31
-
32
- checkSchemaTableUsage(file, lines, violations)
33
- checkRawPgTableImport(file, lines, violations)
34
- checkUnbrandedPrimaryKeys(file, lines, violations)
35
- checkHandWrittenTraitFields(file, lines, violations)
29
+ violations.push(...doctrineViolations(file, readFileSync(abs, 'utf-8')))
36
30
  }
37
31
 
38
32
  return { violations, scanned, scannedFiles }
39
33
  }
40
34
 
35
+ /** The four doctrine scans over one file's text; shared by `check` and the eslint rules. */
36
+ export function doctrineViolations(file: string, content: string): DoctrineViolation[] {
37
+ const lines = content.split('\n')
38
+ const violations: DoctrineViolation[] = []
39
+ checkSchemaTableUsage(file, lines, violations)
40
+ checkRawPgTableImport(file, lines, violations)
41
+ checkUnbrandedPrimaryKeys(file, lines, violations)
42
+ checkHandWrittenTraitFields(file, lines, violations)
43
+ return violations
44
+ }
45
+
41
46
  const SCHEMA_TABLE_PATTERN = /\bschema\.table\s*\(/
42
47
  const PIPE_DEFINE_FILE_PATTERN = /\bpipe\.define\s*\(/
43
48
 
@@ -0,0 +1,31 @@
1
+ import { basename } from 'node:path'
2
+ import type { Rule } from 'eslint'
3
+ import { doctrineViolations, isSourceFileName } from '../doctrine.js'
4
+
5
+ const RULES = ['prefer-pipe-define', 'no-raw-pgTable', 'brand-primary-key', 'use-traits'] as const
6
+
7
+ function doctrineRule(name: string): Rule.RuleModule {
8
+ const id = `define/${name}`
9
+ return {
10
+ meta: {
11
+ type: 'problem',
12
+ docs: { description: `Doctrine rule ${id}; same scan as the doctrine step of pipework check.` },
13
+ schema: [],
14
+ },
15
+ create(context) {
16
+ return {
17
+ 'Program:exit'() {
18
+ if (!isSourceFileName(basename(context.filename))) return
19
+ for (const v of doctrineViolations(context.filename, context.sourceCode.text)) {
20
+ if (v.rule !== id) continue
21
+ context.report({ loc: { line: v.line, column: 0 }, message: v.message })
22
+ }
23
+ },
24
+ }
25
+ },
26
+ }
27
+ }
28
+
29
+ export const doctrineRules: Record<string, Rule.RuleModule> = Object.fromEntries(
30
+ RULES.map(name => [name, doctrineRule(name)]),
31
+ )