@clipboard-health/eslint-plugin 2.5.31 → 2.5.32
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/package.json +1 -1
- package/src/index.d.ts +3 -0
- package/src/index.js +2 -0
- package/src/index.js.map +1 -1
- package/src/lib/rules/no-cross-contract-imports/index.d.ts +4 -0
- package/src/lib/rules/no-cross-contract-imports/index.js +118 -0
- package/src/lib/rules/no-cross-contract-imports/index.js.map +1 -0
package/package.json
CHANGED
package/src/index.d.ts
CHANGED
|
@@ -2,6 +2,9 @@ export declare const rules: {
|
|
|
2
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
3
|
name: string;
|
|
4
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
|
+
};
|
|
5
8
|
"require-http-module-factory": import("@typescript-eslint/utils/ts-eslint").RuleModule<"noImport" | "requireFactory" | "wrongPackage", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
|
|
6
9
|
name: string;
|
|
7
10
|
};
|
package/src/index.js
CHANGED
|
@@ -3,11 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.rules = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const enforce_ts_rest_in_controllers_1 = tslib_1.__importDefault(require("./lib/rules/enforce-ts-rest-in-controllers"));
|
|
6
|
+
const no_cross_contract_imports_1 = tslib_1.__importDefault(require("./lib/rules/no-cross-contract-imports"));
|
|
6
7
|
const require_http_module_factory_1 = tslib_1.__importDefault(require("./lib/rules/require-http-module-factory"));
|
|
7
8
|
const require_run_validators_with_upsert_1 = tslib_1.__importDefault(require("./lib/rules/require-run-validators-with-upsert"));
|
|
8
9
|
const require_zod_import_in_contracts_1 = tslib_1.__importDefault(require("./lib/rules/require-zod-import-in-contracts"));
|
|
9
10
|
exports.rules = {
|
|
10
11
|
"enforce-ts-rest-in-controllers": enforce_ts_rest_in_controllers_1.default,
|
|
12
|
+
"no-cross-contract-imports": no_cross_contract_imports_1.default,
|
|
11
13
|
"require-http-module-factory": require_http_module_factory_1.default,
|
|
12
14
|
"require-run-validators-with-upsert": require_run_validators_with_upsert_1.default,
|
|
13
15
|
"require-zod-import-in-contracts": require_zod_import_in_contracts_1.default,
|
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,kHAA+E;AAC/E,gIAA4F;AAC5F,0HAAsF;AAEzE,QAAA,KAAK,GAAG;IACnB,gCAAgC,EAAE,wCAA0B;IAC5D,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":";;;;AAAA,wHAAoF;AACpF,8GAA2E;AAC3E,kHAA+E;AAC/E,gIAA4F;AAC5F,0HAAsF;AAEzE,QAAA,KAAK,GAAG;IACnB,gCAAgC,EAAE,wCAA0B;IAC5D,2BAA2B,EAAE,mCAAsB;IACnD,6BAA6B,EAAE,qCAAwB;IACvD,oCAAoC,EAAE,4CAA8B;IACpE,iCAAiC,EAAE,yCAA2B;CAC/D,CAAC"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"use strict";
|
|
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;
|
|
118
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +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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"}
|