@clipboard-health/eslint-plugin 2.9.1 → 2.10.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.
Files changed (28) hide show
  1. package/README.md +4 -0
  2. package/package.json +5 -3
  3. package/src/index.d.ts +8 -21
  4. package/src/index.js.map +1 -1
  5. package/src/lib/rules/enforce-ts-rest-in-controllers/index.d.ts +2 -8
  6. package/src/lib/rules/enforce-ts-rest-in-controllers/index.js +2 -123
  7. package/src/lib/rules/enforce-ts-rest-in-controllers/index.js.map +1 -1
  8. package/src/lib/rules/no-cross-contract-imports/index.d.ts +2 -4
  9. package/src/lib/rules/no-cross-contract-imports/index.js +2 -115
  10. package/src/lib/rules/no-cross-contract-imports/index.js.map +1 -1
  11. package/src/lib/rules/require-contract-fixture-construction/index.d.ts +2 -5
  12. package/src/lib/rules/require-contract-fixture-construction/index.js +2 -613
  13. package/src/lib/rules/require-contract-fixture-construction/index.js.map +1 -1
  14. package/src/lib/rules/require-contract-response-parse/index.d.ts +2 -23
  15. package/src/lib/rules/require-contract-response-parse/index.js +2 -374
  16. package/src/lib/rules/require-contract-response-parse/index.js.map +1 -1
  17. package/src/lib/rules/require-http-module-factory/index.d.ts +2 -4
  18. package/src/lib/rules/require-http-module-factory/index.js +2 -71
  19. package/src/lib/rules/require-http-module-factory/index.js.map +1 -1
  20. package/src/lib/rules/require-run-validators-with-upsert/index.d.ts +2 -4
  21. package/src/lib/rules/require-run-validators-with-upsert/index.js +2 -94
  22. package/src/lib/rules/require-run-validators-with-upsert/index.js.map +1 -1
  23. package/src/lib/rules/require-zod-import-in-contracts/index.d.ts +2 -4
  24. package/src/lib/rules/require-zod-import-in-contracts/index.js +2 -46
  25. package/src/lib/rules/require-zod-import-in-contracts/index.js.map +1 -1
  26. package/src/lib/createRule.d.ts +0 -4
  27. package/src/lib/createRule.js +0 -6
  28. package/src/lib/createRule.js.map +0 -1
package/README.md CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  Clipboard's [ESLint](https://eslint.org/) plugin.
4
4
 
5
+ The rule implementations are shared with `@clipboard-health/oxlint-plugin`, so ESLint and Oxlint
6
+ consumers execute the same behavior. This compatibility package remains available for repositories
7
+ that have not migrated to Oxlint yet.
8
+
5
9
  ## Table of contents <!-- omit from toc -->
6
10
 
7
11
  - [Install](#install)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clipboard-health/eslint-plugin",
3
- "version": "2.9.1",
3
+ "version": "2.10.0",
4
4
  "description": "Clipboard's ESLint Plugin",
5
5
  "keywords": [
6
6
  "eslint",
@@ -19,11 +19,13 @@
19
19
  "access": "public"
20
20
  },
21
21
  "dependencies": {
22
- "@typescript-eslint/utils": "8.65.0",
22
+ "@clipboard-health/oxlint-plugin": "1.0.0",
23
+ "@oxlint/plugins": "1.77.0",
23
24
  "tslib": "2.8.1"
24
25
  },
25
26
  "devDependencies": {
26
- "@typescript-eslint/parser": "8.65.0"
27
+ "@typescript-eslint/parser": "8.65.0",
28
+ "@typescript-eslint/utils": "8.65.0"
27
29
  },
28
30
  "types": "./src/index.d.ts"
29
31
  }
