eslint-plugin-next-edge-boundary 0.1.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 (68) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +110 -0
  3. package/dist/configs/recommended.d.ts +3 -0
  4. package/dist/configs/recommended.d.ts.map +1 -0
  5. package/dist/configs/recommended.js +13 -0
  6. package/dist/configs/recommended.js.map +1 -0
  7. package/dist/configs/strict.d.ts +3 -0
  8. package/dist/configs/strict.d.ts.map +1 -0
  9. package/dist/configs/strict.js +13 -0
  10. package/dist/configs/strict.js.map +1 -0
  11. package/dist/core/classify.d.ts +14 -0
  12. package/dist/core/classify.d.ts.map +1 -0
  13. package/dist/core/classify.js +59 -0
  14. package/dist/core/classify.js.map +1 -0
  15. package/dist/core/constants.d.ts +10 -0
  16. package/dist/core/constants.d.ts.map +1 -0
  17. package/dist/core/constants.js +92 -0
  18. package/dist/core/constants.js.map +1 -0
  19. package/dist/core/entrypoints.d.ts +2 -0
  20. package/dist/core/entrypoints.d.ts.map +1 -0
  21. package/dist/core/entrypoints.js +20 -0
  22. package/dist/core/entrypoints.js.map +1 -0
  23. package/dist/core/format-chain.d.ts +5 -0
  24. package/dist/core/format-chain.d.ts.map +1 -0
  25. package/dist/core/format-chain.js +35 -0
  26. package/dist/core/format-chain.js.map +1 -0
  27. package/dist/core/import-graph.d.ts +35 -0
  28. package/dist/core/import-graph.d.ts.map +1 -0
  29. package/dist/core/import-graph.js +169 -0
  30. package/dist/core/import-graph.js.map +1 -0
  31. package/dist/core/import-kind.d.ts +10 -0
  32. package/dist/core/import-kind.d.ts.map +1 -0
  33. package/dist/core/import-kind.js +19 -0
  34. package/dist/core/import-kind.js.map +1 -0
  35. package/dist/core/options.d.ts +26 -0
  36. package/dist/core/options.d.ts.map +1 -0
  37. package/dist/core/options.js +116 -0
  38. package/dist/core/options.js.map +1 -0
  39. package/dist/core/resolve-module.d.ts +24 -0
  40. package/dist/core/resolve-module.d.ts.map +1 -0
  41. package/dist/core/resolve-module.js +232 -0
  42. package/dist/core/resolve-module.js.map +1 -0
  43. package/dist/core/size-estimate.d.ts +17 -0
  44. package/dist/core/size-estimate.d.ts.map +1 -0
  45. package/dist/core/size-estimate.js +48 -0
  46. package/dist/core/size-estimate.js.map +1 -0
  47. package/dist/index.d.ts +18 -0
  48. package/dist/index.d.ts.map +1 -0
  49. package/dist/index.js +40 -0
  50. package/dist/index.js.map +1 -0
  51. package/dist/rules/max-graph-bytes.d.ts +3 -0
  52. package/dist/rules/max-graph-bytes.d.ts.map +1 -0
  53. package/dist/rules/max-graph-bytes.js +123 -0
  54. package/dist/rules/max-graph-bytes.js.map +1 -0
  55. package/dist/rules/no-barrels.d.ts +3 -0
  56. package/dist/rules/no-barrels.d.ts.map +1 -0
  57. package/dist/rules/no-barrels.js +93 -0
  58. package/dist/rules/no-barrels.js.map +1 -0
  59. package/dist/rules/no-node-apis.d.ts +3 -0
  60. package/dist/rules/no-node-apis.d.ts.map +1 -0
  61. package/dist/rules/no-node-apis.js +118 -0
  62. package/dist/rules/no-node-apis.js.map +1 -0
  63. package/dist/rules/types.d.ts +30 -0
  64. package/dist/rules/types.d.ts.map +1 -0
  65. package/dist/rules/types.js +2 -0
  66. package/dist/rules/types.js.map +1 -0
  67. package/docs/hero.png +0 -0
  68. package/package.json +63 -0
