@yasainet/eslint 0.0.26 → 0.0.28

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/README.md CHANGED
@@ -65,6 +65,7 @@ export default defineConfig([
65
65
  globalIgnores([
66
66
  // Default ignores of eslint-config-next:
67
67
  ".next/**",
68
+ ".vercel/**",
68
69
  "out/**",
69
70
  "build/**",
70
71
  "next-env.d.ts",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yasainet/eslint",
3
- "version": "0.0.26",
3
+ "version": "0.0.28",
4
4
  "description": "ESLint",
5
5
  "type": "module",
6
6
  "exports": {
@@ -42,15 +42,16 @@ function parseImportSource(importPath, featureRoot) {
42
42
 
43
43
  // Only process paths within the feature root
44
44
  const rootPrefix = featureRoot + "/";
45
- if (!normalized.startsWith(rootPrefix)) return null;
45
+ const rootIdx = normalized.indexOf(rootPrefix);
46
+ if (rootIdx === -1) return null;
46
47
 
47
- const afterRoot = normalized.slice(rootPrefix.length);
48
+ const afterRoot = normalized.slice(rootIdx + rootPrefix.length);
48
49
  // Expected: {feature}/{layerDir}/{scope}.{layerExt}
49
50
  const segments = afterRoot.split("/");
50
51
  if (segments.length < 2) return null;
51
52
 
52
53
  const featureDir = segments[0];
53
- const fileName = segments[segments.length - 1];
54
+ const fileName = segments[segments.length - 1].replace(/\.tsx?$/, "");
54
55
 
55
56
  const dotIdx = fileName.indexOf(".");
56
57
  if (dotIdx === -1) return null;
@@ -69,11 +70,6 @@ function buildExpectedName(featureDir, scope, layer) {
69
70
  const featureCamel = toCamelCase(featureDir);
70
71
  const scopePascal = toPascalCase(scope);
71
72
 
72
- // Dedup: if feature is "shared" or featureName === scope, omit feature prefix
73
- if (featureDir === "shared" || featureCamel === scope) {
74
- return scope + layer;
75
- }
76
-
77
73
  return featureCamel + scopePascal + layer;
78
74
  }
79
75
 
@@ -1,3 +1,5 @@
1
+ import { denoLocalPlugin } from "./local-plugins/index.mjs";
2
+
1
3
  const FUNCTIONS_ROOT = "supabase/functions";
2
4
  const FEATURE_ROOT = "supabase/functions/_features";
3
5
 
@@ -27,8 +29,9 @@ export const denoImportsConfigs = [
27
29
  },
28
30
  },
29
31
  {
30
- name: "deno/commands-entry-point",
31
- files: [`${FUNCTIONS_ROOT}/commands/**/*.ts`],
32
+ name: "deno/entry-point",
33
+ files: [`${FUNCTIONS_ROOT}/**/*.ts`],
34
+ ignores: [`${FUNCTIONS_ROOT}/_*/**`],
32
35
  rules: {
33
36
  "no-restricted-imports": [
34
37
  "error",
@@ -37,21 +40,51 @@ export const denoImportsConfigs = [
37
40
  {
38
41
  group: ["**/services/*", "**/services"],
39
42
  message:
40
- "commands/ must not import services directly. Import from actions instead.",
43
+ "Entry points must not import services directly. Import from actions instead.",
41
44
  },
42
45
  {
43
46
  group: ["**/repositories/*", "**/repositories"],
44
47
  message:
45
- "commands/ must not import repositories directly. Import from actions instead.",
48
+ "Entry points must not import repositories directly. Import from actions instead.",
46
49
  },
47
50
  {
48
51
  group: ["*/_lib/*", "*/_lib/**"],
49
52
  message:
50
- "commands/ must not import _lib/ directly. Import from actions instead.",
53
+ "Entry points must not import _lib/ directly. Import from actions instead.",
51
54
  },
52
55
  ],
53
56
  },
54
57
  ],
55
58
  },
56
59
  },
60
+ {
61
+ name: "deno/utils-boundary",
62
+ files: [`${FUNCTIONS_ROOT}/_utils/**/*.ts`],
63
+ rules: {
64
+ "no-restricted-imports": [
65
+ "error",
66
+ {
67
+ patterns: [
68
+ {
69
+ group: ["*/_features/*", "*/_features/**"],
70
+ message: "_utils/ cannot import _features/",
71
+ },
72
+ {
73
+ group: ["*/_lib/*", "*/_lib/**"],
74
+ message: "_utils/ cannot import _lib/",
75
+ },
76
+ ],
77
+ },
78
+ ],
79
+ },
80
+ },
81
+ {
82
+ name: "deno/flat-entry-point",
83
+ files: [`${FUNCTIONS_ROOT}/**/*.ts`],
84
+ ignores: [`${FUNCTIONS_ROOT}/_*/**`],
85
+ plugins: { "deno-local": denoLocalPlugin },
86
+ rules: {
87
+ "deno-local/flat-entry-point": "error",
88
+ },
89
+ },
57
90
  ];
@@ -0,0 +1,39 @@
1
+ /** Ensure Edge Function entry points are directly under supabase/functions/. */
2
+ export const flatEntryPointRule = {
3
+ meta: {
4
+ type: "problem",
5
+ messages: {
6
+ nested:
7
+ "Edge Function entry points must be directly under supabase/functions/. Nested directories (e.g., commands/{{name}}) are not supported by Supabase CLI.",
8
+ },
9
+ schema: [],
10
+ },
11
+ create(context) {
12
+ return {
13
+ Program(node) {
14
+ const filename = context.filename ?? context.getFilename();
15
+ const idx = filename.indexOf("supabase/functions/");
16
+ if (idx === -1) return;
17
+
18
+ const relative = filename.slice(idx + "supabase/functions/".length);
19
+ const segments = relative.split("/").filter(Boolean);
20
+
21
+ // _prefix directories are shared code, not entry points
22
+ if (segments[0]?.startsWith("_")) return;
23
+
24
+ // Root-level files (deno.json, .env, etc.) are not entry points
25
+ if (segments.length <= 1) return;
26
+
27
+ // Valid: <name>/index.ts (exactly 2 segments)
28
+ // Invalid: <name>/<nested>/index.ts (3+ segments)
29
+ if (segments.length > 2) {
30
+ context.report({
31
+ node,
32
+ messageId: "nested",
33
+ data: { name: segments.slice(0, -1).join("/") },
34
+ });
35
+ }
36
+ },
37
+ };
38
+ },
39
+ };
@@ -0,0 +1,8 @@
1
+ import { flatEntryPointRule } from "./flat-entry-point.mjs";
2
+
3
+ /** Deno-specific local plugin (independent from common localPlugin). */
4
+ export const denoLocalPlugin = {
5
+ rules: {
6
+ "flat-entry-point": flatEntryPointRule,
7
+ },
8
+ };