package/src/index.d.ts CHANGED
@@ -1,23 +1,10 @@
1
+ import type { Rule } from "@oxlint/plugins";
1
2
  export declare const rules: {
2
- "enforce-ts-rest-in-controllers": import("@typescript-eslint/utils/ts-eslint").RuleModule<"callNotFromPackage" | "decoratorNotFromPackage" | "missingDecorator" | "missingReturn", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
3
- name: string;
4
- };
5
- "no-cross-contract-imports": import("@typescript-eslint/utils/ts-eslint").RuleModule<"noCrossContractImport", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
6
- name: string;
7
- };
8
- "require-contract-fixture-construction": import("@typescript-eslint/utils/ts-eslint").RuleModule<"parseMock" | "parsePayload", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
9
- name: string;
10
- };
11
- "require-contract-response-parse": import("@typescript-eslint/utils/ts-eslint").RuleModule<"inlineAnySchema" | "missingContractParse" | "nonContractSchema", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
12
- name: string;
13
- };
14
- "require-http-module-factory": import("@typescript-eslint/utils/ts-eslint").RuleModule<"noImport" | "requireFactory" | "wrongPackage", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
15
- name: string;
16
- };
17
- "require-run-validators-with-upsert": import("@typescript-eslint/utils/ts-eslint").RuleModule<"missingRunValidators" | "runValidatorsFalse", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
18
- name: string;
19
- };
20
- "require-zod-import-in-contracts": import("@typescript-eslint/utils/ts-eslint").RuleModule<"missingZodReference", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
21
- name: string;
22
- };
3
+ "enforce-ts-rest-in-controllers": Rule;
4
+ "no-cross-contract-imports": Rule;
5
+ "require-contract-fixture-construction": Rule;
6
+ "require-contract-response-parse": Rule;
7
+ "require-http-module-factory": Rule;
8
+ "require-run-validators-with-upsert": Rule;
9
+ "require-zod-import-in-contracts": Rule;
23
10
  };