@@ -0,0 +1,17 @@
1
+ import type { GraphNode } from "./import-graph.js";
2
+ export type SizeContributor = {
3
+ id: string;
4
+ bytes: number;
5
+ };
6
+ export type SizeEstimate = {
7
+ totalBytes: number;
8
+ contributors: SizeContributor[];
9
+ };
10
+ export declare function estimateFileBytes(filePath: string): number;
11
+ export declare function estimateGraphBytes(nodes: GraphNode[], options?: {
12
+ includeNodeModules?: boolean;
13
+ packageWeights?: Record<string, number>;
14
+ ignorePatterns?: string[];
15
+ cwd?: string;
16
+ }): SizeEstimate;
17
+ //# sourceMappingURL=size-estimate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"size-estimate.d.ts","sourceRoot":"","sources":["../../src/core/size-estimate.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAEnD,MAAM,MAAM,eAAe,GAAG;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,eAAe,EAAE,CAAC;CACjC,CAAC;AAEF,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAM1D;AAED,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,SAAS,EAAE,EAClB,OAAO,GAAE;IACP,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,GAAG,CAAC,EAAE,MAAM,CAAC;CACT,GACL,YAAY,CAsCd"}
@@ -0,0 +1,48 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { DEFAULT_PACKAGE_WEIGHTS, } from "./constants.js";
4
+ import { matchesIgnorePattern } from "./options.js";
5
+ export function estimateFileBytes(filePath) {
6
+ try {
7
+ return fs.statSync(filePath).size;
8
+ }
9
+ catch {
10
+ return 0;
11
+ }
12
+ }
13
+ export function estimateGraphBytes(nodes, options = {}) {
14
+ const weights = {
15
+ ...DEFAULT_PACKAGE_WEIGHTS,
16
+ ...options.packageWeights,
17
+ };
18
+ const contributors = [];
19
+ let totalBytes = 0;
20
+ const seen = new Set();
21
+ for (const node of nodes) {
22
+ if (seen.has(node.id)) {
23
+ continue;
24
+ }
25
+ seen.add(node.id);
26
+ if (node.kind === "file") {
27
+ if (matchesIgnorePattern(node.id, options.ignorePatterns)) {
28
+ continue;
29
+ }
30
+ if (!options.includeNodeModules && node.id.includes(`${path.sep}node_modules${path.sep}`)) {
31
+ continue;
32
+ }
33
+ const bytes = estimateFileBytes(node.id);
34
+ totalBytes += bytes;
35
+ contributors.push({ id: node.id, bytes });
36
+ continue;
37
+ }
38
+ if (node.kind === "package" && options.includeNodeModules) {
39
+ const packageName = node.packageName ?? node.id;
40
+ const bytes = weights[packageName] ?? 5_000;
41
+ totalBytes += bytes;
42
+ contributors.push({ id: packageName, bytes });
43
+ }
44
+ }
45
+ contributors.sort((a, b) => b.bytes - a.bytes);
46
+ return { totalBytes, contributors };
47
+ }
48
+ //# sourceMappingURL=size-estimate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"size-estimate.js","sourceRoot":"","sources":["../../src/core/size-estimate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EACL,uBAAuB,GACxB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAapD,MAAM,UAAU,iBAAiB,CAAC,QAAgB;IAChD,IAAI,CAAC;QACH,OAAO,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC;IACpC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,CAAC;IACX,CAAC;AACH,CAAC;AAED,MAAM,UAAU,kBAAkB,CAChC,KAAkB,EAClB,UAKI,EAAE;IAEN,MAAM,OAAO,GAAG;QACd,GAAG,uBAAuB;QAC1B,GAAG,OAAO,CAAC,cAAc;KAC1B,CAAC;IACF,MAAM,YAAY,GAAsB,EAAE,CAAC;IAC3C,IAAI,UAAU,GAAG,CAAC,CAAC;IACnB,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAE/B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;YACtB,SAAS;QACX,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAElB,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YACzB,IAAI,oBAAoB,CAAC,IAAI,CAAC,EAAE,EAAE,OAAO,CAAC,cAAc,CAAC,EAAE,CAAC;gBAC1D,SAAS;YACX,CAAC;YACD,IAAI,CAAC,OAAO,CAAC,kBAAkB,IAAI,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC,GAAG,eAAe,IAAI,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC;gBAC1F,SAAS;YACX,CAAC;YACD,MAAM,KAAK,GAAG,iBAAiB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACzC,UAAU,IAAI,KAAK,CAAC;YACpB,YAAY,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;YAC1C,SAAS;QACX,CAAC;QAED,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,OAAO,CAAC,kBAAkB,EAAE,CAAC;YAC1D,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,EAAE,CAAC;YAChD,MAAM,KAAK,GAAG,OAAO,CAAC,WAAW,CAAC,IAAI,KAAK,CAAC;YAC5C,UAAU,IAAI,KAAK,CAAC;YACpB,YAAY,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,CAAC;QAChD,CAAC;IACH,CAAC;IAED,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;IAC/C,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,CAAC;AACtC,CAAC"}
@@ -0,0 +1,18 @@
1
+ import type { ESLint } from "eslint";
2
+ declare const rules: {
3
+ "no-node-apis": import("./rules/types.js").RuleModule;
4
+ "max-graph-bytes": import("./rules/types.js").RuleModule;
5
+ "no-barrels": import("./rules/types.js").RuleModule;
6
+ };
7
+ declare const plugin: {
8
+ meta: {
9
+ name: string;
10
+ version: string;
11
+ };
12
+ rules: ESLint.Plugin["rules"];
13
+ configs: NonNullable<ESLint.Plugin["configs"]>;
14
+ };
15
+ export default plugin;
16
+ export { rules };
17
+ export type { SharedOptions, MaxGraphBytesOptions, NoBarrelsOptions, } from "./core/options.js";
18
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAU,MAAM,QAAQ,CAAC;AAQ7C,QAAA,MAAM,KAAK;;;;CAIV,CAAC;AAEF,QAAA,MAAM,MAAM;;;;;WAKM,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC;aACvB,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;CAC7B,CAAC;AAsB1B,eAAe,MAAM,CAAC;AACtB,OAAO,EAAE,KAAK,EAAE,CAAC;AACjB,YAAY,EACV,aAAa,EACb,oBAAoB,EACpB,gBAAgB,GACjB,MAAM,mBAAmB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,40 @@
1
+ import { PACKAGE_NAME } from "./core/constants.js";
2
+ import { recommendedConfig } from "./configs/recommended.js";
3
+ import { strictConfig } from "./configs/strict.js";
4
+ import { maxGraphBytesRule } from "./rules/max-graph-bytes.js";
5
+ import { noBarrelsRule } from "./rules/no-barrels.js";
6
+ import { noNodeApisRule } from "./rules/no-node-apis.js";
7
+ const rules = {
8
+ "no-node-apis": noNodeApisRule,
9
+ "max-graph-bytes": maxGraphBytesRule,
10
+ "no-barrels": noBarrelsRule,
11
+ };
12
+ const plugin = {
13
+ meta: {
14
+ name: PACKAGE_NAME,
15
+ version: "0.1.0",
16
+ },
17
+ rules: rules,
18
+ configs: {},
19
+ };
20
+ function withPlugin(config) {
21
+ return {
22
+ ...config,
23
+ plugins: {
24
+ "next-edge-boundary": plugin,
25
+ },
26
+ };
27
+ }
28
+ plugin.configs.recommended = withPlugin(recommendedConfig);
29
+ plugin.configs.strict = withPlugin(strictConfig);
30
+ plugin.configs["recommended-legacy"] = {
31
+ plugins: ["next-edge-boundary"],
32
+ rules: recommendedConfig.rules,
33
+ };
34
+ plugin.configs["strict-legacy"] = {
35
+ plugins: ["next-edge-boundary"],
36
+ rules: strictConfig.rules,
37
+ };
38
+ export default plugin;
39
+ export { rules };
40
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAEzD,MAAM,KAAK,GAAG;IACZ,cAAc,EAAE,cAAc;IAC9B,iBAAiB,EAAE,iBAAiB;IACpC,YAAY,EAAE,aAAa;CAC5B,CAAC;AAEF,MAAM,MAAM,GAAG;IACb,IAAI,EAAE;QACJ,IAAI,EAAE,YAAY;QAClB,OAAO,EAAE,OAAO;KACjB;IACD,KAAK,EAAE,KAA+B;IACtC,OAAO,EAAE,EAA2C;CAC7B,CAAC;AAE1B,SAAS,UAAU,CAAC,MAAqB;IACvC,OAAO;QACL,GAAG,MAAM;QACT,OAAO,EAAE;YACP,oBAAoB,EAAE,MAAM;SAC7B;KACF,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,OAAO,CAAC,WAAW,GAAG,UAAU,CAAC,iBAAiB,CAAC,CAAC;AAC3D,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,UAAU,CAAC,YAAY,CAAC,CAAC;AACjD,MAAM,CAAC,OAAO,CAAC,oBAAoB,CAAC,GAAG;IACrC,OAAO,EAAE,CAAC,oBAAoB,CAAC;IAC/B,KAAK,EAAE,iBAAiB,CAAC,KAAK;CAC/B,CAAC;AACF,MAAM,CAAC,OAAO,CAAC,eAAe,CAAC,GAAG;IAChC,OAAO,EAAE,CAAC,oBAAoB,CAAC;IAC/B,KAAK,EAAE,YAAY,CAAC,KAAK;CAC1B,CAAC;AAEF,eAAe,MAAM,CAAC;AACtB,OAAO,EAAE,KAAK,EAAE,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { RuleModule } from "./types.js";
2
+ export declare const maxGraphBytesRule: RuleModule;
3
+ //# sourceMappingURL=max-graph-bytes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"max-graph-bytes.d.ts","sourceRoot":"","sources":["../../src/rules/max-graph-bytes.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAe,UAAU,EAAE,MAAM,YAAY,CAAC;AAE1D,eAAO,MAAM,iBAAiB,EAAE,UA8H/B,CAAC"}
@@ -0,0 +1,123 @@
1
+ import { DEFAULT_MAX_BYTES_RECOMMENDED } from "../core/constants.js";
2
+ import { isEdgeEntrypoint } from "../core/entrypoints.js";
3
+ import { formatBytes, formatChain } from "../core/format-chain.js";
4
+ import { walkImportGraph } from "../core/import-graph.js";
5
+ import { parseMaxGraphBytesOptions, } from "../core/options.js";
6
+ import { estimateGraphBytes } from "../core/size-estimate.js";
7
+ export const maxGraphBytesRule = {
8
+ meta: {
9
+ type: "problem",
10
+ docs: {
11
+ description: "Limit the estimated local import-graph size reachable from Edge entries.",
12
+ },
13
+ schema: [
14
+ {
15
+ type: "object",
16
+ additionalProperties: false,
17
+ properties: {
18
+ max: { type: "number" },
19
+ includeNodeModules: { type: "boolean" },
20
+ packageWeights: {
21
+ type: "object",
22
+ additionalProperties: { type: "number" },
23
+ },
24
+ allowModules: { type: "array", items: { type: "string" } },
25
+ denyModules: { type: "array", items: { type: "string" } },
26
+ ignorePatterns: { type: "array", items: { type: "string" } },
27
+ tsconfigPath: { type: "string" },
28
+ allowImportChains: {
29
+ type: "array",
30
+ items: {
31
+ type: "array",
32
+ items: { type: "string" },
33
+ },
34
+ },
35
+ },
36
+ },
37
+ ],
38
+ messages: {
39
+ tooLarge: "Edge import graph is ~{{total}} (budget {{budget}}).\n\nHeaviest contributors:\n{{contributors}}\n\nImport a thinner Edge slice from the entry file.",
40
+ },
41
+ },
42
+ create(context) {
43
+ const filename = context.filename ?? context.getFilename();
44
+ if (!isEdgeEntrypoint(filename)) {
45
+ return {};
46
+ }
47
+ let options;
48
+ try {
49
+ options = parseMaxGraphBytesOptions(context.options[0]);
50
+ }
51
+ catch (error) {
52
+ throw error instanceof Error ? error : new Error(String(error));
53
+ }
54
+ const max = options.max ?? DEFAULT_MAX_BYTES_RECOMMENDED;
55
+ const entryImports = [];
56
+ let programNode = null;
57
+ return {
58
+ Program(node) {
59
+ programNode = node;
60
+ },
61
+ ImportDeclaration(node) {
62
+ if (node.importKind === "type") {
63
+ return;
64
+ }
65
+ if (typeof node.source.value !== "string") {
66
+ return;
67
+ }
68
+ entryImports.push({ specifier: node.source.value, node });
69
+ },
70
+ ExportNamedDeclaration(node) {
71
+ if (node.exportKind === "type" || !node.source) {
72
+ return;
73
+ }
74
+ if (typeof node.source.value !== "string") {
75
+ return;
76
+ }
77
+ entryImports.push({ specifier: node.source.value, node });
78
+ },
79
+ ExportAllDeclaration(node) {
80
+ if (node.exportKind === "type") {
81
+ return;
82
+ }
83
+ if (typeof node.source.value !== "string") {
84
+ return;
85
+ }
86
+ entryImports.push({ specifier: node.source.value, node });
87
+ },
88
+ "Program:exit"() {
89
+ const walk = walkImportGraph(filename, options);
90
+ const estimate = estimateGraphBytes(walk.nodes, {
91
+ includeNodeModules: options.includeNodeModules,
92
+ packageWeights: options.packageWeights,
93
+ ignorePatterns: options.ignorePatterns,
94
+ });
95
+ if (estimate.totalBytes <= max) {
96
+ return;
97
+ }
98
+ const top = estimate.contributors.slice(0, 5);
99
+ const contributors = top
100
+ .map((item) => {
101
+ const label = formatChain([item.id]).trim();
102
+ const size = formatBytes(item.bytes).padStart(5, " ");
103
+ return ` +${size} ${label}`;
104
+ })
105
+ .join("\n");
106
+ const reportNode = entryImports[0]?.node ?? programNode;
107
+ if (!reportNode) {
108
+ return;
109
+ }
110
+ context.report({
111
+ node: reportNode,
112
+ messageId: "tooLarge",
113
+ data: {
114
+ total: formatBytes(estimate.totalBytes),
115
+ budget: formatBytes(max),
116
+ contributors,
117
+ },
118
+ });
119
+ },
120
+ };
121
+ },
122
+ };
123
+ //# sourceMappingURL=max-graph-bytes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"max-graph-bytes.js","sourceRoot":"","sources":["../../src/rules/max-graph-bytes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { RuleModule } from "./types.js";
2
+ export declare const noBarrelsRule: RuleModule;
3
+ //# sourceMappingURL=no-barrels.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-barrels.d.ts","sourceRoot":"","sources":["../../src/rules/no-barrels.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAe,UAAU,EAAE,MAAM,YAAY,CAAC;AAgB1D,eAAO,MAAM,aAAa,EAAE,UAwF3B,CAAC"}
@@ -0,0 +1,93 @@
1
+ import { DEFAULT_BARREL_PATTERNS } from "../core/constants.js";
2
+ import { isEdgeEntrypoint } from "../core/entrypoints.js";
3
+ import { matchesAllowOrDeny, parseNoBarrelsOptions, } from "../core/options.js";
4
+ function matchesBarrelPattern(specifier, patterns) {
5
+ const normalized = specifier.replace(/\/index$/, "");
6
+ return patterns.some((pattern) => {
7
+ const p = pattern.replace(/\/index$/, "");
8
+ return (specifier === pattern ||
9
+ normalized === p ||
10
+ specifier === `${p}/index` ||
11
+ specifier.endsWith(`/${pattern}`) ||
12
+ specifier.endsWith(`/${p}`));
13
+ });
14
+ }
15
+ export const noBarrelsRule = {
16
+ meta: {
17
+ type: "problem",
18
+ docs: {
19
+ description: "Disallow barrel and heavy namespace imports directly from Edge entries.",
20
+ },
21
+ schema: [
22
+ {
23
+ type: "object",
24
+ additionalProperties: false,
25
+ properties: {
26
+ barrelPatterns: { type: "array", items: { type: "string" } },
27
+ forbidNamespaceImports: { type: "boolean" },
28
+ allowModules: { type: "array", items: { type: "string" } },
29
+ denyModules: { type: "array", items: { type: "string" } },
30
+ ignorePatterns: { type: "array", items: { type: "string" } },
31
+ tsconfigPath: { type: "string" },
32
+ allowImportChains: {
33
+ type: "array",
34
+ items: {
35
+ type: "array",
36
+ items: { type: "string" },
37
+ },
38
+ },
39
+ },
40
+ },
41
+ ],
42
+ messages: {
43
+ barrel: "Edge entry imports barrel module \"{{specifier}}\". Import a specific Edge-safe module instead.",
44
+ namespace: "Edge entry uses namespace import from \"{{specifier}}\". Prefer named imports of a thin Edge slice.",
45
+ },
46
+ },
47
+ create(context) {
48
+ const filename = context.filename ?? context.getFilename();
49
+ if (!isEdgeEntrypoint(filename)) {
50
+ return {};
51
+ }
52
+ let options;
53
+ try {
54
+ options = parseNoBarrelsOptions(context.options[0]);
55
+ }
56
+ catch (error) {
57
+ throw error instanceof Error ? error : new Error(String(error));
58
+ }
59
+ const patterns = options.barrelPatterns ?? [...DEFAULT_BARREL_PATTERNS];
60
+ const forbidNamespace = options.forbidNamespaceImports ?? true;
61
+ return {
62
+ ImportDeclaration(node) {
63
+ if (node.importKind === "type") {
64
+ return;
65
+ }
66
+ if (typeof node.source.value !== "string") {
67
+ return;
68
+ }
69
+ const specifier = node.source.value;
70
+ if (matchesAllowOrDeny(specifier, options.allowModules)) {
71
+ return;
72
+ }
73
+ if (matchesBarrelPattern(specifier, patterns)) {
74
+ context.report({
75
+ node,
76
+ messageId: "barrel",
77
+ data: { specifier },
78
+ });
79
+ return;
80
+ }
81
+ if (forbidNamespace &&
82
+ node.specifiers.some((spec) => spec.type === "ImportNamespaceSpecifier")) {
83
+ context.report({
84
+ node,
85
+ messageId: "namespace",
86
+ data: { specifier },
87
+ });
88
+ }
89
+ },
90
+ };
91
+ },
92
+ };
93
+ //# sourceMappingURL=no-barrels.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-barrels.js","sourceRoot":"","sources":["../../src/rules/no-barrels.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { RuleModule } from "./types.js";
2
+ export declare const noNodeApisRule: RuleModule;
3
+ //# sourceMappingURL=no-node-apis.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-node-apis.d.ts","sourceRoot":"","sources":["../../src/rules/no-node-apis.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAe,UAAU,EAAE,MAAM,YAAY,CAAC;AAoB1D,eAAO,MAAM,cAAc,EAAE,UA0G5B,CAAC"}
@@ -0,0 +1,118 @@
1
+ import { isEdgeEntrypoint } from "../core/entrypoints.js";
2
+ import { findDeniedPaths, walkImportGraph, } from "../core/import-graph.js";
3
+ import { formatChain } from "../core/format-chain.js";
4
+ import { matchesAllowOrDeny, parseSharedOptions, } from "../core/options.js";
5
+ function chainAllowed(chain, allowImportChains) {
6
+ if (!allowImportChains || allowImportChains.length === 0) {
7
+ return false;
8
+ }
9
+ return allowImportChains.some((allowed) => {
10
+ if (allowed.length !== chain.length) {
11
+ return false;
12
+ }
13
+ return allowed.every((part, index) => {
14
+ const actual = chain[index] ?? "";
15
+ return actual === part || actual.endsWith(part) || actual.includes(part);
16
+ });
17
+ });
18
+ }
19
+ export const noNodeApisRule = {
20
+ meta: {
21
+ type: "problem",
22
+ docs: {
23
+ description: "Disallow Node builtins and Edge-hostile packages reachable from Edge entry imports.",
24
+ },
25
+ schema: [
26
+ {
27
+ type: "object",
28
+ additionalProperties: false,
29
+ properties: {
30
+ allowModules: { type: "array", items: { type: "string" } },
31
+ denyModules: { type: "array", items: { type: "string" } },
32
+ ignorePatterns: { type: "array", items: { type: "string" } },
33
+ tsconfigPath: { type: "string" },
34
+ allowImportChains: {
35
+ type: "array",
36
+ items: {
37
+ type: "array",
38
+ items: { type: "string" },
39
+ },
40
+ },
41
+ },
42
+ },
43
+ ],
44
+ messages: {
45
+ forbidden: "Edge boundary violated: Node / forbidden module \"{{moduleId}}\" is reachable.\n\n{{chain}}\n\nSplit an Edge-safe module that only exports what middleware needs.",
46
+ },
47
+ },
48
+ create(context) {
49
+ const filename = context.filename ?? context.getFilename();
50
+ if (!isEdgeEntrypoint(filename)) {
51
+ return {};
52
+ }
53
+ let options;
54
+ try {
55
+ options = parseSharedOptions(context.options[0]);
56
+ }
57
+ catch (error) {
58
+ throw error instanceof Error ? error : new Error(String(error));
59
+ }
60
+ const entryImports = [];
61
+ return {
62
+ ImportDeclaration(node) {
63
+ if (node.importKind === "type") {
64
+ return;
65
+ }
66
+ if (typeof node.source.value !== "string") {
67
+ return;
68
+ }
69
+ entryImports.push({ specifier: node.source.value, node });
70
+ },
71
+ ExportNamedDeclaration(node) {
72
+ if (node.exportKind === "type" || !node.source) {
73
+ return;
74
+ }
75
+ if (typeof node.source.value !== "string") {
76
+ return;
77
+ }
78
+ entryImports.push({ specifier: node.source.value, node });
79
+ },
80
+ ExportAllDeclaration(node) {
81
+ if (node.exportKind === "type") {
82
+ return;
83
+ }
84
+ if (typeof node.source.value !== "string") {
85
+ return;
86
+ }
87
+ entryImports.push({ specifier: node.source.value, node });
88
+ },
89
+ "Program:exit"() {
90
+ for (const entryImport of entryImports) {
91
+ if (matchesAllowOrDeny(entryImport.specifier, options.allowModules)) {
92
+ continue;
93
+ }
94
+ const walk = walkImportGraph(filename, {
95
+ ...options,
96
+ seedSpecifiers: [entryImport.specifier],
97
+ });
98
+ const denied = findDeniedPaths(walk);
99
+ for (const hit of denied) {
100
+ if (chainAllowed(hit.chain, options.allowImportChains)) {
101
+ continue;
102
+ }
103
+ context.report({
104
+ node: entryImport.node,
105
+ messageId: "forbidden",
106
+ data: {
107
+ moduleId: hit.moduleId,
108
+ chain: formatChain(hit.chain),
109
+ },
110
+ });
111
+ break;
112
+ }
113
+ }
114
+ },
115
+ };
116
+ },
117
+ };
118
+ //# sourceMappingURL=no-node-apis.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-node-apis.js","sourceRoot":"","sources":["../../src/rules/no-node-apis.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import type { TSESLint, TSESTree } from "@typescript-eslint/utils";
2
+ export type RuleListener = TSESLint.RuleListener & {
3
+ ImportDeclaration?(node: TSESTree.ImportDeclaration): void;
4
+ ExportNamedDeclaration?(node: TSESTree.ExportNamedDeclaration): void;
5
+ ExportAllDeclaration?(node: TSESTree.ExportAllDeclaration): void;
6
+ Program?(node: TSESTree.Program): void;
7
+ "Program:exit"?(): void;
8
+ };
9
+ export type RuleContext = {
10
+ filename?: string;
11
+ getFilename(): string;
12
+ options: readonly unknown[];
13
+ report(descriptor: {
14
+ node: TSESTree.Node;
15
+ messageId: string;
16
+ data?: Record<string, string>;
17
+ }): void;
18
+ };
19
+ export type RuleModule = {
20
+ meta: {
21
+ type: "problem" | "suggestion" | "layout";
22
+ docs: {
23
+ description: string;
24
+ };
25
+ schema: unknown[];
26
+ messages: Record<string, string>;
27
+ };
28
+ create(context: RuleContext): RuleListener;
29
+ };
30
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/rules/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAEnE,MAAM,MAAM,YAAY,GAAG,QAAQ,CAAC,YAAY,GAAG;IACjD,iBAAiB,CAAC,CAAC,IAAI,EAAE,QAAQ,CAAC,iBAAiB,GAAG,IAAI,CAAC;IAC3D,sBAAsB,CAAC,CAAC,IAAI,EAAE,QAAQ,CAAC,sBAAsB,GAAG,IAAI,CAAC;IACrE,oBAAoB,CAAC,CAAC,IAAI,EAAE,QAAQ,CAAC,oBAAoB,GAAG,IAAI,CAAC;IACjE,OAAO,CAAC,CAAC,IAAI,EAAE,QAAQ,CAAC,OAAO,GAAG,IAAI,CAAC;IACvC,cAAc,CAAC,IAAI,IAAI,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,IAAI,MAAM,CAAC;IACtB,OAAO,EAAE,SAAS,OAAO,EAAE,CAAC;IAC5B,MAAM,CAAC,UAAU,EAAE;QACjB,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC;QACpB,SAAS,EAAE,MAAM,CAAC;QAClB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KAC/B,GAAG,IAAI,CAAC;CACV,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS,GAAG,YAAY,GAAG,QAAQ,CAAC;QAC1C,IAAI,EAAE;YAAE,WAAW,EAAE,MAAM,CAAA;SAAE,CAAC;QAC9B,MAAM,EAAE,OAAO,EAAE,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KAClC,CAAC;IACF,MAAM,CAAC,OAAO,EAAE,WAAW,GAAG,YAAY,CAAC;CAC5C,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/rules/types.ts"],"names":[],"mappings":""}
package/docs/hero.png ADDED
Binary file
package/package.json ADDED
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "eslint-plugin-next-edge-boundary",
3
+ "version": "0.1.0",
4
+ "description": "Lint-time import-graph guardrails for Next.js Edge entries — transitive Node denial, byte budgets, and barrel bans.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "engines": {
8
+ "node": ">=20"
9
+ },
10
+ "main": "./dist/index.js",
11
+ "types": "./dist/index.d.ts",
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/index.d.ts",
15
+ "import": "./dist/index.js",
16
+ "default": "./dist/index.js"
17
+ }
18
+ },
19
+ "files": [
20
+ "dist",
21
+ "docs",
22
+ "LICENSE",
23
+ "README.md"
24
+ ],
25
+ "scripts": {
26
+ "build": "tsc -p tsconfig.build.json",
27
+ "typecheck": "tsc -p tsconfig.json --noEmit",
28
+ "test": "pnpm build && vitest run",
29
+ "lint": "eslint ."
30
+ },
31
+ "peerDependencies": {
32
+ "eslint": ">=9",
33
+ "typescript": ">=5"
34
+ },
35
+ "peerDependenciesMeta": {
36
+ "typescript": {
37
+ "optional": true
38
+ }
39
+ },
40
+ "devDependencies": {
41
+ "@types/node": "^22.13.10",
42
+ "@typescript-eslint/parser": "^8.26.1",
43
+ "@typescript-eslint/utils": "^8.26.1",
44
+ "eslint": "^9.22.0",
45
+ "typescript": "^5.8.2",
46
+ "typescript-eslint": "^8.26.1",
47
+ "vitest": "^3.0.8"
48
+ },
49
+ "keywords": [
50
+ "eslint",
51
+ "eslint-plugin",
52
+ "nextjs",
53
+ "edge",
54
+ "middleware",
55
+ "proxy"
56
+ ],
57
+ "repository": {
58
+ "type": "git",
59
+ "url": "git+https://github.com/asyncfinkd/eslint-plugin-next-edge-boundary.git"
60
+ },
61
+ "author": "asyncfinkd",
62
+ "sideEffects": false
63
+ }