eslint-plugin-code-policy 0.2.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/LICENSE +21 -0
- package/README.md +376 -0
- package/dist/chunk-URER6VHN.js +525 -0
- package/dist/chunk-URER6VHN.js.map +1 -0
- package/dist/chunk-YKNN7DF3.cjs +531 -0
- package/dist/chunk-YKNN7DF3.cjs.map +1 -0
- package/dist/configs/next.cjs +9 -0
- package/dist/configs/next.cjs.map +1 -0
- package/dist/configs/next.d.ts +14 -0
- package/dist/configs/next.d.ts.map +1 -0
- package/dist/configs/next.js +6 -0
- package/dist/configs/next.js.map +1 -0
- package/dist/configs/react.cjs +9 -0
- package/dist/configs/react.cjs.map +1 -0
- package/dist/configs/react.d.ts +14 -0
- package/dist/configs/react.d.ts.map +1 -0
- package/dist/configs/react.js +6 -0
- package/dist/configs/react.js.map +1 -0
- package/dist/configs/recommended.cjs +9 -0
- package/dist/configs/recommended.cjs.map +1 -0
- package/dist/configs/recommended.d.ts +14 -0
- package/dist/configs/recommended.d.ts.map +1 -0
- package/dist/configs/recommended.js +6 -0
- package/dist/configs/recommended.js.map +1 -0
- package/dist/configs/strict.cjs +9 -0
- package/dist/configs/strict.cjs.map +1 -0
- package/dist/configs/strict.d.ts +14 -0
- package/dist/configs/strict.d.ts.map +1 -0
- package/dist/configs/strict.js +6 -0
- package/dist/configs/strict.js.map +1 -0
- package/dist/index.cjs +18 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +66 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/rules/atomic-file.d.ts +4 -0
- package/dist/rules/atomic-file.d.ts.map +1 -0
- package/dist/rules/no-cross-module-deep-imports.d.ts +31 -0
- package/dist/rules/no-cross-module-deep-imports.d.ts.map +1 -0
- package/dist/rules/no-inline-types.d.ts +4 -0
- package/dist/rules/no-inline-types.d.ts.map +1 -0
- package/dist/rules/public-api-imports.d.ts +4 -0
- package/dist/rules/public-api-imports.d.ts.map +1 -0
- package/dist/rules/view-logic-separation.d.ts +4 -0
- package/dist/rules/view-logic-separation.d.ts.map +1 -0
- package/package.json +92 -0
|
@@ -0,0 +1,531 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __esm = (fn, res) => function __init() {
|
|
8
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
9
|
+
};
|
|
10
|
+
var __export = (target, all) => {
|
|
11
|
+
for (var name in all)
|
|
12
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
13
|
+
};
|
|
14
|
+
var __copyProps = (to, from, except, desc) => {
|
|
15
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
16
|
+
for (let key of __getOwnPropNames(from))
|
|
17
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
18
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
19
|
+
}
|
|
20
|
+
return to;
|
|
21
|
+
};
|
|
22
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
23
|
+
|
|
24
|
+
// src/configs/strict.ts
|
|
25
|
+
exports.strict_default = void 0;
|
|
26
|
+
var init_strict = __esm({
|
|
27
|
+
"src/configs/strict.ts"() {
|
|
28
|
+
init_recommended();
|
|
29
|
+
exports.strict_default = {
|
|
30
|
+
...exports.recommended_default,
|
|
31
|
+
rules: {
|
|
32
|
+
...exports.recommended_default.rules
|
|
33
|
+
// Strict overrides added here
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// src/configs/react.ts
|
|
40
|
+
exports.react_default = void 0;
|
|
41
|
+
var init_react = __esm({
|
|
42
|
+
"src/configs/react.ts"() {
|
|
43
|
+
init_recommended();
|
|
44
|
+
exports.react_default = {
|
|
45
|
+
...exports.recommended_default,
|
|
46
|
+
rules: {
|
|
47
|
+
...exports.recommended_default.rules
|
|
48
|
+
// React specific adjustments
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// src/configs/next.ts
|
|
55
|
+
exports.next_default = void 0;
|
|
56
|
+
var init_next = __esm({
|
|
57
|
+
"src/configs/next.ts"() {
|
|
58
|
+
init_recommended();
|
|
59
|
+
exports.next_default = {
|
|
60
|
+
...exports.recommended_default,
|
|
61
|
+
rules: {
|
|
62
|
+
...exports.recommended_default.rules
|
|
63
|
+
// Next specific adjustments
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// src/rules/atomic-file.ts
|
|
70
|
+
var NEXT_RESERVED_EXPORTS, atomic_file_default;
|
|
71
|
+
var init_atomic_file = __esm({
|
|
72
|
+
"src/rules/atomic-file.ts"() {
|
|
73
|
+
NEXT_RESERVED_EXPORTS = /* @__PURE__ */ new Set([
|
|
74
|
+
"config",
|
|
75
|
+
"metadata",
|
|
76
|
+
"dynamic",
|
|
77
|
+
"revalidate",
|
|
78
|
+
"fetchCache",
|
|
79
|
+
"runtime",
|
|
80
|
+
"preferredRegion",
|
|
81
|
+
"viewport",
|
|
82
|
+
"generateMetadata",
|
|
83
|
+
"generateViewport",
|
|
84
|
+
"generateStaticParams",
|
|
85
|
+
"GET",
|
|
86
|
+
"POST",
|
|
87
|
+
"PUT",
|
|
88
|
+
"PATCH",
|
|
89
|
+
"DELETE",
|
|
90
|
+
"HEAD",
|
|
91
|
+
"OPTIONS"
|
|
92
|
+
]);
|
|
93
|
+
atomic_file_default = {
|
|
94
|
+
meta: {
|
|
95
|
+
type: "problem",
|
|
96
|
+
docs: {
|
|
97
|
+
description: "Enforce atomic file structure (exactly one top-level unit per file)",
|
|
98
|
+
recommended: true
|
|
99
|
+
},
|
|
100
|
+
fixable: void 0,
|
|
101
|
+
schema: [],
|
|
102
|
+
messages: {
|
|
103
|
+
multipleDeclarations: "File contains multiple top-level declarations (found {{count}}). Extract them into separate files to enforce atomic file structure."
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
create(context) {
|
|
107
|
+
const filename = context.filename || context.physicalFilename || "";
|
|
108
|
+
if (filename.endsWith(".config.ts") || filename.endsWith(".config.js") || filename.endsWith(".config.mjs") || filename.endsWith(".config.cjs") || filename.endsWith(".d.ts") || filename.endsWith("index.ts") || filename.endsWith("index.tsx") || filename.endsWith("index.js")) {
|
|
109
|
+
return {};
|
|
110
|
+
}
|
|
111
|
+
const isNextJsRouterFile = /(?:page|layout|loading|error|not-found)\.tsx$|route\.ts$|middleware\.ts$|proxy\.ts$/.test(
|
|
112
|
+
filename
|
|
113
|
+
);
|
|
114
|
+
return {
|
|
115
|
+
Program(node) {
|
|
116
|
+
let count = 0;
|
|
117
|
+
const declarations = [];
|
|
118
|
+
for (const statement of node.body) {
|
|
119
|
+
if (statement.type === "ImportDeclaration" || statement.type === "ExportAllDeclaration" || statement.type === "EmptyStatement" || // @ts-expect-error Typescript specific nodes not in standard estree
|
|
120
|
+
statement.type === "TSImportEqualsDeclaration") {
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
if (statement.type === "ExportNamedDeclaration" && !statement.declaration) {
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
if (isNextJsRouterFile && statement.type === "ExportNamedDeclaration" && statement.declaration) {
|
|
127
|
+
if (statement.declaration.type === "FunctionDeclaration" && statement.declaration.id && NEXT_RESERVED_EXPORTS.has(statement.declaration.id.name)) {
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
if (statement.declaration.type === "VariableDeclaration") {
|
|
131
|
+
const allReserved = statement.declaration.declarations.every(
|
|
132
|
+
(d) => d.id.type === "Identifier" && NEXT_RESERVED_EXPORTS.has(d.id.name)
|
|
133
|
+
);
|
|
134
|
+
if (allReserved) {
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
if (statement.type === "ExpressionStatement") {
|
|
140
|
+
if (
|
|
141
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
142
|
+
statement.directive || statement.expression.type === "Literal" && typeof statement.expression.value === "string"
|
|
143
|
+
) {
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
if (statement.type === "ExportDefaultDeclaration") {
|
|
148
|
+
if (statement.declaration.type === "Identifier") {
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
if (statement.declaration.type === "CallExpression" && statement.declaration.arguments.length === 1 && statement.declaration.arguments[0].type === "Identifier") {
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
const added = statement.type === "VariableDeclaration" ? statement.declarations.length : statement.type === "ExportNamedDeclaration" && statement.declaration && statement.declaration.type === "VariableDeclaration" ? statement.declaration.declarations.length : 1;
|
|
156
|
+
count += added;
|
|
157
|
+
if (added > 0) {
|
|
158
|
+
declarations.push({ statement, added });
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
if (count > 1) {
|
|
162
|
+
let reported = 0;
|
|
163
|
+
for (const { statement, added } of declarations) {
|
|
164
|
+
if (reported > 0 || added > 1) {
|
|
165
|
+
context.report({
|
|
166
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
167
|
+
node: statement,
|
|
168
|
+
messageId: "multipleDeclarations",
|
|
169
|
+
data: { count }
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
reported += added;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
// src/rules/no-inline-types.ts
|
|
183
|
+
var ALLOWED_NEXT_EXPORTS, ROUTE_METHODS, no_inline_types_default;
|
|
184
|
+
var init_no_inline_types = __esm({
|
|
185
|
+
"src/rules/no-inline-types.ts"() {
|
|
186
|
+
ALLOWED_NEXT_EXPORTS = /* @__PURE__ */ new Set([
|
|
187
|
+
"config",
|
|
188
|
+
"metadata",
|
|
189
|
+
"dynamic",
|
|
190
|
+
"revalidate",
|
|
191
|
+
"fetchCache",
|
|
192
|
+
"runtime",
|
|
193
|
+
"preferredRegion",
|
|
194
|
+
"viewport",
|
|
195
|
+
"generateMetadata",
|
|
196
|
+
"generateViewport",
|
|
197
|
+
"generateStaticParams"
|
|
198
|
+
]);
|
|
199
|
+
ROUTE_METHODS = /* @__PURE__ */ new Set(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"]);
|
|
200
|
+
no_inline_types_default = {
|
|
201
|
+
meta: {
|
|
202
|
+
type: "problem",
|
|
203
|
+
docs: {
|
|
204
|
+
description: "Enforces the Atomic File Rule: exactly one top-level declaration (function, type, class, constant) per file.",
|
|
205
|
+
recommended: true
|
|
206
|
+
},
|
|
207
|
+
fixable: void 0,
|
|
208
|
+
schema: [],
|
|
209
|
+
messages: {
|
|
210
|
+
singleDeclaration: 'Atomic File Rule violation: file contains multiple declarations. Extract "{{name}}" into its own file.'
|
|
211
|
+
}
|
|
212
|
+
},
|
|
213
|
+
create(context) {
|
|
214
|
+
if (context.filename.endsWith(".d.ts")) return {};
|
|
215
|
+
return {
|
|
216
|
+
Program(node) {
|
|
217
|
+
const units = [];
|
|
218
|
+
for (const stmt of node.body) {
|
|
219
|
+
let decl = stmt;
|
|
220
|
+
let isExport = false;
|
|
221
|
+
if (stmt.type === "ExportNamedDeclaration" && stmt.declaration) {
|
|
222
|
+
decl = stmt.declaration;
|
|
223
|
+
isExport = true;
|
|
224
|
+
} else if (stmt.type === "ExportDefaultDeclaration" && stmt.declaration) {
|
|
225
|
+
decl = stmt.declaration;
|
|
226
|
+
isExport = true;
|
|
227
|
+
}
|
|
228
|
+
const isRouteFile = context.filename.endsWith("/route.ts") || context.filename.endsWith("/route.js");
|
|
229
|
+
const declType = decl.type;
|
|
230
|
+
if (declType === "FunctionDeclaration" || declType === "ClassDeclaration" || declType === "TSTypeAliasDeclaration" || declType === "TSInterfaceDeclaration" || declType === "TSEnumDeclaration") {
|
|
231
|
+
const name = decl.id?.name ?? "default";
|
|
232
|
+
if (isRouteFile && isExport && declType === "FunctionDeclaration" && ROUTE_METHODS.has(name)) {
|
|
233
|
+
continue;
|
|
234
|
+
}
|
|
235
|
+
units.push({ node: decl, name });
|
|
236
|
+
} else if (declType === "VariableDeclaration") {
|
|
237
|
+
for (const d of decl.declarations) {
|
|
238
|
+
const name = d.id?.name;
|
|
239
|
+
if (isExport && ALLOWED_NEXT_EXPORTS.has(name)) {
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
if (isRouteFile && isExport && ROUTE_METHODS.has(name)) {
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
245
|
+
units.push({ node: decl, name: name ?? "unknown" });
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
if (units.length > 1) {
|
|
250
|
+
for (let i = 1; i < units.length; i++) {
|
|
251
|
+
context.report({
|
|
252
|
+
node: units[i].node,
|
|
253
|
+
messageId: "singleDeclaration",
|
|
254
|
+
data: { name: units[i].name }
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
// src/rules/view-logic-separation.ts
|
|
266
|
+
function isComponentNode(node) {
|
|
267
|
+
if (!node.parent) return false;
|
|
268
|
+
const isTopLevel = node.parent.type === "Program" || node.parent.type === "ExportNamedDeclaration" || node.parent.type === "ExportDefaultDeclaration" || node.parent.type === "VariableDeclarator" && (node.parent.parent?.parent?.type === "Program" || node.parent.parent?.parent?.type === "ExportNamedDeclaration");
|
|
269
|
+
return isTopLevel;
|
|
270
|
+
}
|
|
271
|
+
function getEnclosingComponent(node) {
|
|
272
|
+
let curr = node.parent;
|
|
273
|
+
while (curr) {
|
|
274
|
+
if ((curr.type === "FunctionDeclaration" || curr.type === "ArrowFunctionExpression" || curr.type === "FunctionExpression") && isComponentNode(curr)) {
|
|
275
|
+
return curr;
|
|
276
|
+
}
|
|
277
|
+
curr = curr.parent;
|
|
278
|
+
}
|
|
279
|
+
return null;
|
|
280
|
+
}
|
|
281
|
+
var view_logic_separation_default;
|
|
282
|
+
var init_view_logic_separation = __esm({
|
|
283
|
+
"src/rules/view-logic-separation.ts"() {
|
|
284
|
+
view_logic_separation_default = {
|
|
285
|
+
meta: {
|
|
286
|
+
type: "problem",
|
|
287
|
+
docs: {
|
|
288
|
+
description: "Enforces strict separation of logic from views. React views (.tsx) must not contain state, lifecycle effects, or inline handler declarations. Move logic to a custom hook.",
|
|
289
|
+
recommended: true
|
|
290
|
+
},
|
|
291
|
+
fixable: void 0,
|
|
292
|
+
schema: [],
|
|
293
|
+
messages: {
|
|
294
|
+
noReactHooks: 'Strict View Separation: The hook "{{name}}" is forbidden in a view component. Extract your state/effects to a separate use{{componentName}} hook.',
|
|
295
|
+
noInlineHandlers: "Strict View Separation: Inline function or handler declaration ({{name}}) inside a view component is forbidden. Return it from your custom hook instead."
|
|
296
|
+
}
|
|
297
|
+
},
|
|
298
|
+
create(context) {
|
|
299
|
+
const filename = context.filename || context.physicalFilename || "";
|
|
300
|
+
if (!filename.endsWith(".tsx")) {
|
|
301
|
+
return {};
|
|
302
|
+
}
|
|
303
|
+
return {
|
|
304
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
305
|
+
"FunctionDeclaration, ArrowFunctionExpression, FunctionExpression"(node) {
|
|
306
|
+
if (!isComponentNode(node)) {
|
|
307
|
+
const component = getEnclosingComponent(node);
|
|
308
|
+
if (component) {
|
|
309
|
+
if (node.parent && (node.parent.type === "VariableDeclarator" || node.type === "FunctionDeclaration")) {
|
|
310
|
+
let name = "anonymous function";
|
|
311
|
+
if (node.id && node.id.name) name = node.id.name;
|
|
312
|
+
else if (node.parent.type === "VariableDeclarator" && node.parent.id && node.parent.id.name)
|
|
313
|
+
name = node.parent.id.name;
|
|
314
|
+
context.report({
|
|
315
|
+
node,
|
|
316
|
+
messageId: "noInlineHandlers",
|
|
317
|
+
data: { name }
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
},
|
|
323
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
324
|
+
CallExpression(node) {
|
|
325
|
+
if (node.callee && node.callee.type === "Identifier") {
|
|
326
|
+
const name = node.callee.name;
|
|
327
|
+
if (/^use(State|Effect|Reducer|Callback|Memo|Ref|ImperativeHandle|LayoutEffect|DebugValue|DeferredValue|Transition|Id|SyncExternalStore|InsertionEffect|Query|Mutation)$/.test(
|
|
328
|
+
name
|
|
329
|
+
)) {
|
|
330
|
+
const component = getEnclosingComponent(node);
|
|
331
|
+
if (component) {
|
|
332
|
+
const componentNameBase = filename.split("/").pop()?.replace(".tsx", "") || "Component";
|
|
333
|
+
context.report({
|
|
334
|
+
node,
|
|
335
|
+
messageId: "noReactHooks",
|
|
336
|
+
data: { name, componentName: componentNameBase }
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
// src/rules/public-api-imports.ts
|
|
349
|
+
var public_api_imports_default;
|
|
350
|
+
var init_public_api_imports = __esm({
|
|
351
|
+
"src/rules/public-api-imports.ts"() {
|
|
352
|
+
public_api_imports_default = {
|
|
353
|
+
meta: {
|
|
354
|
+
type: "problem",
|
|
355
|
+
docs: {
|
|
356
|
+
description: "Enforce that cross-module imports only target the module public API (index), not deep internal files.",
|
|
357
|
+
recommended: true
|
|
358
|
+
},
|
|
359
|
+
fixable: void 0,
|
|
360
|
+
schema: [
|
|
361
|
+
{
|
|
362
|
+
type: "object",
|
|
363
|
+
properties: {
|
|
364
|
+
bannedSubpaths: {
|
|
365
|
+
type: "array",
|
|
366
|
+
items: { type: "string" }
|
|
367
|
+
}
|
|
368
|
+
},
|
|
369
|
+
additionalProperties: false
|
|
370
|
+
}
|
|
371
|
+
],
|
|
372
|
+
messages: {
|
|
373
|
+
deepImportNotAllowed: 'Deep import "{{importPath}}" is not allowed. Import from the public API (root) of the module instead.'
|
|
374
|
+
}
|
|
375
|
+
},
|
|
376
|
+
create(context) {
|
|
377
|
+
const options = context.options[0] || {};
|
|
378
|
+
const bannedSubpaths = options.bannedSubpaths || ["/src/"];
|
|
379
|
+
return {
|
|
380
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
381
|
+
ImportDeclaration(node) {
|
|
382
|
+
const importPath = node.source.value;
|
|
383
|
+
if (typeof importPath !== "string") return;
|
|
384
|
+
if (importPath.startsWith(".")) return;
|
|
385
|
+
for (const subpath of bannedSubpaths) {
|
|
386
|
+
if (importPath.includes(subpath)) {
|
|
387
|
+
context.report({
|
|
388
|
+
node,
|
|
389
|
+
messageId: "deepImportNotAllowed",
|
|
390
|
+
data: { importPath }
|
|
391
|
+
});
|
|
392
|
+
break;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
// src/rules/no-cross-module-deep-imports.ts
|
|
403
|
+
var no_cross_module_deep_imports_default;
|
|
404
|
+
var init_no_cross_module_deep_imports = __esm({
|
|
405
|
+
"src/rules/no-cross-module-deep-imports.ts"() {
|
|
406
|
+
no_cross_module_deep_imports_default = {
|
|
407
|
+
meta: {
|
|
408
|
+
type: "problem",
|
|
409
|
+
docs: {
|
|
410
|
+
description: "Forbid relative imports that bypass the public API of another module within the monorepo by importing directly from its internal directories.",
|
|
411
|
+
recommended: true
|
|
412
|
+
},
|
|
413
|
+
fixable: void 0,
|
|
414
|
+
schema: [
|
|
415
|
+
{
|
|
416
|
+
type: "object",
|
|
417
|
+
properties: {
|
|
418
|
+
minParentTraversals: { type: "number" },
|
|
419
|
+
internalDirs: {
|
|
420
|
+
type: "array",
|
|
421
|
+
items: { type: "string" }
|
|
422
|
+
}
|
|
423
|
+
},
|
|
424
|
+
additionalProperties: false
|
|
425
|
+
}
|
|
426
|
+
],
|
|
427
|
+
messages: {
|
|
428
|
+
deepImport: `Cross-module deep import "{{importPath}}" bypasses the module's public API. Import from the module root (index) instead.`
|
|
429
|
+
}
|
|
430
|
+
},
|
|
431
|
+
create(context) {
|
|
432
|
+
const options = context.options[0] || {};
|
|
433
|
+
const minParentTraversals = options.minParentTraversals ?? 2;
|
|
434
|
+
const internalDirs = options.internalDirs ?? ["src"];
|
|
435
|
+
return {
|
|
436
|
+
ImportDeclaration(node) {
|
|
437
|
+
const importPath = node.source.value;
|
|
438
|
+
if (typeof importPath !== "string") return;
|
|
439
|
+
if (!importPath.startsWith(".")) return;
|
|
440
|
+
const parts = importPath.split("/");
|
|
441
|
+
let parentCount = 0;
|
|
442
|
+
for (const part of parts) {
|
|
443
|
+
if (part === "..") parentCount++;
|
|
444
|
+
else break;
|
|
445
|
+
}
|
|
446
|
+
if (parentCount < minParentTraversals) return;
|
|
447
|
+
const descendantParts = parts.slice(parentCount);
|
|
448
|
+
const hasInternalSegment = descendantParts.some((p) => internalDirs.includes(p));
|
|
449
|
+
if (hasInternalSegment) {
|
|
450
|
+
context.report({
|
|
451
|
+
node,
|
|
452
|
+
messageId: "deepImport",
|
|
453
|
+
data: { importPath }
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
// src/index.ts
|
|
464
|
+
var index_exports = {};
|
|
465
|
+
__export(index_exports, {
|
|
466
|
+
default: () => exports.index_default,
|
|
467
|
+
plugin: () => exports.plugin
|
|
468
|
+
});
|
|
469
|
+
exports.plugin = void 0; exports.index_default = void 0;
|
|
470
|
+
var init_index = __esm({
|
|
471
|
+
"src/index.ts"() {
|
|
472
|
+
init_recommended();
|
|
473
|
+
init_strict();
|
|
474
|
+
init_react();
|
|
475
|
+
init_next();
|
|
476
|
+
init_atomic_file();
|
|
477
|
+
init_no_inline_types();
|
|
478
|
+
init_view_logic_separation();
|
|
479
|
+
init_public_api_imports();
|
|
480
|
+
init_no_cross_module_deep_imports();
|
|
481
|
+
exports.plugin = {
|
|
482
|
+
meta: {
|
|
483
|
+
name: "eslint-plugin-code-policy",
|
|
484
|
+
version: "0.1.0"
|
|
485
|
+
},
|
|
486
|
+
rules: {
|
|
487
|
+
"atomic-file": atomic_file_default,
|
|
488
|
+
"no-inline-types": no_inline_types_default,
|
|
489
|
+
"view-logic-separation": view_logic_separation_default,
|
|
490
|
+
"public-api-imports": public_api_imports_default,
|
|
491
|
+
"no-cross-module-deep-imports": no_cross_module_deep_imports_default
|
|
492
|
+
},
|
|
493
|
+
configs: {
|
|
494
|
+
recommended: exports.recommended_default,
|
|
495
|
+
strict: exports.strict_default,
|
|
496
|
+
react: exports.react_default,
|
|
497
|
+
next: exports.next_default
|
|
498
|
+
}
|
|
499
|
+
};
|
|
500
|
+
exports.index_default = exports.plugin;
|
|
501
|
+
}
|
|
502
|
+
});
|
|
503
|
+
|
|
504
|
+
// src/configs/recommended.ts
|
|
505
|
+
exports.recommended_default = void 0;
|
|
506
|
+
var init_recommended = __esm({
|
|
507
|
+
"src/configs/recommended.ts"() {
|
|
508
|
+
exports.recommended_default = {
|
|
509
|
+
plugins: {
|
|
510
|
+
get "code-policy"() {
|
|
511
|
+
return (init_index(), __toCommonJS(index_exports)).default;
|
|
512
|
+
}
|
|
513
|
+
},
|
|
514
|
+
rules: {
|
|
515
|
+
"code-policy/atomic-file": "error",
|
|
516
|
+
"code-policy/no-inline-types": "error",
|
|
517
|
+
"code-policy/view-logic-separation": "error",
|
|
518
|
+
"code-policy/public-api-imports": "error",
|
|
519
|
+
"code-policy/no-cross-module-deep-imports": "error"
|
|
520
|
+
}
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
});
|
|
524
|
+
|
|
525
|
+
exports.init_index = init_index;
|
|
526
|
+
exports.init_next = init_next;
|
|
527
|
+
exports.init_react = init_react;
|
|
528
|
+
exports.init_recommended = init_recommended;
|
|
529
|
+
exports.init_strict = init_strict;
|
|
530
|
+
//# sourceMappingURL=chunk-YKNN7DF3.cjs.map
|
|
531
|
+
//# sourceMappingURL=chunk-YKNN7DF3.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/configs/strict.ts","../src/configs/react.ts","../src/configs/next.ts","../src/rules/atomic-file.ts","../src/rules/no-inline-types.ts","../src/rules/view-logic-separation.ts","../src/rules/public-api-imports.ts","../src/rules/no-cross-module-deep-imports.ts","../src/index.ts","../src/configs/recommended.ts"],"names":["strict_default","recommended_default","react_default","next_default","index_default","plugin"],"mappings":"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","file":"chunk-YKNN7DF3.cjs","sourcesContent":["import recommended from './recommended.js'\n\nexport default {\n ...recommended,\n rules: {\n ...recommended.rules,\n // Strict overrides added here\n },\n}\n","import recommended from './recommended.js'\n\nexport default {\n ...recommended,\n rules: {\n ...recommended.rules,\n // React specific adjustments\n },\n}\n","import recommended from './recommended.js'\n\nexport default {\n ...recommended,\n rules: {\n ...recommended.rules,\n // Next specific adjustments\n },\n}\n","import type { Rule } from 'eslint'\n\nconst NEXT_RESERVED_EXPORTS = new Set([\n 'config',\n 'metadata',\n 'dynamic',\n 'revalidate',\n 'fetchCache',\n 'runtime',\n 'preferredRegion',\n 'viewport',\n 'generateMetadata',\n 'generateViewport',\n 'generateStaticParams',\n 'GET',\n 'POST',\n 'PUT',\n 'PATCH',\n 'DELETE',\n 'HEAD',\n 'OPTIONS',\n])\n\nexport default {\n meta: {\n type: 'problem',\n docs: {\n description: 'Enforce atomic file structure (exactly one top-level unit per file)',\n recommended: true,\n },\n fixable: undefined,\n schema: [],\n messages: {\n multipleDeclarations:\n 'File contains multiple top-level declarations (found {{count}}). Extract them into separate files to enforce atomic file structure.',\n },\n },\n create(context) {\n const filename = context.filename || context.physicalFilename || ''\n\n if (\n filename.endsWith('.config.ts') ||\n filename.endsWith('.config.js') ||\n filename.endsWith('.config.mjs') ||\n filename.endsWith('.config.cjs') ||\n filename.endsWith('.d.ts') ||\n filename.endsWith('index.ts') ||\n filename.endsWith('index.tsx') ||\n filename.endsWith('index.js')\n ) {\n return {}\n }\n\n const isNextJsRouterFile =\n /(?:page|layout|loading|error|not-found)\\.tsx$|route\\.ts$|middleware\\.ts$|proxy\\.ts$/.test(\n filename\n )\n\n return {\n Program(node) {\n let count = 0\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const declarations: any[] = []\n\n for (const statement of node.body) {\n if (\n statement.type === 'ImportDeclaration' ||\n statement.type === 'ExportAllDeclaration' ||\n statement.type === 'EmptyStatement' ||\n // @ts-expect-error Typescript specific nodes not in standard estree\n statement.type === 'TSImportEqualsDeclaration'\n ) {\n continue\n }\n\n if (statement.type === 'ExportNamedDeclaration' && !statement.declaration) {\n continue\n }\n\n if (\n isNextJsRouterFile &&\n statement.type === 'ExportNamedDeclaration' &&\n statement.declaration\n ) {\n if (\n statement.declaration.type === 'FunctionDeclaration' &&\n statement.declaration.id &&\n NEXT_RESERVED_EXPORTS.has(statement.declaration.id.name)\n ) {\n continue\n }\n if (statement.declaration.type === 'VariableDeclaration') {\n const allReserved = statement.declaration.declarations.every(\n (d) => d.id.type === 'Identifier' && NEXT_RESERVED_EXPORTS.has(d.id.name)\n )\n if (allReserved) {\n continue\n }\n }\n }\n\n if (statement.type === 'ExpressionStatement') {\n if (\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (statement as any).directive ||\n (statement.expression.type === 'Literal' &&\n typeof statement.expression.value === 'string')\n ) {\n continue\n }\n }\n\n if (statement.type === 'ExportDefaultDeclaration') {\n if (statement.declaration.type === 'Identifier') {\n continue\n }\n if (\n statement.declaration.type === 'CallExpression' &&\n statement.declaration.arguments.length === 1 &&\n statement.declaration.arguments[0].type === 'Identifier'\n ) {\n continue // e.g., export default memo(Component)\n }\n }\n\n const added =\n statement.type === 'VariableDeclaration'\n ? statement.declarations.length\n : statement.type === 'ExportNamedDeclaration' &&\n statement.declaration &&\n statement.declaration.type === 'VariableDeclaration'\n ? statement.declaration.declarations.length\n : 1\n\n count += added\n if (added > 0) {\n declarations.push({ statement, added })\n }\n }\n\n if (count > 1) {\n let reported = 0\n for (const { statement, added } of declarations) {\n if (reported > 0 || added > 1) {\n context.report({\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n node: statement as any,\n messageId: 'multipleDeclarations',\n data: { count },\n })\n }\n reported += added\n }\n }\n },\n }\n },\n} as Rule.RuleModule\n","import type { Rule } from 'eslint'\n\n/**\n * @fileoverview ESLint rule: no inline type or interface declarations.\n *\n * Enforces the atomic file rule: every `type` alias and `interface` declaration\n * must live in its own dedicated file (inside a `types/` folder OR as a\n * standalone \"pure type file\" that contains nothing but type declarations).\n *\n * ✅ Correct: import type { Foo } from '@/types/Foo'\n * ✅ Correct: FooProps.ts containing only `export interface FooProps { ... }`\n * ❌ Wrong: type Foo = { ... } declared inside an implementation file\n *\n * Exemptions:\n * - Files inside `types/` or `types/**` folders\n * - Files ending in `.d.ts`\n * - \"Pure type files\": files whose entire body consists only of\n * import declarations + type/interface declarations (possibly exported)\n */\n\nconst ALLOWED_NEXT_EXPORTS = new Set([\n 'config',\n 'metadata',\n 'dynamic',\n 'revalidate',\n 'fetchCache',\n 'runtime',\n 'preferredRegion',\n 'viewport',\n 'generateMetadata',\n 'generateViewport',\n 'generateStaticParams',\n])\n\nconst ROUTE_METHODS = new Set(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'])\n\nexport default {\n meta: {\n type: 'problem',\n docs: {\n description:\n 'Enforces the Atomic File Rule: exactly one top-level declaration (function, type, class, constant) per file.',\n recommended: true,\n },\n fixable: undefined,\n schema: [],\n messages: {\n singleDeclaration:\n 'Atomic File Rule violation: file contains multiple declarations. Extract \"{{name}}\" into its own file.',\n },\n },\n create(context) {\n // Allow multiple declarations in ambient definition files\n if (context.filename.endsWith('.d.ts')) return {}\n\n return {\n Program(node) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const units: Array<{ node: any; name: string }> = []\n\n for (const stmt of node.body) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let decl: any = stmt\n let isExport = false\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n if (stmt.type === 'ExportNamedDeclaration' && (stmt as any).declaration) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n decl = (stmt as any).declaration\n isExport = true\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } else if (stmt.type === 'ExportDefaultDeclaration' && (stmt as any).declaration) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n decl = (stmt as any).declaration\n isExport = true\n }\n\n const isRouteFile =\n context.filename.endsWith('/route.ts') || context.filename.endsWith('/route.js')\n const declType = decl.type\n\n if (\n declType === 'FunctionDeclaration' ||\n declType === 'ClassDeclaration' ||\n declType === 'TSTypeAliasDeclaration' ||\n declType === 'TSInterfaceDeclaration' ||\n declType === 'TSEnumDeclaration'\n ) {\n const name = decl.id?.name ?? 'default'\n if (\n isRouteFile &&\n isExport &&\n declType === 'FunctionDeclaration' &&\n ROUTE_METHODS.has(name)\n ) {\n continue\n }\n units.push({ node: decl, name })\n } else if (declType === 'VariableDeclaration') {\n for (const d of decl.declarations) {\n const name = d.id?.name\n if (isExport && ALLOWED_NEXT_EXPORTS.has(name)) {\n continue\n }\n if (isRouteFile && isExport && ROUTE_METHODS.has(name)) {\n continue\n }\n units.push({ node: decl, name: name ?? 'unknown' })\n }\n }\n }\n\n if (units.length > 1) {\n for (let i = 1; i < units.length; i++) {\n context.report({\n node: units[i].node,\n messageId: 'singleDeclaration',\n data: { name: units[i].name },\n })\n }\n }\n },\n }\n },\n} as Rule.RuleModule\n","import type { Rule } from 'eslint'\n\n/**\n * Determines whether a function node is a top-level component declaration.\n * Top-level means it is directly under Program, ExportNamedDeclaration,\n * ExportDefaultDeclaration, or assigned as a top-level VariableDeclarator.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction isComponentNode(node: any): boolean {\n if (!node.parent) return false\n const isTopLevel =\n node.parent.type === 'Program' ||\n node.parent.type === 'ExportNamedDeclaration' ||\n node.parent.type === 'ExportDefaultDeclaration' ||\n (node.parent.type === 'VariableDeclarator' &&\n (node.parent.parent?.parent?.type === 'Program' ||\n node.parent.parent?.parent?.type === 'ExportNamedDeclaration'))\n return isTopLevel\n}\n\n/**\n * Walks up the AST to find the nearest enclosing top-level function component.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction getEnclosingComponent(node: any): any {\n let curr = node.parent\n while (curr) {\n if (\n (curr.type === 'FunctionDeclaration' ||\n curr.type === 'ArrowFunctionExpression' ||\n curr.type === 'FunctionExpression') &&\n isComponentNode(curr)\n ) {\n return curr\n }\n curr = curr.parent\n }\n return null\n}\n\nexport default {\n meta: {\n type: 'problem',\n docs: {\n description:\n 'Enforces strict separation of logic from views. React views (.tsx) must not contain state, lifecycle effects, or inline handler declarations. Move logic to a custom hook.',\n recommended: true,\n },\n fixable: undefined,\n schema: [],\n messages: {\n noReactHooks:\n 'Strict View Separation: The hook \"{{name}}\" is forbidden in a view component. Extract your state/effects to a separate use{{componentName}} hook.',\n noInlineHandlers:\n 'Strict View Separation: Inline function or handler declaration ({{name}}) inside a view component is forbidden. Return it from your custom hook instead.',\n },\n },\n create(context) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const filename = context.filename || (context as any).physicalFilename || ''\n\n // Only run this rule on .tsx files\n if (!filename.endsWith('.tsx')) {\n return {}\n }\n\n return {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n 'FunctionDeclaration, ArrowFunctionExpression, FunctionExpression'(node: any) {\n if (!isComponentNode(node)) {\n const component = getEnclosingComponent(node)\n if (component) {\n if (\n node.parent &&\n (node.parent.type === 'VariableDeclarator' || node.type === 'FunctionDeclaration')\n ) {\n let name = 'anonymous function'\n if (node.id && node.id.name) name = node.id.name\n else if (\n node.parent.type === 'VariableDeclarator' &&\n node.parent.id &&\n node.parent.id.name\n )\n name = node.parent.id.name\n\n context.report({\n node,\n messageId: 'noInlineHandlers',\n data: { name },\n })\n }\n }\n }\n },\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n CallExpression(node: any) {\n if (node.callee && node.callee.type === 'Identifier') {\n const name = node.callee.name\n if (\n /^use(State|Effect|Reducer|Callback|Memo|Ref|ImperativeHandle|LayoutEffect|DebugValue|DeferredValue|Transition|Id|SyncExternalStore|InsertionEffect|Query|Mutation)$/.test(\n name\n )\n ) {\n const component = getEnclosingComponent(node)\n if (component) {\n const componentNameBase =\n filename.split('/').pop()?.replace('.tsx', '') || 'Component'\n context.report({\n node,\n messageId: 'noReactHooks',\n data: { name, componentName: componentNameBase },\n })\n }\n }\n }\n },\n }\n },\n} as Rule.RuleModule\n","import type { Rule } from 'eslint'\n\nexport default {\n meta: {\n type: 'problem',\n docs: {\n description:\n 'Enforce that cross-module imports only target the module public API (index), not deep internal files.',\n recommended: true,\n },\n fixable: undefined,\n schema: [\n {\n type: 'object',\n properties: {\n bannedSubpaths: {\n type: 'array',\n items: { type: 'string' },\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n deepImportNotAllowed:\n 'Deep import \"{{importPath}}\" is not allowed. Import from the public API (root) of the module instead.',\n },\n },\n create(context) {\n const options = context.options[0] || {}\n const bannedSubpaths: string[] = options.bannedSubpaths || ['/src/']\n\n return {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n ImportDeclaration(node: any) {\n const importPath = node.source.value\n\n if (typeof importPath !== 'string') return\n if (importPath.startsWith('.')) return // Ignore relative imports within the same package\n\n for (const subpath of bannedSubpaths) {\n // If the import is an absolute/alias import and contains the banned subpath\n if (importPath.includes(subpath)) {\n context.report({\n node,\n messageId: 'deepImportNotAllowed',\n data: { importPath },\n })\n break\n }\n }\n },\n }\n },\n} as Rule.RuleModule\n","import type { Rule } from 'eslint'\n\n/**\n * no-cross-module-deep-imports\n *\n * Prevents modules within a monorepo from bypassing each other's public API.\n * A \"deep import\" is any relative import that traverses up two or more directory\n * levels and then descends into another module's internal directory.\n *\n * Example monorepo:\n * packages/core/src/utils/helper.ts\n * packages/ui/src/Button.tsx\n *\n * ❌ Wrong (from Button.tsx):\n * import { helper } from '../../core/src/utils/helper'\n *\n * ✅ Correct:\n * import { helper } from '@myorg/core' // through published public API\n *\n * The rule detects the pattern by looking for relative imports that:\n * 1. Go up at least `minParentTraversals` levels (default: 2)\n * 2. Then descend into a directory matching one of `internalDirs` (default: ['src'])\n *\n * Options (object):\n * - minParentTraversals: number (default 2) — how many `../` levels must be\n * present before we start looking for an internal dir descent.\n * - internalDirs: string[] (default ['src']) — directory names that signal\n * internal code that should be accessed only via the public API.\n */\n\nexport default {\n meta: {\n type: 'problem',\n docs: {\n description:\n 'Forbid relative imports that bypass the public API of another module within the monorepo by importing directly from its internal directories.',\n recommended: true,\n },\n fixable: undefined,\n schema: [\n {\n type: 'object',\n properties: {\n minParentTraversals: { type: 'number' },\n internalDirs: {\n type: 'array',\n items: { type: 'string' },\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n deepImport:\n 'Cross-module deep import \"{{importPath}}\" bypasses the module\\'s public API. Import from the module root (index) instead.',\n },\n },\n create(context) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const options = (context.options[0] as any) || {}\n const minParentTraversals: number = options.minParentTraversals ?? 2\n const internalDirs: string[] = options.internalDirs ?? ['src']\n\n return {\n ImportDeclaration(node) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const importPath = (node.source as any).value as string\n\n if (typeof importPath !== 'string') return\n if (!importPath.startsWith('.')) return // ignore absolute/alias imports\n\n // Count leading `../` segments\n const parts = importPath.split('/')\n let parentCount = 0\n for (const part of parts) {\n if (part === '..') parentCount++\n else break\n }\n\n if (parentCount < minParentTraversals) return\n\n // Check if any of the non-`..` segments is an internal dir\n const descendantParts = parts.slice(parentCount)\n const hasInternalSegment = descendantParts.some((p) => internalDirs.includes(p))\n\n if (hasInternalSegment) {\n context.report({\n node,\n messageId: 'deepImport',\n data: { importPath },\n })\n }\n },\n }\n },\n} as Rule.RuleModule\n","import recommended from './configs/recommended.js'\nimport strict from './configs/strict.js'\nimport react from './configs/react.js'\nimport next from './configs/next.js'\n\nimport atomicFile from './rules/atomic-file.js'\nimport noInlineTypes from './rules/no-inline-types.js'\nimport viewLogicSeparation from './rules/view-logic-separation.js'\nimport publicApiImports from './rules/public-api-imports.js'\nimport noCrossModuleDeepImports from './rules/no-cross-module-deep-imports.js'\n\nconst plugin = {\n meta: {\n name: 'eslint-plugin-code-policy',\n version: '0.1.0',\n },\n rules: {\n 'atomic-file': atomicFile,\n 'no-inline-types': noInlineTypes,\n 'view-logic-separation': viewLogicSeparation,\n 'public-api-imports': publicApiImports,\n 'no-cross-module-deep-imports': noCrossModuleDeepImports,\n },\n configs: {\n recommended,\n strict,\n react,\n next,\n },\n}\n\nexport default plugin\nexport { plugin }\n","export default {\n plugins: {\n get 'code-policy'() {\n // Workaround for circular dependency\n // Since configs imports rules, and index exports both\n // Flat config works best when plugin object is injected locally\n // We will resolve this strictly in execution.\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n return require('../index.js').default\n },\n },\n rules: {\n 'code-policy/atomic-file': 'error',\n 'code-policy/no-inline-types': 'error',\n 'code-policy/view-logic-separation': 'error',\n 'code-policy/public-api-imports': 'error',\n 'code-policy/no-cross-module-deep-imports': 'error',\n },\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"next.cjs"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
declare const _default: {
|
|
2
|
+
rules: {
|
|
3
|
+
'code-policy/atomic-file': string;
|
|
4
|
+
'code-policy/no-inline-types': string;
|
|
5
|
+
'code-policy/view-logic-separation': string;
|
|
6
|
+
'code-policy/public-api-imports': string;
|
|
7
|
+
'code-policy/no-cross-module-deep-imports': string;
|
|
8
|
+
};
|
|
9
|
+
plugins: {
|
|
10
|
+
readonly 'code-policy': any;
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
export default _default;
|
|
14
|
+
//# sourceMappingURL=next.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"next.d.ts","sourceRoot":"","sources":["../../src/configs/next.ts"],"names":[],"mappings":";;;;;;;;;;;;AAEA,wBAMC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"next.js"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"react.cjs"}
|