package/src/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../packages/eslint-plugin/src/index.ts"],"names":[],"mappings":";;;;AAAA,wHAAoF;AACpF,8GAA2E;AAC3E,sIAAmG;AACnG,0HAAuF;AACvF,kHAA+E;AAC/E,gIAA4F;AAC5F,0HAAsF;AAEzE,QAAA,KAAK,GAAG;IACnB,gCAAgC,EAAE,wCAA0B;IAC5D,2BAA2B,EAAE,mCAAsB;IACnD,uCAAuC,EAAE,+CAAkC;IAC3E,iCAAiC,EAAE,yCAA4B;IAC/D,6BAA6B,EAAE,qCAAwB;IACvD,oCAAoC,EAAE,4CAA8B;IACpE,iCAAiC,EAAE,yCAA2B;CAC/D,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../packages/eslint-plugin/src/index.ts"],"names":[],"mappings":";;;;AAEA,wHAAoF;AACpF,8GAA2E;AAC3E,sIAAmG;AACnG,0HAAuF;AACvF,kHAA+E;AAC/E,gIAA4F;AAC5F,0HAAsF;AAEzE,QAAA,KAAK,GAAG;IACnB,gCAAgC,EAAE,wCAA0B;IAC5D,2BAA2B,EAAE,mCAAsB;IACnD,uCAAuC,EAAE,+CAAkC;IAC3E,iCAAiC,EAAE,yCAA4B;IAC/D,6BAA6B,EAAE,qCAAwB;IACvD,oCAAoC,EAAE,4CAA8B;IACpE,iCAAiC,EAAE,yCAA2B;CAChC,CAAC"}
@@ -1,8 +1,2 @@
1
- /**
2
- * @fileoverview Rule to require controller methods to use ts-rest as per our best practices on backend REST APIs
3
- */
4
- import { type TSESLint } from "@typescript-eslint/utils";
5
- declare const rule: TSESLint.RuleModule<"callNotFromPackage" | "decoratorNotFromPackage" | "missingDecorator" | "missingReturn", [], unknown, TSESLint.RuleListener> & {
6
- name: string;
7
- };
8
- export default rule;
1
+ declare const _default: import("@oxlint/plugins").Rule;
2
+ export default _default;
@@ -1,126 +1,5 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- /**
4
- * @fileoverview Rule to require controller methods to use ts-rest as per our best practices on backend REST APIs
5
- */
6
- const utils_1 = require("@typescript-eslint/utils");
7
- const createRule_1 = require("../../createRule");
8
- function validateDecorators(context, node, symbolName, decoratorImportedCorrectly) {
9
- const decorators = node.decorators ?? [];
10
- const hasMatchingDecorator = decorators.some((decorator) => decorator.expression.type === utils_1.AST_NODE_TYPES.CallExpression &&
11
- decorator.expression.callee.type === utils_1.AST_NODE_TYPES.Identifier &&
12
- decorator.expression.callee.name === "TsRestHandler");
13
- if (!hasMatchingDecorator) {
14
- context.report({
15
- node,
16
- messageId: "missingDecorator",
17
- data: { name: symbolName },
18
- });
19
- }
20
- decorators.forEach((decorator) => {
21
- if (decorator.expression.type === utils_1.AST_NODE_TYPES.CallExpression &&
22
- decorator.expression.callee.type === utils_1.AST_NODE_TYPES.Identifier &&
23
- decorator.expression.callee.name === "TsRestHandler" &&
24
- !decoratorImportedCorrectly) {
25
- context.report({
26
- node: decorator,
27
- messageId: "decoratorNotFromPackage",
28
- });
29
- }
30
- });
31
- }
32
- function validateReturnStatement(context, node, symbolName, methodImportedCorrectly) {
33
- const body = node.value?.body;
34
- if (body?.type !== utils_1.AST_NODE_TYPES.BlockStatement ||
35
- body.body.length !== 1 ||
36
- body.body[0]?.type !== utils_1.AST_NODE_TYPES.ReturnStatement) {
37
- context.report({
38
- node,
39
- messageId: "missingReturn",
40
- data: { name: symbolName },
41
- });
42
- return;
43
- }
44
- const returnValueExpr = body.body[0].argument;
45
- if (returnValueExpr?.type !== utils_1.AST_NODE_TYPES.CallExpression ||
46
- returnValueExpr.callee.type !== utils_1.AST_NODE_TYPES.Identifier ||
47
- returnValueExpr.callee.name !== "tsRestHandler") {
48
- context.report({
49
- node,
50
- messageId: "missingReturn",
51
- data: { name: symbolName },
52
- });
53
- }
54
- if (returnValueExpr &&
55
- returnValueExpr?.type === utils_1.AST_NODE_TYPES.CallExpression &&
56
- returnValueExpr.callee.type === utils_1.AST_NODE_TYPES.Identifier &&
57
- returnValueExpr.callee.name === "tsRestHandler" &&
58
- !methodImportedCorrectly) {
59
- context.report({
60
- node: returnValueExpr,
61
- messageId: "callNotFromPackage",
62
- });
63
- }
64
- }
65
- const rule = (0, createRule_1.createRule)({
66
- name: "enforce-ts-rest-in-controllers",
67
- defaultOptions: [],
68
- meta: {
69
- type: "problem",
70
- docs: {
71
- description: "Require use of ts-rest on all controller methods",
72
- },
73
- schema: [],
74
- messages: {
75
- missingDecorator: "Controller method '{{name}}' must be decorated with `@TsRestHandler()` from `@ts-rest/nest` package. See https://www.notion.so/BP-REST-API-f769b7fe745c4cf38f6eca2e9ad8a843 for more information.",
76
- missingReturn: "Controller method '{{name}}' must only return the result of calling `tsRestHandler()` from `@ts-rest/nest` package. See https://www.notion.so/BP-REST-API-f769b7fe745c4cf38f6eca2e9ad8a843 for more information.",
77
- decoratorNotFromPackage: "Decorator `TsRestHandler` must be imported from `@ts-rest/nest`",
78
- callNotFromPackage: "Method `tsRestHandler` must be imported from `@ts-rest/nest`",
79
- },
80
- },
81
- create(context) {
82
- let methodImportedCorrectly = false;
83
- let decoratorImportedCorrectly = false;
84
- return {
85
- /*
86
- * This method iterates through import declarations and verifies that the the `TsRestHandler`
87
- * decorator and `tsRestHandler` method are imported from `@ts-rest/nest` package. We'll use
88
- * this information to later highlight usages of those symbols to point out that they need to
89
- * be imported from the correct source.
90
- */
91
- ImportDeclaration(node) {
92
- if (node.source.value === "@ts-rest/nest") {
93
- for (const spec of node.specifiers) {
94
- if (spec.type === utils_1.AST_NODE_TYPES.ImportSpecifier) {
95
- if (spec.imported.type === utils_1.AST_NODE_TYPES.Identifier &&
96
- spec.imported.name === "tsRestHandler") {
97
- methodImportedCorrectly = true;
98
- }
99
- if (spec.imported.type === utils_1.AST_NODE_TYPES.Identifier &&
100
- spec.imported.name === "TsRestHandler") {
101
- decoratorImportedCorrectly = true;
102
- }
103
- }
104
- }
105
- }
106
- },
107
- /*
108
- * This method verifies that non-constructor and non-private methods use the
109
- * `TsRestHandler` decorator and return the result of `tsRestHandler` as the
110
- * only expression in it.
111
- */
112
- MethodDefinition(node) {
113
- const symbolName = (node.key.type === utils_1.AST_NODE_TYPES.Identifier && node.key.name) || "<unknown>";
114
- if (node.kind === "constructor" ||
115
- node.accessibility === "private" ||
116
- (node.key.type === utils_1.AST_NODE_TYPES.Identifier && node.key.name === "constructor")) {
117
- return;
118
- }
119
- validateDecorators(context, node, symbolName, decoratorImportedCorrectly);
120
- validateReturnStatement(context, node, symbolName, methodImportedCorrectly);
121
- },
122
- };
123
- },
124
- });
125
- exports.default = rule;
3
+ const oxlint_plugin_1 = require("@clipboard-health/oxlint-plugin");
4
+ exports.default = oxlint_plugin_1.rules["enforce-ts-rest-in-controllers"];
126
5
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../../packages/eslint-plugin/src/lib/rules/enforce-ts-rest-in-controllers/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../../packages/eslint-plugin/src/lib/rules/enforce-ts-rest-in-controllers/index.ts"],"names":[],"mappings":";;AAAA,mEAAwD;kBAEzC,qBAAK,CAAC,gCAAgC,CAAC"}
@@ -1,4 +1,2 @@
1
- declare const rule: import("@typescript-eslint/utils/ts-eslint").RuleModule<"noCrossContractImport", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
2
- name: string;
3
- };
4
- export default rule;
1
+ declare const _default: import("@oxlint/plugins").Rule;
2
+ export default _default;
@@ -1,118 +1,5 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- const tslib_1 = require("tslib");
4
- /**
5
- * @fileoverview Forbid contract packages from importing other contract packages.
6
- * Cross-contract dependencies pin one contract into another's dependencies,
7
- * vendoring duplicate copies into every consumer and risking dependency cycles.
8
- */
9
- const node_fs_1 = require("node:fs");
10
- const node_path_1 = tslib_1.__importDefault(require("node:path"));
11
- const utils_1 = require("@typescript-eslint/utils");
12
- const createRule_1 = require("../../createRule");
13
- const CONTRACT_PACKAGE_PATTERN = /^@clipboard-health\/(?:contract-|api-contract-|flag-)/;
14
- const SHARED_CONTRACT_PACKAGE = "@clipboard-health/contract-core";
15
- const packageNameCache = new Map();
16
- /**
17
- * Walks up from `directory` to the nearest package.json that declares a `name`.
18
- * Skips nameless manifests (e.g. `{"type":"module"}` build-output markers).
19
- */
20
- function nearestPackageName(directory) {
21
- if (packageNameCache.has(directory)) {
22
- return packageNameCache.get(directory);
23
- }
24
- let name;
25
- const manifestPath = node_path_1.default.join(directory, "package.json");
26
- try {
27
- // eslint-disable-next-line security/detect-non-literal-fs-filename -- resolves the linted file's own package.json
28
- const manifest = JSON.parse((0, node_fs_1.readFileSync)(manifestPath, "utf8"));
29
- if (typeof manifest === "object" &&
30
- manifest !== null &&
31
- "name" in manifest &&
32
- typeof manifest.name === "string") {
33
- name = manifest.name;
34
- }
35
- }
36
- catch {
37
- // No package.json in this directory; keep walking up.
38
- }
39
- if (name === undefined) {
40
- const parent = node_path_1.default.dirname(directory);
41
- name = parent === directory ? undefined : nearestPackageName(parent);
42
- }
43
- packageNameCache.set(directory, name);
44
- return name;
45
- }
46
- function isBannedSpecifier(specifier) {
47
- return (CONTRACT_PACKAGE_PATTERN.test(specifier) &&
48
- specifier !== SHARED_CONTRACT_PACKAGE &&
49
- !specifier.startsWith(`${SHARED_CONTRACT_PACKAGE}/`));
50
- }
51
- const rule = (0, createRule_1.createRule)({
52
- name: "no-cross-contract-imports",
53
- defaultOptions: [],
54
- meta: {
55
- type: "problem",
56
- docs: {
57
- description: "Forbid contract packages from importing other contract packages; contracts own the shape of their inputs and outputs",
58
- },
59
- schema: [],
60
- messages: {
61
- noCrossContractImport: "Contract packages must not depend on '{{specifier}}'. Cross-contract imports (including type-only imports and re-exports) pin another contract into this package's dependencies, vendoring duplicate copies into every consumer and risking dependency cycles. Import shared primitives from @clipboard-health/contract-core, or duplicate the schema locally — type-checking and response validation catch drift.",
62
- },
63
- },
64
- create(context) {
65
- // context.filename requires ESLint >=8.40; fall back for older 8.x hosts.
66
- const filename = context.filename ?? context.getFilename();
67
- const packageName = nearestPackageName(node_path_1.default.dirname(filename));
68
- if (packageName === undefined || !CONTRACT_PACKAGE_PATTERN.test(packageName)) {
69
- return {};
70
- }
71
- function checkSpecifier(node, specifier) {
72
- const isSelfImport = specifier === packageName || specifier.startsWith(`${packageName}/`);
73
- if (!isSelfImport && isBannedSpecifier(specifier)) {
74
- context.report({
75
- node,
76
- messageId: "noCrossContractImport",
77
- data: { specifier },
78
- });
79
- }
80
- }
81
- return {
82
- ImportDeclaration(node) {
83
- checkSpecifier(node, node.source.value);
84
- },
85
- ExportNamedDeclaration(node) {
86
- if (node.source) {
87
- checkSpecifier(node, node.source.value);
88
- }
89
- },
90
- ExportAllDeclaration(node) {
91
- checkSpecifier(node, node.source.value);
92
- },
93
- ImportExpression(node) {
94
- if (node.source.type === utils_1.AST_NODE_TYPES.Literal && typeof node.source.value === "string") {
95
- checkSpecifier(node, node.source.value);
96
- }
97
- },
98
- CallExpression(node) {
99
- const [argument] = node.arguments;
100
- if (node.callee.type === utils_1.AST_NODE_TYPES.Identifier &&
101
- node.callee.name === "require" &&
102
- argument?.type === utils_1.AST_NODE_TYPES.Literal &&
103
- typeof argument.value === "string") {
104
- checkSpecifier(node, argument.value);
105
- }
106
- },
107
- TSImportEqualsDeclaration(node) {
108
- if (node.moduleReference.type === utils_1.AST_NODE_TYPES.TSExternalModuleReference &&
109
- node.moduleReference.expression.type === utils_1.AST_NODE_TYPES.Literal &&
110
- typeof node.moduleReference.expression.value === "string") {
111
- checkSpecifier(node, node.moduleReference.expression.value);
112
- }
113
- },
114
- };
115
- },
116
- });
117
- exports.default = rule;
3
+ const oxlint_plugin_1 = require("@clipboard-health/oxlint-plugin");
4
+ exports.default = oxlint_plugin_1.rules["no-cross-contract-imports"];
118
5
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../../packages/eslint-plugin/src/lib/rules/no-cross-contract-imports/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../../packages/eslint-plugin/src/lib/rules/no-cross-contract-imports/index.ts"],"names":[],"mappings":";;AAAA,mEAAwD;kBAEzC,qBAAK,CAAC,2BAA2B,CAAC"}
@@ -1,5 +1,2 @@
1
- import { type TSESLint } from "@typescript-eslint/utils";
2
- declare const rule: TSESLint.RuleModule<"parseMock" | "parsePayload", [], unknown, TSESLint.RuleListener> & {
3
- name: string;
4
- };
5
- export default rule;
1
+ declare const _default: import("@oxlint/plugins").Rule;
2
+ export default _default;