pasika 0.7.7 → 0.8.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/dist/eslint/pasika/index.d.ts +3 -0
- package/dist/eslint/pasika/index.js +279 -119
- package/package.json +1 -1
|
@@ -199,11 +199,14 @@ declare const pasikaPlugin: {
|
|
|
199
199
|
"enforce-barrel-exports": eslint.Rule.RuleModule;
|
|
200
200
|
"config-extraction": eslint.Rule.RuleModule;
|
|
201
201
|
"value-extraction": eslint.Rule.RuleModule;
|
|
202
|
+
"constant-casing": eslint.Rule.RuleModule;
|
|
202
203
|
"type-extraction": eslint.Rule.RuleModule;
|
|
203
204
|
"zod-schema-validation": eslint.Rule.RuleModule;
|
|
205
|
+
"schema-casing": eslint.Rule.RuleModule;
|
|
204
206
|
"source-under-src": eslint.Rule.RuleModule;
|
|
205
207
|
"zirka-baseline": eslint.Rule.RuleModule;
|
|
206
208
|
"component-placement": eslint.Rule.RuleModule;
|
|
209
|
+
"component-casing": eslint.Rule.RuleModule;
|
|
207
210
|
"application-structure": eslint.Rule.RuleModule;
|
|
208
211
|
"data-testid-case": eslint.Rule.RuleModule;
|
|
209
212
|
"jsx-hygiene": eslint.Rule.RuleModule;
|
|
@@ -137,6 +137,30 @@ function parseComponentInfo(text, filename, options) {
|
|
|
137
137
|
}
|
|
138
138
|
return components;
|
|
139
139
|
}
|
|
140
|
+
function findJsxReturningDeclarations(text, filename) {
|
|
141
|
+
const sourceFile = ts.createSourceFile(path.resolve(filename), text, ts.ScriptTarget.Latest, true, ts.ScriptKind.TSX);
|
|
142
|
+
const results = [];
|
|
143
|
+
const record = (identifier, body) => {
|
|
144
|
+
if (isHookCallName(identifier.text) || !containsJsx(body)) return;
|
|
145
|
+
const { line, character } = sourceFile.getLineAndCharacterOfPosition(identifier.getStart(sourceFile));
|
|
146
|
+
results.push({ name: identifier.text, line: line + 1, column: character });
|
|
147
|
+
};
|
|
148
|
+
for (const statement of sourceFile.statements) {
|
|
149
|
+
if (ts.isFunctionDeclaration(statement) && statement.name) {
|
|
150
|
+
record(statement.name, statement);
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
if (ts.isVariableStatement(statement)) {
|
|
154
|
+
for (const declaration of statement.declarationList.declarations) {
|
|
155
|
+
if (!ts.isIdentifier(declaration.name)) continue;
|
|
156
|
+
const initializer = declaration.initializer;
|
|
157
|
+
if (!initializer || !ts.isArrowFunction(initializer) && !ts.isFunctionExpression(initializer)) continue;
|
|
158
|
+
record(declaration.name, initializer);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return results;
|
|
163
|
+
}
|
|
140
164
|
function jsxTagName(element) {
|
|
141
165
|
const tagName2 = ts.isJsxElement(element) ? element.openingElement.tagName : element.tagName;
|
|
142
166
|
return ts.isIdentifier(tagName2) ? tagName2.text : void 0;
|
|
@@ -2108,8 +2132,46 @@ var supportFolderShapeRule = {
|
|
|
2108
2132
|
}
|
|
2109
2133
|
};
|
|
2110
2134
|
|
|
2111
|
-
// eslint/rules/
|
|
2135
|
+
// eslint/rules/constant-casing.ts
|
|
2112
2136
|
import path17 from "path";
|
|
2137
|
+
var NEXTJS_ROUTE_HANDLER_NAMES = /* @__PURE__ */ new Set(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"]);
|
|
2138
|
+
function isScreamingSnakeCase(name) {
|
|
2139
|
+
return /^[A-Z][A-Z0-9]*(?:_[A-Z0-9]+)*$/.test(name);
|
|
2140
|
+
}
|
|
2141
|
+
var constantCasingRule = {
|
|
2142
|
+
meta: {
|
|
2143
|
+
schema: [],
|
|
2144
|
+
type: "problem",
|
|
2145
|
+
docs: {
|
|
2146
|
+
description: "Require a module-level constant to be camelCase, unless a framework requires a specific name."
|
|
2147
|
+
}
|
|
2148
|
+
},
|
|
2149
|
+
create(context) {
|
|
2150
|
+
const filename = path17.resolve(context.filename);
|
|
2151
|
+
const sourceRoot = sourceRootOf(context);
|
|
2152
|
+
if (!filename.startsWith(sourceRoot + path17.sep)) return {};
|
|
2153
|
+
return {
|
|
2154
|
+
VariableDeclarator(node) {
|
|
2155
|
+
if (node.id.type !== "Identifier") return;
|
|
2156
|
+
const declaration = node.parent;
|
|
2157
|
+
if (declaration.type !== "VariableDeclaration" || declaration.kind !== "const") return;
|
|
2158
|
+
const container = declaration.parent;
|
|
2159
|
+
const isModuleLevel = container.type === "Program" || container.type === "ExportNamedDeclaration" && container.parent.type === "Program";
|
|
2160
|
+
if (!isModuleLevel) return;
|
|
2161
|
+
const { name } = node.id;
|
|
2162
|
+
if (!isScreamingSnakeCase(name)) return;
|
|
2163
|
+
if (NEXTJS_ROUTE_HANDLER_NAMES.has(name)) return;
|
|
2164
|
+
context.report({
|
|
2165
|
+
node,
|
|
2166
|
+
message: `${name} must be camelCase, unless a framework requires this exact name. See docs/next-codebase-guide/rules/constants-rule.md`
|
|
2167
|
+
});
|
|
2168
|
+
}
|
|
2169
|
+
};
|
|
2170
|
+
}
|
|
2171
|
+
};
|
|
2172
|
+
|
|
2173
|
+
// eslint/rules/import-through-index.ts
|
|
2174
|
+
import path18 from "path";
|
|
2113
2175
|
var importThroughIndexRule = {
|
|
2114
2176
|
meta: {
|
|
2115
2177
|
schema: [],
|
|
@@ -2119,7 +2181,7 @@ var importThroughIndexRule = {
|
|
|
2119
2181
|
}
|
|
2120
2182
|
},
|
|
2121
2183
|
create(context) {
|
|
2122
|
-
const filename =
|
|
2184
|
+
const filename = path18.resolve(context.filename);
|
|
2123
2185
|
const sourceRoot = sourceRootOf2(context, filename);
|
|
2124
2186
|
return {
|
|
2125
2187
|
Program(node) {
|
|
@@ -2131,7 +2193,7 @@ var importThroughIndexRule = {
|
|
|
2131
2193
|
(segment) => ["constants", "types", "schemas"].includes(segment)
|
|
2132
2194
|
);
|
|
2133
2195
|
const supportFolder = supportFolderIndex >= 0 ? targetSegments[supportFolderIndex] : void 0;
|
|
2134
|
-
if (!supportFolder ||
|
|
2196
|
+
if (!supportFolder || path18.basename(target).startsWith("index.")) continue;
|
|
2135
2197
|
const folderIndex = targetSegments.slice(0, supportFolderIndex + 1);
|
|
2136
2198
|
const expected = `@/${folderIndex.join("/")}`;
|
|
2137
2199
|
context.report({
|
|
@@ -2153,14 +2215,14 @@ function importSpecifiers(source) {
|
|
|
2153
2215
|
return specifiers;
|
|
2154
2216
|
}
|
|
2155
2217
|
function sourceRootOf2(context, filename) {
|
|
2156
|
-
const marker = `${
|
|
2218
|
+
const marker = `${path18.sep}src${path18.sep}`;
|
|
2157
2219
|
const srcIndex = filename.lastIndexOf(marker);
|
|
2158
2220
|
if (srcIndex >= 0) return filename.slice(0, srcIndex + marker.length - 1);
|
|
2159
|
-
return
|
|
2221
|
+
return path18.resolve(context.cwd ?? process.cwd(), "src");
|
|
2160
2222
|
}
|
|
2161
2223
|
|
|
2162
2224
|
// eslint/rules/util-file-name.ts
|
|
2163
|
-
import
|
|
2225
|
+
import path19 from "path";
|
|
2164
2226
|
function toKebabCase2(value) {
|
|
2165
2227
|
return value.replace(/(?<lower>[a-z0-9])(?<upper>[A-Z])/g, "$<lower>-$<upper>").replace(/(?<first>[A-Z])(?<rest>[A-Z][a-z])/g, "$<first>-$<rest>").toLowerCase();
|
|
2166
2228
|
}
|
|
@@ -2173,7 +2235,7 @@ var utilFileNameRule = {
|
|
|
2173
2235
|
}
|
|
2174
2236
|
},
|
|
2175
2237
|
create(context) {
|
|
2176
|
-
const filename =
|
|
2238
|
+
const filename = path19.resolve(context.filename);
|
|
2177
2239
|
const segments = filename.replace(/\\/g, "/").split("/");
|
|
2178
2240
|
if (!segments.includes("utils")) return {};
|
|
2179
2241
|
let module;
|
|
@@ -2187,13 +2249,13 @@ var utilFileNameRule = {
|
|
|
2187
2249
|
const functionName = functions[0]?.name;
|
|
2188
2250
|
if (!functionName) return {};
|
|
2189
2251
|
const expected = toKebabCase2(functionName);
|
|
2190
|
-
const actual =
|
|
2252
|
+
const actual = path19.basename(filename, path19.extname(filename));
|
|
2191
2253
|
if (!expected || actual === expected) return {};
|
|
2192
2254
|
return {
|
|
2193
2255
|
Program(node) {
|
|
2194
2256
|
context.report({
|
|
2195
2257
|
node,
|
|
2196
|
-
message: `A utility file exporting ${functionName} must be named ${expected}.${
|
|
2258
|
+
message: `A utility file exporting ${functionName} must be named ${expected}.${path19.extname(filename).slice(1)}.`
|
|
2197
2259
|
});
|
|
2198
2260
|
}
|
|
2199
2261
|
};
|
|
@@ -2201,7 +2263,7 @@ var utilFileNameRule = {
|
|
|
2201
2263
|
};
|
|
2202
2264
|
|
|
2203
2265
|
// eslint/rules/no-util-barrel.ts
|
|
2204
|
-
import
|
|
2266
|
+
import path20 from "path";
|
|
2205
2267
|
var noUtilBarrelRule = {
|
|
2206
2268
|
meta: {
|
|
2207
2269
|
schema: [],
|
|
@@ -2211,7 +2273,7 @@ var noUtilBarrelRule = {
|
|
|
2211
2273
|
}
|
|
2212
2274
|
},
|
|
2213
2275
|
create(context) {
|
|
2214
|
-
const filename =
|
|
2276
|
+
const filename = path20.resolve(context.filename);
|
|
2215
2277
|
const sourceRoot = sourceRootOf3(context, filename);
|
|
2216
2278
|
return {
|
|
2217
2279
|
Program(node) {
|
|
@@ -2220,7 +2282,7 @@ var noUtilBarrelRule = {
|
|
|
2220
2282
|
if (!target) continue;
|
|
2221
2283
|
const segments = target.replace(/\\/g, "/").split("/");
|
|
2222
2284
|
const utilsIndex = segments.lastIndexOf("utils");
|
|
2223
|
-
if (utilsIndex < 0 || !
|
|
2285
|
+
if (utilsIndex < 0 || !path20.basename(target).startsWith("index.")) continue;
|
|
2224
2286
|
context.report({
|
|
2225
2287
|
node,
|
|
2226
2288
|
message: `Import utilities directly instead of through "${specifier}". See docs/next-codebase-guide/rules/utilities-rule.md`
|
|
@@ -2240,10 +2302,10 @@ function importSpecifiers2(source) {
|
|
|
2240
2302
|
return specifiers;
|
|
2241
2303
|
}
|
|
2242
2304
|
function sourceRootOf3(context, filename) {
|
|
2243
|
-
const marker = `${
|
|
2305
|
+
const marker = `${path20.sep}src${path20.sep}`;
|
|
2244
2306
|
const srcIndex = filename.lastIndexOf(marker);
|
|
2245
2307
|
if (srcIndex >= 0) return filename.slice(0, srcIndex + marker.length - 1);
|
|
2246
|
-
return
|
|
2308
|
+
return path20.resolve(context.cwd ?? process.cwd(), "src");
|
|
2247
2309
|
}
|
|
2248
2310
|
|
|
2249
2311
|
// eslint/rules/jsx-hygiene.ts
|
|
@@ -2336,7 +2398,7 @@ var jsxHygieneRule = {
|
|
|
2336
2398
|
};
|
|
2337
2399
|
|
|
2338
2400
|
// eslint/rules/interactive-component.ts
|
|
2339
|
-
import
|
|
2401
|
+
import path21 from "path";
|
|
2340
2402
|
var INTERACTIVE_TAGS = /* @__PURE__ */ new Set([
|
|
2341
2403
|
"a",
|
|
2342
2404
|
"button",
|
|
@@ -2491,8 +2553,8 @@ var interactiveComponentRule = {
|
|
|
2491
2553
|
},
|
|
2492
2554
|
create(context) {
|
|
2493
2555
|
if (!context.filename.endsWith(".tsx") && !context.filename.endsWith(".jsx")) return {};
|
|
2494
|
-
const filename =
|
|
2495
|
-
const base =
|
|
2556
|
+
const filename = path21.resolve(context.filename);
|
|
2557
|
+
const base = path21.basename(filename, path21.extname(filename));
|
|
2496
2558
|
if (NEXT_ROUTING_FILES3.has(base)) return {};
|
|
2497
2559
|
return {
|
|
2498
2560
|
JSXElement(node) {
|
|
@@ -2743,12 +2805,12 @@ var cvaBooleanVariantsRule = {
|
|
|
2743
2805
|
};
|
|
2744
2806
|
|
|
2745
2807
|
// eslint/rules/cross-feature-import.ts
|
|
2746
|
-
import
|
|
2808
|
+
import path22 from "path";
|
|
2747
2809
|
var FEATURES_SEGMENT = "features";
|
|
2748
2810
|
function featureNameOf(resolvedPath, sourceRoot) {
|
|
2749
|
-
const relative =
|
|
2811
|
+
const relative = path22.relative(sourceRoot, resolvedPath);
|
|
2750
2812
|
if (relative.startsWith("..")) return void 0;
|
|
2751
|
-
const segments = relative.split(
|
|
2813
|
+
const segments = relative.split(path22.sep);
|
|
2752
2814
|
if (segments[0] !== FEATURES_SEGMENT || segments.length < 2) return void 0;
|
|
2753
2815
|
return segments[1];
|
|
2754
2816
|
}
|
|
@@ -2764,9 +2826,9 @@ var crossFeatureImportRule = {
|
|
|
2764
2826
|
const filename = context.filename;
|
|
2765
2827
|
if (!filename.endsWith(".tsx") && !filename.endsWith(".jsx")) return {};
|
|
2766
2828
|
const sourceRoot = sourceRootOf(context);
|
|
2767
|
-
const fileRelative =
|
|
2829
|
+
const fileRelative = path22.relative(sourceRoot, filename);
|
|
2768
2830
|
if (fileRelative.startsWith("..")) return {};
|
|
2769
|
-
const fileSegments = fileRelative.split(
|
|
2831
|
+
const fileSegments = fileRelative.split(path22.sep);
|
|
2770
2832
|
const isInCompositions = fileSegments[0] === "compositions";
|
|
2771
2833
|
const isInApp = fileSegments[0] === "app";
|
|
2772
2834
|
const isConfig = fileSegments[0] === "config";
|
|
@@ -2780,9 +2842,9 @@ var crossFeatureImportRule = {
|
|
|
2780
2842
|
if (typeof source.value !== "string") return;
|
|
2781
2843
|
let resolved;
|
|
2782
2844
|
if (source.value.startsWith("@/")) {
|
|
2783
|
-
resolved =
|
|
2845
|
+
resolved = path22.resolve(sourceRoot, source.value.slice(2));
|
|
2784
2846
|
} else if (source.value.startsWith(".")) {
|
|
2785
|
-
resolved =
|
|
2847
|
+
resolved = path22.resolve(path22.dirname(filename), source.value);
|
|
2786
2848
|
}
|
|
2787
2849
|
if (!resolved) return;
|
|
2788
2850
|
const feature = featureNameOf(resolved, sourceRoot);
|
|
@@ -2801,7 +2863,7 @@ var crossFeatureImportRule = {
|
|
|
2801
2863
|
};
|
|
2802
2864
|
|
|
2803
2865
|
// eslint/rules/pure-function-extract.ts
|
|
2804
|
-
import
|
|
2866
|
+
import path23 from "path";
|
|
2805
2867
|
function isComponentLikeName(name) {
|
|
2806
2868
|
return /^[A-Z]/.test(name);
|
|
2807
2869
|
}
|
|
@@ -2830,9 +2892,9 @@ var pureFunctionExtractRule = {
|
|
|
2830
2892
|
const filename = context.filename;
|
|
2831
2893
|
if (!filename.endsWith(".tsx") && !filename.endsWith(".jsx")) return {};
|
|
2832
2894
|
const sourceRoot = sourceRootOf(context);
|
|
2833
|
-
const relative =
|
|
2895
|
+
const relative = path23.relative(sourceRoot, filename);
|
|
2834
2896
|
if (relative.startsWith("..")) return {};
|
|
2835
|
-
const segments = relative.split(
|
|
2897
|
+
const segments = relative.split(path23.sep);
|
|
2836
2898
|
if (segments[0] === "utils") return {};
|
|
2837
2899
|
if (segments[0] === "app") return {};
|
|
2838
2900
|
const supportFolders = /* @__PURE__ */ new Set(["hooks", "types", "schemas", "constants", "utils"]);
|
|
@@ -2872,7 +2934,7 @@ var pureFunctionExtractRule = {
|
|
|
2872
2934
|
};
|
|
2873
2935
|
|
|
2874
2936
|
// eslint/rules/hook-complexity.ts
|
|
2875
|
-
import
|
|
2937
|
+
import path24 from "path";
|
|
2876
2938
|
import ts4 from "typescript";
|
|
2877
2939
|
var REACT_HOOKS = /* @__PURE__ */ new Set([
|
|
2878
2940
|
"useState",
|
|
@@ -2925,9 +2987,9 @@ var hookComplexityRule = {
|
|
|
2925
2987
|
create(context) {
|
|
2926
2988
|
const filename = context.filename;
|
|
2927
2989
|
const sourceRoot = sourceRootOf(context);
|
|
2928
|
-
const relative =
|
|
2990
|
+
const relative = path24.relative(sourceRoot, filename);
|
|
2929
2991
|
if (relative.startsWith("..")) return {};
|
|
2930
|
-
const segments = relative.split(
|
|
2992
|
+
const segments = relative.split(path24.sep);
|
|
2931
2993
|
const sourceText = context.sourceCode.text;
|
|
2932
2994
|
function checkHook(node, name, body, exported) {
|
|
2933
2995
|
if (!exported) return;
|
|
@@ -2969,9 +3031,9 @@ var hookComplexityRule = {
|
|
|
2969
3031
|
};
|
|
2970
3032
|
|
|
2971
3033
|
// eslint/rules/locale-dotted-path.ts
|
|
2972
|
-
import
|
|
3034
|
+
import path25 from "path";
|
|
2973
3035
|
function isInLocalesDir(filename) {
|
|
2974
|
-
const segments =
|
|
3036
|
+
const segments = path25.resolve(filename).split(path25.sep);
|
|
2975
3037
|
const srcIdx = segments.lastIndexOf("src");
|
|
2976
3038
|
return srcIdx !== -1 && segments[srcIdx + 1] === "locales";
|
|
2977
3039
|
}
|
|
@@ -3020,9 +3082,9 @@ var localeDottedPathRule = {
|
|
|
3020
3082
|
};
|
|
3021
3083
|
|
|
3022
3084
|
// eslint/rules/locales-location.ts
|
|
3023
|
-
import
|
|
3085
|
+
import path26 from "path";
|
|
3024
3086
|
function isLocalesFile(filename) {
|
|
3025
|
-
const segments =
|
|
3087
|
+
const segments = path26.resolve(filename).split(path26.sep);
|
|
3026
3088
|
const srcIdx = segments.lastIndexOf("src");
|
|
3027
3089
|
return srcIdx !== -1 && segments[srcIdx + 1] === "locales";
|
|
3028
3090
|
}
|
|
@@ -3041,7 +3103,7 @@ var localesLocationRule = {
|
|
|
3041
3103
|
create(context) {
|
|
3042
3104
|
if (isLocalesFile(context.filename)) return {};
|
|
3043
3105
|
const filename = context.filename;
|
|
3044
|
-
const segments =
|
|
3106
|
+
const segments = path26.resolve(filename).split(path26.sep);
|
|
3045
3107
|
const srcIdx = segments.lastIndexOf("src");
|
|
3046
3108
|
if (srcIdx === -1) return {};
|
|
3047
3109
|
const folder = segments[srcIdx + 1];
|
|
@@ -3063,7 +3125,7 @@ var localesLocationRule = {
|
|
|
3063
3125
|
};
|
|
3064
3126
|
|
|
3065
3127
|
// eslint/rules/hook-extraction.ts
|
|
3066
|
-
import
|
|
3128
|
+
import path27 from "path";
|
|
3067
3129
|
var hookExtractionRule = {
|
|
3068
3130
|
meta: {
|
|
3069
3131
|
schema: [],
|
|
@@ -3074,7 +3136,7 @@ var hookExtractionRule = {
|
|
|
3074
3136
|
},
|
|
3075
3137
|
create(context) {
|
|
3076
3138
|
const sourceRoot = sourceRootOf(context);
|
|
3077
|
-
const file =
|
|
3139
|
+
const file = path27.resolve(context.filename);
|
|
3078
3140
|
const segments = segmentsOf(file, sourceRoot);
|
|
3079
3141
|
if (segments.length === 0) return {};
|
|
3080
3142
|
const index = getProjectIndex(sourceRoot);
|
|
@@ -3100,7 +3162,7 @@ var hookExtractionRule = {
|
|
|
3100
3162
|
};
|
|
3101
3163
|
|
|
3102
3164
|
// eslint/rules/value-extraction.ts
|
|
3103
|
-
import
|
|
3165
|
+
import path28 from "path";
|
|
3104
3166
|
var valueExtractionRule = {
|
|
3105
3167
|
meta: {
|
|
3106
3168
|
schema: [],
|
|
@@ -3111,7 +3173,7 @@ var valueExtractionRule = {
|
|
|
3111
3173
|
},
|
|
3112
3174
|
create(context) {
|
|
3113
3175
|
const sourceRoot = sourceRootOf(context);
|
|
3114
|
-
const file =
|
|
3176
|
+
const file = path28.resolve(context.filename);
|
|
3115
3177
|
const segments = segmentsOf(file, sourceRoot);
|
|
3116
3178
|
if (segments.length === 0 || segments[0] !== "app") return {};
|
|
3117
3179
|
const index = getProjectIndex(sourceRoot);
|
|
@@ -3132,7 +3194,7 @@ var valueExtractionRule = {
|
|
|
3132
3194
|
};
|
|
3133
3195
|
|
|
3134
3196
|
// eslint/rules/config-extraction.ts
|
|
3135
|
-
import
|
|
3197
|
+
import path29 from "path";
|
|
3136
3198
|
var configExtractionRule = {
|
|
3137
3199
|
meta: {
|
|
3138
3200
|
schema: [],
|
|
@@ -3143,7 +3205,7 @@ var configExtractionRule = {
|
|
|
3143
3205
|
},
|
|
3144
3206
|
create(context) {
|
|
3145
3207
|
const sourceRoot = sourceRootOf(context);
|
|
3146
|
-
const file =
|
|
3208
|
+
const file = path29.resolve(context.filename);
|
|
3147
3209
|
const segments = segmentsOf(file, sourceRoot);
|
|
3148
3210
|
if (segments.length < 3 || segments[0] !== "config") return {};
|
|
3149
3211
|
if (SUPPORT_FOLDERS2.has(segments[2] ?? "")) return {};
|
|
@@ -3181,7 +3243,7 @@ var configExtractionRule = {
|
|
|
3181
3243
|
};
|
|
3182
3244
|
|
|
3183
3245
|
// eslint/rules/component-nesting.ts
|
|
3184
|
-
import
|
|
3246
|
+
import path30 from "path";
|
|
3185
3247
|
var componentNestingRule = {
|
|
3186
3248
|
meta: {
|
|
3187
3249
|
schema: [],
|
|
@@ -3192,7 +3254,7 @@ var componentNestingRule = {
|
|
|
3192
3254
|
},
|
|
3193
3255
|
create(context) {
|
|
3194
3256
|
const sourceRoot = sourceRootOf(context);
|
|
3195
|
-
const file =
|
|
3257
|
+
const file = path30.resolve(context.filename);
|
|
3196
3258
|
const segments = segmentsOf(file, sourceRoot);
|
|
3197
3259
|
if (segments.length !== 4 || segments[0] !== "features") return {};
|
|
3198
3260
|
const index = getProjectIndex(sourceRoot);
|
|
@@ -3225,7 +3287,7 @@ var componentNestingRule = {
|
|
|
3225
3287
|
};
|
|
3226
3288
|
|
|
3227
3289
|
// eslint/rules/stay-flat.ts
|
|
3228
|
-
import
|
|
3290
|
+
import path31 from "path";
|
|
3229
3291
|
var stayFlatRule = {
|
|
3230
3292
|
meta: {
|
|
3231
3293
|
schema: [],
|
|
@@ -3236,7 +3298,7 @@ var stayFlatRule = {
|
|
|
3236
3298
|
},
|
|
3237
3299
|
create(context) {
|
|
3238
3300
|
const sourceRoot = sourceRootOf(context);
|
|
3239
|
-
const file =
|
|
3301
|
+
const file = path31.resolve(context.filename);
|
|
3240
3302
|
const segments = segmentsOf(file, sourceRoot);
|
|
3241
3303
|
if (segments.length !== 3 || segments[0] !== "features") return {};
|
|
3242
3304
|
const index = getProjectIndex(sourceRoot);
|
|
@@ -3276,7 +3338,7 @@ var stayFlatRule = {
|
|
|
3276
3338
|
};
|
|
3277
3339
|
|
|
3278
3340
|
// eslint/rules/type-extraction.ts
|
|
3279
|
-
import
|
|
3341
|
+
import path32 from "path";
|
|
3280
3342
|
var typeExtractionRule = {
|
|
3281
3343
|
meta: {
|
|
3282
3344
|
schema: [],
|
|
@@ -3287,7 +3349,7 @@ var typeExtractionRule = {
|
|
|
3287
3349
|
},
|
|
3288
3350
|
create(context) {
|
|
3289
3351
|
const sourceRoot = sourceRootOf(context);
|
|
3290
|
-
const file =
|
|
3352
|
+
const file = path32.resolve(context.filename);
|
|
3291
3353
|
const segments = segmentsOf(file, sourceRoot);
|
|
3292
3354
|
if (segments.length === 0) return {};
|
|
3293
3355
|
const index = getProjectIndex(sourceRoot);
|
|
@@ -3333,7 +3395,7 @@ var typeExtractionRule = {
|
|
|
3333
3395
|
};
|
|
3334
3396
|
|
|
3335
3397
|
// eslint/rules/locale-placement.ts
|
|
3336
|
-
import
|
|
3398
|
+
import path33 from "path";
|
|
3337
3399
|
import { readFileSync as readFileSync4 } from "fs";
|
|
3338
3400
|
import ts5 from "typescript";
|
|
3339
3401
|
var LOCALE_ACCESS = /\blocales\.(?<key>[A-Za-z_$][\w$]*)/g;
|
|
@@ -3381,7 +3443,7 @@ var localePlacementRule = {
|
|
|
3381
3443
|
},
|
|
3382
3444
|
create(context) {
|
|
3383
3445
|
const sourceRoot = sourceRootOf(context);
|
|
3384
|
-
const file =
|
|
3446
|
+
const file = path33.resolve(context.filename);
|
|
3385
3447
|
const segments = segmentsOf(file, sourceRoot);
|
|
3386
3448
|
if (segments.length === 0) return {};
|
|
3387
3449
|
const index = getProjectIndex(sourceRoot);
|
|
@@ -3459,7 +3521,7 @@ var localePlacementRule = {
|
|
|
3459
3521
|
};
|
|
3460
3522
|
|
|
3461
3523
|
// eslint/rules/sole-state-owner.ts
|
|
3462
|
-
import
|
|
3524
|
+
import path34 from "path";
|
|
3463
3525
|
import ts6 from "typescript";
|
|
3464
3526
|
function findStateHooks(node) {
|
|
3465
3527
|
const hooks = [];
|
|
@@ -3539,7 +3601,7 @@ var soleStateOwnerRule = {
|
|
|
3539
3601
|
}
|
|
3540
3602
|
},
|
|
3541
3603
|
create(context) {
|
|
3542
|
-
const filename =
|
|
3604
|
+
const filename = path34.resolve(context.filename);
|
|
3543
3605
|
if (!filename.endsWith(".tsx") && !filename.endsWith(".jsx")) return {};
|
|
3544
3606
|
const text = context.sourceCode.text;
|
|
3545
3607
|
const components = parseComponentInfo(text, filename);
|
|
@@ -3618,7 +3680,7 @@ function usesOutsideJsx(declaration, hook, children) {
|
|
|
3618
3680
|
}
|
|
3619
3681
|
|
|
3620
3682
|
// eslint/rules/locale-key-shape.ts
|
|
3621
|
-
import
|
|
3683
|
+
import path35 from "path";
|
|
3622
3684
|
var MAX_KEY_LENGTH = 30;
|
|
3623
3685
|
var ROLE_POSTFIXES = /* @__PURE__ */ new Set([
|
|
3624
3686
|
"Button",
|
|
@@ -3668,7 +3730,7 @@ var ROLE_POSTFIXES = /* @__PURE__ */ new Set([
|
|
|
3668
3730
|
var CAMEL_CASE = /^[a-z][a-zA-Z0-9]*$/;
|
|
3669
3731
|
var ENGLISH = /^[A-Za-z0-9_]*$/;
|
|
3670
3732
|
function isLocalesFile2(filename) {
|
|
3671
|
-
const segments =
|
|
3733
|
+
const segments = path35.resolve(filename).split(path35.sep);
|
|
3672
3734
|
const srcIdx = segments.lastIndexOf("src");
|
|
3673
3735
|
return srcIdx !== -1 && segments[srcIdx + 1] === "locales";
|
|
3674
3736
|
}
|
|
@@ -3739,7 +3801,7 @@ var localeKeyShapeRule = {
|
|
|
3739
3801
|
};
|
|
3740
3802
|
|
|
3741
3803
|
// eslint/rules/shared-style-dedup.ts
|
|
3742
|
-
import
|
|
3804
|
+
import path36 from "path";
|
|
3743
3805
|
import { readFileSync as readFileSync5, statSync as statSync3 } from "fs";
|
|
3744
3806
|
var CLASS_NAME = /className="(?<classes>[^"]+)"/g;
|
|
3745
3807
|
var comboCache;
|
|
@@ -3777,7 +3839,7 @@ var sharedStyleDedupRule = {
|
|
|
3777
3839
|
},
|
|
3778
3840
|
create(context) {
|
|
3779
3841
|
const sourceRoot = sourceRootOf(context);
|
|
3780
|
-
const file =
|
|
3842
|
+
const file = path36.resolve(context.filename);
|
|
3781
3843
|
const segments = segmentsOf(file, sourceRoot);
|
|
3782
3844
|
if (segments.length === 0) return {};
|
|
3783
3845
|
const index = getProjectIndex(sourceRoot);
|
|
@@ -3980,8 +4042,103 @@ var zodSchemaValidationRule = {
|
|
|
3980
4042
|
}
|
|
3981
4043
|
};
|
|
3982
4044
|
|
|
4045
|
+
// eslint/rules/schema-casing.ts
|
|
4046
|
+
import path37 from "path";
|
|
4047
|
+
function isCamelCase(name) {
|
|
4048
|
+
return /^[a-z][a-zA-Z0-9]*$/.test(name);
|
|
4049
|
+
}
|
|
4050
|
+
function rootIdentifierName(node) {
|
|
4051
|
+
let current = node;
|
|
4052
|
+
for (; ; ) {
|
|
4053
|
+
if (current.type === "Identifier") return current.name;
|
|
4054
|
+
if (current.type === "CallExpression") {
|
|
4055
|
+
current = current.callee;
|
|
4056
|
+
continue;
|
|
4057
|
+
}
|
|
4058
|
+
if (current.type === "MemberExpression") {
|
|
4059
|
+
current = current.object;
|
|
4060
|
+
continue;
|
|
4061
|
+
}
|
|
4062
|
+
return void 0;
|
|
4063
|
+
}
|
|
4064
|
+
}
|
|
4065
|
+
var schemaCasingRule = {
|
|
4066
|
+
meta: {
|
|
4067
|
+
schema: [],
|
|
4068
|
+
type: "problem",
|
|
4069
|
+
docs: {
|
|
4070
|
+
description: "Require a Zod schema constant to be named in camelCase."
|
|
4071
|
+
}
|
|
4072
|
+
},
|
|
4073
|
+
create(context) {
|
|
4074
|
+
const filename = path37.resolve(context.filename);
|
|
4075
|
+
const sourceRoot = sourceRootOf(context);
|
|
4076
|
+
if (!filename.startsWith(sourceRoot + path37.sep)) return {};
|
|
4077
|
+
let zodLocalName;
|
|
4078
|
+
return {
|
|
4079
|
+
ImportDeclaration(node) {
|
|
4080
|
+
if (node.source.value !== "zod") return;
|
|
4081
|
+
for (const specifier of node.specifiers) {
|
|
4082
|
+
if (specifier.type === "ImportSpecifier" && specifier.imported.type === "Identifier" && specifier.imported.name === "z") {
|
|
4083
|
+
zodLocalName = specifier.local.name;
|
|
4084
|
+
}
|
|
4085
|
+
}
|
|
4086
|
+
},
|
|
4087
|
+
VariableDeclarator(node) {
|
|
4088
|
+
if (!zodLocalName) return;
|
|
4089
|
+
if (node.id.type !== "Identifier") return;
|
|
4090
|
+
const declaration = node.parent;
|
|
4091
|
+
if (declaration.type !== "VariableDeclaration" || declaration.kind !== "const") return;
|
|
4092
|
+
const container = declaration.parent;
|
|
4093
|
+
const isModuleLevel = container.type === "Program" || container.type === "ExportNamedDeclaration" && container.parent.type === "Program";
|
|
4094
|
+
if (!isModuleLevel) return;
|
|
4095
|
+
if (!node.init || rootIdentifierName(node.init) !== zodLocalName) return;
|
|
4096
|
+
const { name } = node.id;
|
|
4097
|
+
if (isCamelCase(name)) return;
|
|
4098
|
+
context.report({
|
|
4099
|
+
node,
|
|
4100
|
+
message: `${name} must be camelCase. See docs/next-codebase-guide/rules/types-and-schemas-rule.md`
|
|
4101
|
+
});
|
|
4102
|
+
}
|
|
4103
|
+
};
|
|
4104
|
+
}
|
|
4105
|
+
};
|
|
4106
|
+
|
|
4107
|
+
// eslint/rules/component-casing.ts
|
|
4108
|
+
import path38 from "path";
|
|
4109
|
+
function isPascalCase6(name) {
|
|
4110
|
+
return /^[A-Z][A-Za-z0-9]*$/.test(name);
|
|
4111
|
+
}
|
|
4112
|
+
var componentCasingRule = {
|
|
4113
|
+
meta: {
|
|
4114
|
+
schema: [],
|
|
4115
|
+
type: "problem",
|
|
4116
|
+
docs: {
|
|
4117
|
+
description: "Require a JSX-returning function or const to be named in PascalCase."
|
|
4118
|
+
}
|
|
4119
|
+
},
|
|
4120
|
+
create(context) {
|
|
4121
|
+
const filename = path38.resolve(context.filename);
|
|
4122
|
+
const sourceRoot = sourceRootOf(context);
|
|
4123
|
+
if (!filename.startsWith(sourceRoot + path38.sep)) return {};
|
|
4124
|
+
if (path38.extname(filename) !== ".tsx") return {};
|
|
4125
|
+
return {
|
|
4126
|
+
Program(node) {
|
|
4127
|
+
for (const declaration of findJsxReturningDeclarations(context.sourceCode.text, filename)) {
|
|
4128
|
+
if (isPascalCase6(declaration.name)) continue;
|
|
4129
|
+
context.report({
|
|
4130
|
+
node,
|
|
4131
|
+
loc: { line: declaration.line, column: declaration.column },
|
|
4132
|
+
message: `${declaration.name} must be PascalCase; only a PascalCase name resolves as a JSX component. See docs/next-codebase-guide/rules/smart-vs-dumb-component-rule.md`
|
|
4133
|
+
});
|
|
4134
|
+
}
|
|
4135
|
+
}
|
|
4136
|
+
};
|
|
4137
|
+
}
|
|
4138
|
+
};
|
|
4139
|
+
|
|
3983
4140
|
// eslint/rules/source-under-src.ts
|
|
3984
|
-
import
|
|
4141
|
+
import path39 from "path";
|
|
3985
4142
|
var NON_SOURCE_ROOT_DIRS = /* @__PURE__ */ new Set([
|
|
3986
4143
|
".agents",
|
|
3987
4144
|
".cache",
|
|
@@ -4022,14 +4179,14 @@ var sourceUnderSrcRule = {
|
|
|
4022
4179
|
}
|
|
4023
4180
|
},
|
|
4024
4181
|
create(context) {
|
|
4025
|
-
const filename =
|
|
4182
|
+
const filename = path39.resolve(context.filename);
|
|
4026
4183
|
if (!MODULE_EXTENSION.test(filename)) return {};
|
|
4027
|
-
const relative =
|
|
4184
|
+
const relative = path39.relative(context.cwd, filename).replace(/\\/g, "/");
|
|
4028
4185
|
if (relative === "src" || relative.startsWith("src/")) return {};
|
|
4029
4186
|
const topLevel = relative.split("/")[0] ?? "";
|
|
4030
4187
|
if (NON_SOURCE_ROOT_DIRS.has(topLevel)) return {};
|
|
4031
4188
|
if (!relative.includes("/")) {
|
|
4032
|
-
const basename =
|
|
4189
|
+
const basename = path39.basename(filename);
|
|
4033
4190
|
if (CONFIG_FILE.test(basename) || DECLARATION_FILE.test(basename) || basename.startsWith(".")) return {};
|
|
4034
4191
|
}
|
|
4035
4192
|
return {
|
|
@@ -4046,7 +4203,7 @@ var sourceUnderSrcRule = {
|
|
|
4046
4203
|
|
|
4047
4204
|
// eslint/rules/zirka-baseline.ts
|
|
4048
4205
|
import fs5 from "fs";
|
|
4049
|
-
import
|
|
4206
|
+
import path40 from "path";
|
|
4050
4207
|
var ESLINT_CONFIG = /^eslint\.config\.(?:ts|mts|cts|js|mjs|cjs)$/;
|
|
4051
4208
|
var PRETTIER_CONFIGS = [
|
|
4052
4209
|
"prettier.config.mjs",
|
|
@@ -4065,10 +4222,10 @@ var zirkaBaselineRule = {
|
|
|
4065
4222
|
}
|
|
4066
4223
|
},
|
|
4067
4224
|
create(context) {
|
|
4068
|
-
const filename =
|
|
4069
|
-
const basename =
|
|
4225
|
+
const filename = path40.resolve(context.filename);
|
|
4226
|
+
const basename = path40.basename(filename);
|
|
4070
4227
|
if (!ESLINT_CONFIG.test(basename)) return {};
|
|
4071
|
-
const projectRoot =
|
|
4228
|
+
const projectRoot = path40.dirname(filename);
|
|
4072
4229
|
const report3 = (message) => {
|
|
4073
4230
|
context.report({
|
|
4074
4231
|
node: context.sourceCode.ast,
|
|
@@ -4083,7 +4240,7 @@ var zirkaBaselineRule = {
|
|
|
4083
4240
|
'ESLint config must take its configuration from zirka (import { styleguide } from "zirka") instead of restating rules locally.'
|
|
4084
4241
|
);
|
|
4085
4242
|
}
|
|
4086
|
-
const tsconfigPath =
|
|
4243
|
+
const tsconfigPath = path40.join(projectRoot, "tsconfig.json");
|
|
4087
4244
|
if (!fs5.existsSync(tsconfigPath)) {
|
|
4088
4245
|
report3('No tsconfig.json found. Create one extending the zirka TypeScript base config ("zirka/typescript").');
|
|
4089
4246
|
} else {
|
|
@@ -4101,13 +4258,13 @@ var zirkaBaselineRule = {
|
|
|
4101
4258
|
report3('tsconfig.json must extend the zirka TypeScript base config ("zirka/typescript").');
|
|
4102
4259
|
}
|
|
4103
4260
|
}
|
|
4104
|
-
const prettierConfigFile = PRETTIER_CONFIGS.find((name) => fs5.existsSync(
|
|
4261
|
+
const prettierConfigFile = PRETTIER_CONFIGS.find((name) => fs5.existsSync(path40.join(projectRoot, name)));
|
|
4105
4262
|
if (!prettierConfigFile) {
|
|
4106
4263
|
report3(
|
|
4107
4264
|
"No prettier config found. Create one that takes its configuration from zirka (styleguide({ prettier: true }).prettierConfig)."
|
|
4108
4265
|
);
|
|
4109
4266
|
} else {
|
|
4110
|
-
const content = fs5.readFileSync(
|
|
4267
|
+
const content = fs5.readFileSync(path40.join(projectRoot, prettierConfigFile), "utf8");
|
|
4111
4268
|
if (!content.includes("zirka")) {
|
|
4112
4269
|
report3(
|
|
4113
4270
|
"The prettier config must take its configuration from zirka (styleguide({ prettier: true }).prettierConfig) instead of restating it locally."
|
|
@@ -4177,7 +4334,7 @@ var docKindSuffixRule = {
|
|
|
4177
4334
|
};
|
|
4178
4335
|
|
|
4179
4336
|
// eslint/rules/documentation/title-matches-file-name.ts
|
|
4180
|
-
import
|
|
4337
|
+
import path41 from "path";
|
|
4181
4338
|
function toExpectedFileName(title) {
|
|
4182
4339
|
return `${title.toLowerCase().replaceAll(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "")}.md`;
|
|
4183
4340
|
}
|
|
@@ -4197,7 +4354,7 @@ var titleMatchesFileNameRule = {
|
|
|
4197
4354
|
if (!filename.endsWith(".md")) return;
|
|
4198
4355
|
const title = getTextContent(node).trim();
|
|
4199
4356
|
const expectedFileName = toExpectedFileName(title);
|
|
4200
|
-
const actualFileName =
|
|
4357
|
+
const actualFileName = path41.basename(filename);
|
|
4201
4358
|
if (!title) {
|
|
4202
4359
|
context.report({
|
|
4203
4360
|
node,
|
|
@@ -4640,20 +4797,20 @@ var referenceBlockHeadingsRule = {
|
|
|
4640
4797
|
|
|
4641
4798
|
// eslint/rules/documentation/support-document-placement.ts
|
|
4642
4799
|
import { existsSync as existsSync2 } from "fs";
|
|
4643
|
-
import
|
|
4800
|
+
import path42 from "path";
|
|
4644
4801
|
function checkPlacement(filename, kind) {
|
|
4645
|
-
const parentFolder =
|
|
4802
|
+
const parentFolder = path42.basename(path42.dirname(filename));
|
|
4646
4803
|
const expectedParent = `${kind}s`;
|
|
4647
4804
|
if (parentFolder !== expectedParent) {
|
|
4648
4805
|
return `${kind} lives in "${parentFolder}/" instead of "${expectedParent}/"`;
|
|
4649
4806
|
}
|
|
4650
|
-
const guideFolderPath =
|
|
4651
|
-
const guideFolder =
|
|
4807
|
+
const guideFolderPath = path42.dirname(path42.dirname(filename));
|
|
4808
|
+
const guideFolder = path42.basename(guideFolderPath);
|
|
4652
4809
|
if (!guideFolder.endsWith("-guide")) {
|
|
4653
4810
|
return `${kind} owner folder "${guideFolder}/" does not use the "*-guide/" suffix`;
|
|
4654
4811
|
}
|
|
4655
4812
|
const entryPoint = `${guideFolder}.md`;
|
|
4656
|
-
if (!existsSync2(
|
|
4813
|
+
if (!existsSync2(path42.join(guideFolderPath, entryPoint))) {
|
|
4657
4814
|
return `${kind} owner folder "${guideFolder}/" has no "${entryPoint}" entry point`;
|
|
4658
4815
|
}
|
|
4659
4816
|
return void 0;
|
|
@@ -4712,11 +4869,11 @@ var noTemplatePromptRule = {
|
|
|
4712
4869
|
};
|
|
4713
4870
|
|
|
4714
4871
|
// eslint/rules/documentation/guide-folder-entry-point.ts
|
|
4715
|
-
import
|
|
4872
|
+
import path44 from "path";
|
|
4716
4873
|
|
|
4717
4874
|
// eslint/rules/documentation/project-index.ts
|
|
4718
4875
|
import { readdirSync as readdirSync3, readFileSync as readFileSync6, statSync as statSync4 } from "fs";
|
|
4719
|
-
import
|
|
4876
|
+
import path43 from "path";
|
|
4720
4877
|
var KIND_BY_SUFFIX = [
|
|
4721
4878
|
["-rule.md", "rule"],
|
|
4722
4879
|
["-guide.md", "guide"],
|
|
@@ -4725,7 +4882,7 @@ var KIND_BY_SUFFIX = [
|
|
|
4725
4882
|
];
|
|
4726
4883
|
function listMarkdownFiles(dir) {
|
|
4727
4884
|
return readdirSync3(dir).flatMap((entry) => {
|
|
4728
|
-
const entryPath =
|
|
4885
|
+
const entryPath = path43.join(dir, entry);
|
|
4729
4886
|
if (statSync4(entryPath).isDirectory()) {
|
|
4730
4887
|
return entry.startsWith("_") ? [] : listMarkdownFiles(entryPath);
|
|
4731
4888
|
}
|
|
@@ -4743,11 +4900,11 @@ function getProjectDocs(docsRoot) {
|
|
|
4743
4900
|
if (cached) return cached;
|
|
4744
4901
|
const files = listMarkdownFiles(docsRoot);
|
|
4745
4902
|
const docs = files.sort((a, b) => a.localeCompare(b)).map((filePath) => {
|
|
4746
|
-
const fileName =
|
|
4903
|
+
const fileName = path43.basename(filePath);
|
|
4747
4904
|
const kind = KIND_BY_SUFFIX.find(([suffix]) => fileName.endsWith(suffix))?.[1];
|
|
4748
4905
|
return {
|
|
4749
4906
|
filePath,
|
|
4750
|
-
doc:
|
|
4907
|
+
doc: path43.relative(docsRoot, filePath).split(path43.sep).join("/"),
|
|
4751
4908
|
fileName,
|
|
4752
4909
|
kind,
|
|
4753
4910
|
title: extractTitle(filePath)
|
|
@@ -4757,12 +4914,12 @@ function getProjectDocs(docsRoot) {
|
|
|
4757
4914
|
return docs;
|
|
4758
4915
|
}
|
|
4759
4916
|
function findDocsRoot(filePath) {
|
|
4760
|
-
let dir =
|
|
4917
|
+
let dir = path43.dirname(filePath);
|
|
4761
4918
|
for (; ; ) {
|
|
4762
|
-
if (
|
|
4919
|
+
if (path43.basename(dir) === "docs" && statSync4(dir).isDirectory()) {
|
|
4763
4920
|
return dir;
|
|
4764
4921
|
}
|
|
4765
|
-
const parent =
|
|
4922
|
+
const parent = path43.dirname(dir);
|
|
4766
4923
|
if (parent === dir) return void 0;
|
|
4767
4924
|
dir = parent;
|
|
4768
4925
|
}
|
|
@@ -4786,13 +4943,13 @@ var guideFolderEntryPointRule = {
|
|
|
4786
4943
|
if (!docsRoot) return;
|
|
4787
4944
|
const docs = getProjectDocs(docsRoot);
|
|
4788
4945
|
const guideFolders = new Set(
|
|
4789
|
-
docs.filter((doc) => ["rules", "references"].includes(
|
|
4946
|
+
docs.filter((doc) => ["rules", "references"].includes(path44.basename(path44.dirname(doc.filePath)))).map((doc) => path44.dirname(path44.dirname(doc.filePath))).filter((folder) => path44.resolve(folder) !== path44.resolve(docsRoot))
|
|
4790
4947
|
);
|
|
4791
|
-
const currentDir =
|
|
4948
|
+
const currentDir = path44.dirname(filename);
|
|
4792
4949
|
if (guideFolders.has(currentDir)) {
|
|
4793
|
-
const expectedEntryPoint = `${
|
|
4950
|
+
const expectedEntryPoint = `${path44.basename(currentDir)}.md`;
|
|
4794
4951
|
const hasEntryPoint = docs.some(
|
|
4795
|
-
(doc) => doc.kind === "guide" &&
|
|
4952
|
+
(doc) => doc.kind === "guide" && path44.dirname(doc.filePath) === currentDir && doc.fileName === expectedEntryPoint
|
|
4796
4953
|
);
|
|
4797
4954
|
if (!hasEntryPoint) {
|
|
4798
4955
|
context.report({
|
|
@@ -5017,7 +5174,7 @@ var noNestedHowToRule = {
|
|
|
5017
5174
|
|
|
5018
5175
|
// eslint/rules/documentation/glossary-term-linking.ts
|
|
5019
5176
|
import { readFileSync as readFileSync7 } from "fs";
|
|
5020
|
-
import
|
|
5177
|
+
import path45 from "path";
|
|
5021
5178
|
function extractGlossaryTerms(filePath) {
|
|
5022
5179
|
const content = readFileSync7(filePath, "utf8");
|
|
5023
5180
|
const terms = [];
|
|
@@ -5071,9 +5228,9 @@ var glossaryTermLinkingRule = {
|
|
|
5071
5228
|
const docsRoot = findDocsRoot(filename);
|
|
5072
5229
|
if (!docsRoot) return;
|
|
5073
5230
|
const docs = getProjectDocs(docsRoot);
|
|
5074
|
-
const guideDir =
|
|
5231
|
+
const guideDir = path45.dirname(filename);
|
|
5075
5232
|
const guideReferences = docs.filter(
|
|
5076
|
-
(doc) => doc.kind === "reference" &&
|
|
5233
|
+
(doc) => doc.kind === "reference" && path45.dirname(doc.filePath) === guideDir
|
|
5077
5234
|
);
|
|
5078
5235
|
if (guideReferences.length === 0) return;
|
|
5079
5236
|
const glossaryTerms = [];
|
|
@@ -5098,7 +5255,7 @@ var glossaryTermLinkingRule = {
|
|
|
5098
5255
|
|
|
5099
5256
|
// eslint/rules/documentation/guide-mentions-documents.ts
|
|
5100
5257
|
import { existsSync as existsSync3 } from "fs";
|
|
5101
|
-
import
|
|
5258
|
+
import path46 from "path";
|
|
5102
5259
|
function visitSteps3(node, check) {
|
|
5103
5260
|
if (node.type === "list" && node.ordered) {
|
|
5104
5261
|
for (const child of node.children) check(child);
|
|
@@ -5131,12 +5288,12 @@ var guideMentionsDocumentsRule = {
|
|
|
5131
5288
|
if (!filename.endsWith("-guide.md")) return;
|
|
5132
5289
|
const docsRoot = findDocsRoot(filename);
|
|
5133
5290
|
if (!docsRoot) return;
|
|
5134
|
-
const guideDir =
|
|
5135
|
-
if (
|
|
5291
|
+
const guideDir = path46.dirname(filename);
|
|
5292
|
+
if (path46.basename(filename, ".md") !== path46.basename(guideDir)) return;
|
|
5136
5293
|
const docs = getProjectDocs(docsRoot);
|
|
5137
5294
|
const owned = docs.filter((doc) => {
|
|
5138
|
-
const parent =
|
|
5139
|
-
return parent ===
|
|
5295
|
+
const parent = path46.dirname(doc.filePath);
|
|
5296
|
+
return parent === path46.join(guideDir, "rules") || parent === path46.join(guideDir, "references");
|
|
5140
5297
|
});
|
|
5141
5298
|
const allLinks = [];
|
|
5142
5299
|
collectMarkdownLinks(node, allLinks);
|
|
@@ -5163,7 +5320,7 @@ var guideMentionsDocumentsRule = {
|
|
|
5163
5320
|
for (const link of allLinks) {
|
|
5164
5321
|
const target = linkTarget(link.url);
|
|
5165
5322
|
if (!target.endsWith(".md")) continue;
|
|
5166
|
-
const resolved =
|
|
5323
|
+
const resolved = path46.normalize(path46.join(guideDir, target));
|
|
5167
5324
|
if (!existsSync3(resolved)) {
|
|
5168
5325
|
context.report({
|
|
5169
5326
|
node: link,
|
|
@@ -5713,11 +5870,11 @@ var themeVariableNamespaceRule = {
|
|
|
5713
5870
|
|
|
5714
5871
|
// eslint/rules/tailwind/css-entry-point.ts
|
|
5715
5872
|
import { statSync as statSync6 } from "fs";
|
|
5716
|
-
import
|
|
5873
|
+
import path49 from "path";
|
|
5717
5874
|
|
|
5718
5875
|
// eslint/rules/tailwind/source-files.ts
|
|
5719
5876
|
import { readdirSync as readdirSync4, readFileSync as readFileSync8, statSync as statSync5 } from "fs";
|
|
5720
|
-
import
|
|
5877
|
+
import path47 from "path";
|
|
5721
5878
|
var CSS_EXTENSIONS = [".css"];
|
|
5722
5879
|
var MODULE_EXTENSIONS3 = [".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs"];
|
|
5723
5880
|
var SOURCE_EXTENSIONS = [...MODULE_EXTENSIONS3, ...CSS_EXTENSIONS];
|
|
@@ -5730,7 +5887,7 @@ function findFiles(dir, extensions) {
|
|
|
5730
5887
|
}
|
|
5731
5888
|
return entries.flatMap((entry) => {
|
|
5732
5889
|
if (entry.startsWith(".") || entry === "node_modules") return [];
|
|
5733
|
-
const entryPath =
|
|
5890
|
+
const entryPath = path47.join(dir, entry);
|
|
5734
5891
|
let stats;
|
|
5735
5892
|
try {
|
|
5736
5893
|
stats = statSync5(entryPath);
|
|
@@ -5738,7 +5895,7 @@ function findFiles(dir, extensions) {
|
|
|
5738
5895
|
return [];
|
|
5739
5896
|
}
|
|
5740
5897
|
if (stats.isDirectory()) return findFiles(entryPath, extensions);
|
|
5741
|
-
return extensions.includes(
|
|
5898
|
+
return extensions.includes(path47.extname(entry)) ? [entryPath] : [];
|
|
5742
5899
|
});
|
|
5743
5900
|
}
|
|
5744
5901
|
function cachedTextReader() {
|
|
@@ -5761,7 +5918,7 @@ function escapeRegExp(text) {
|
|
|
5761
5918
|
}
|
|
5762
5919
|
|
|
5763
5920
|
// eslint/rules/tailwind/stylesheet-graph.ts
|
|
5764
|
-
import
|
|
5921
|
+
import path48 from "path";
|
|
5765
5922
|
function registersTailwind(text) {
|
|
5766
5923
|
return /@import\s+(?:url\(\s*)?["']tailwindcss["']\s*\)?/i.test(text);
|
|
5767
5924
|
}
|
|
@@ -5775,25 +5932,25 @@ function moduleImports(text, fileName) {
|
|
|
5775
5932
|
return new RegExp(`(?:import|require)\\s*\\(?\\s*["'][^"']*${escaped}["']`, "i").test(text);
|
|
5776
5933
|
}
|
|
5777
5934
|
function resolveSpecifier2(fromFile, spec, sourceRoot) {
|
|
5778
|
-
if (spec.startsWith("/")) return
|
|
5779
|
-
if (spec.startsWith("./") || spec.startsWith("../")) return
|
|
5780
|
-
if (spec.startsWith("@/")) return
|
|
5935
|
+
if (spec.startsWith("/")) return path48.resolve(spec);
|
|
5936
|
+
if (spec.startsWith("./") || spec.startsWith("../")) return path48.resolve(path48.dirname(fromFile), spec);
|
|
5937
|
+
if (spec.startsWith("@/")) return path48.resolve(sourceRoot, spec.slice(2));
|
|
5781
5938
|
return void 0;
|
|
5782
5939
|
}
|
|
5783
5940
|
function buildStylesheetGraph(options) {
|
|
5784
5941
|
const { cssFiles, sourceRoot, textOf } = options;
|
|
5785
|
-
const cssSet = new Set(cssFiles.map((file) =>
|
|
5942
|
+
const cssSet = new Set(cssFiles.map((file) => path48.normalize(file)));
|
|
5786
5943
|
const globals = cssFiles.filter((file) => registersTailwind(textOf(file)));
|
|
5787
5944
|
const reachable = /* @__PURE__ */ new Set();
|
|
5788
5945
|
const queue = [...globals];
|
|
5789
|
-
for (const global of globals) reachable.add(
|
|
5946
|
+
for (const global of globals) reachable.add(path48.normalize(global));
|
|
5790
5947
|
while (queue.length > 0) {
|
|
5791
5948
|
const from = queue.shift();
|
|
5792
5949
|
if (!from) continue;
|
|
5793
5950
|
for (const spec of importedSpecifiers(textOf(from))) {
|
|
5794
5951
|
const target = resolveSpecifier2(from, spec, sourceRoot);
|
|
5795
5952
|
if (!target) continue;
|
|
5796
|
-
const normalized =
|
|
5953
|
+
const normalized = path48.normalize(target);
|
|
5797
5954
|
if (cssSet.has(normalized) && !reachable.has(normalized)) {
|
|
5798
5955
|
reachable.add(normalized);
|
|
5799
5956
|
queue.push(normalized);
|
|
@@ -5805,7 +5962,7 @@ function buildStylesheetGraph(options) {
|
|
|
5805
5962
|
for (const spec of importedSpecifiers(textOf(global))) {
|
|
5806
5963
|
const target = resolveSpecifier2(global, spec, sourceRoot);
|
|
5807
5964
|
if (!target) continue;
|
|
5808
|
-
const normalized =
|
|
5965
|
+
const normalized = path48.normalize(target);
|
|
5809
5966
|
if (cssSet.has(normalized)) directChildren.add(normalized);
|
|
5810
5967
|
}
|
|
5811
5968
|
}
|
|
@@ -5838,7 +5995,7 @@ var cssEntryPointRule = {
|
|
|
5838
5995
|
return {
|
|
5839
5996
|
"StyleSheet:exit"(node) {
|
|
5840
5997
|
if (globals.length === 0) return;
|
|
5841
|
-
const current =
|
|
5998
|
+
const current = path49.normalize(path49.resolve(context.filename));
|
|
5842
5999
|
if (globals.includes(current)) {
|
|
5843
6000
|
if (globals.length > 1) {
|
|
5844
6001
|
context.report({
|
|
@@ -5847,7 +6004,7 @@ var cssEntryPointRule = {
|
|
|
5847
6004
|
});
|
|
5848
6005
|
return;
|
|
5849
6006
|
}
|
|
5850
|
-
const basename =
|
|
6007
|
+
const basename = path49.basename(current);
|
|
5851
6008
|
const importCount = moduleFiles.filter((modulePath) => moduleImports(textOf(modulePath), basename)).length;
|
|
5852
6009
|
if (importCount !== 1) {
|
|
5853
6010
|
context.report({
|
|
@@ -6176,7 +6333,7 @@ var nextjsStackRule = {
|
|
|
6176
6333
|
|
|
6177
6334
|
// eslint/rules/package-json/vitest-coverage.ts
|
|
6178
6335
|
import { existsSync as existsSync4, readFileSync as readFileSync9 } from "fs";
|
|
6179
|
-
import
|
|
6336
|
+
import path50 from "path";
|
|
6180
6337
|
function memberName4(member) {
|
|
6181
6338
|
return member.name.type === "String" ? member.name.value : member.name.name;
|
|
6182
6339
|
}
|
|
@@ -6245,7 +6402,7 @@ var vitestCoverageRule = {
|
|
|
6245
6402
|
message: 'package.json must declare a "test:unit:coverage" script that runs Vitest with coverage.'
|
|
6246
6403
|
});
|
|
6247
6404
|
}
|
|
6248
|
-
const configName = VITEST_CONFIG_NAMES.find((name) => existsSync4(
|
|
6405
|
+
const configName = VITEST_CONFIG_NAMES.find((name) => existsSync4(path50.join(context.cwd, name)));
|
|
6249
6406
|
if (!configName) {
|
|
6250
6407
|
context.report({
|
|
6251
6408
|
node,
|
|
@@ -6253,7 +6410,7 @@ var vitestCoverageRule = {
|
|
|
6253
6410
|
});
|
|
6254
6411
|
return;
|
|
6255
6412
|
}
|
|
6256
|
-
const content = readFileSync9(
|
|
6413
|
+
const content = readFileSync9(path50.join(context.cwd, configName), "utf8");
|
|
6257
6414
|
for (const metric of THRESHOLD_METRICS) {
|
|
6258
6415
|
if (!new RegExp(`\\b${metric}\\s*:\\s*[1-9]\\d*`).test(content)) {
|
|
6259
6416
|
context.report({ node, message: `${configName} must set a coverage threshold above zero for ${metric}.` });
|
|
@@ -6300,7 +6457,7 @@ var nextjsPackageJsonRules = {
|
|
|
6300
6457
|
|
|
6301
6458
|
// eslint/rules/husky/husky-hook.ts
|
|
6302
6459
|
import { existsSync as existsSync5, readFileSync as readFileSync10 } from "fs";
|
|
6303
|
-
import
|
|
6460
|
+
import path51 from "path";
|
|
6304
6461
|
var VITEST_CONFIG_NAMES2 = [
|
|
6305
6462
|
"vitest.config.ts",
|
|
6306
6463
|
"vitest.config.mts",
|
|
@@ -6326,7 +6483,7 @@ var huskyHookRule = {
|
|
|
6326
6483
|
const root = node.body;
|
|
6327
6484
|
if (root.type !== "Object") return;
|
|
6328
6485
|
if (!context.filename.endsWith("package.json")) return;
|
|
6329
|
-
const hookPath =
|
|
6486
|
+
const hookPath = path51.join(context.cwd, ".husky", "pre-commit");
|
|
6330
6487
|
if (!existsSync5(hookPath)) {
|
|
6331
6488
|
context.report({
|
|
6332
6489
|
node,
|
|
@@ -6350,7 +6507,7 @@ var huskyHookRule = {
|
|
|
6350
6507
|
}
|
|
6351
6508
|
requireNamedScript("typecheck");
|
|
6352
6509
|
requireNamedScript("test:unit:coverage");
|
|
6353
|
-
const vitestConfigName = VITEST_CONFIG_NAMES2.find((name) => existsSync5(
|
|
6510
|
+
const vitestConfigName = VITEST_CONFIG_NAMES2.find((name) => existsSync5(path51.join(context.cwd, name)));
|
|
6354
6511
|
if (vitestConfigName !== void 0) {
|
|
6355
6512
|
const coverageIndex = content.indexOf("npm run test:unit:coverage");
|
|
6356
6513
|
const localAddIndex = content.indexOf(`git add ${vitestConfigName}`);
|
|
@@ -6364,7 +6521,7 @@ var huskyHookRule = {
|
|
|
6364
6521
|
if (!content.includes("libyear --limit-major-individual=1")) {
|
|
6365
6522
|
context.report({ node, message: ".husky/pre-commit must run npx libyear --limit-major-individual=1." });
|
|
6366
6523
|
}
|
|
6367
|
-
const suppressionsPath =
|
|
6524
|
+
const suppressionsPath = path51.join(context.cwd, "eslint-suppressions.json");
|
|
6368
6525
|
if (existsSync5(suppressionsPath)) {
|
|
6369
6526
|
requireNamedScript("lint:prune");
|
|
6370
6527
|
const pruneIndex = content.indexOf("npm run lint:prune");
|
|
@@ -6437,7 +6594,7 @@ var vulykDependencyRule = {
|
|
|
6437
6594
|
|
|
6438
6595
|
// eslint/rules/vulyk/vulyk-docs.ts
|
|
6439
6596
|
import { existsSync as existsSync6, readFileSync as readFileSync11 } from "fs";
|
|
6440
|
-
import
|
|
6597
|
+
import path52 from "path";
|
|
6441
6598
|
var PASIKA_REPO = "Bredansky/pasika";
|
|
6442
6599
|
var BASE_REQUIRED_DOCS = [
|
|
6443
6600
|
{ name: "documentation-guide", path: "docs/documentation-guide" },
|
|
@@ -6470,8 +6627,8 @@ var vulykDocsRule = {
|
|
|
6470
6627
|
if (!context.filename.endsWith("package.json")) return;
|
|
6471
6628
|
const root = node.body;
|
|
6472
6629
|
if (root.type !== "Object") return;
|
|
6473
|
-
const projectRoot =
|
|
6474
|
-
const configPath =
|
|
6630
|
+
const projectRoot = path52.dirname(path52.resolve(context.filename));
|
|
6631
|
+
const configPath = path52.join(projectRoot, "vulyk.config.ts");
|
|
6475
6632
|
if (!existsSync6(configPath)) {
|
|
6476
6633
|
context.report({
|
|
6477
6634
|
node,
|
|
@@ -6496,7 +6653,7 @@ var vulykDocsRule = {
|
|
|
6496
6653
|
});
|
|
6497
6654
|
}
|
|
6498
6655
|
}
|
|
6499
|
-
const agentsPath =
|
|
6656
|
+
const agentsPath = path52.join(projectRoot, "AGENTS.md");
|
|
6500
6657
|
if (!existsSync6(agentsPath)) {
|
|
6501
6658
|
context.report({
|
|
6502
6659
|
node,
|
|
@@ -6528,12 +6685,15 @@ var pasikaNextjsAppRules = {
|
|
|
6528
6685
|
"enforce-barrel-exports": enforceBarrelExportsRule,
|
|
6529
6686
|
"config-extraction": configExtractionRule,
|
|
6530
6687
|
"value-extraction": valueExtractionRule,
|
|
6688
|
+
"constant-casing": constantCasingRule,
|
|
6531
6689
|
"type-extraction": typeExtractionRule,
|
|
6532
6690
|
"zod-schema-validation": zodSchemaValidationRule,
|
|
6691
|
+
"schema-casing": schemaCasingRule,
|
|
6533
6692
|
"source-under-src": sourceUnderSrcRule,
|
|
6534
6693
|
"zirka-baseline": zirkaBaselineRule,
|
|
6535
6694
|
// Next.js/React application rules.
|
|
6536
6695
|
"component-placement": componentPlacementRule,
|
|
6696
|
+
"component-casing": componentCasingRule,
|
|
6537
6697
|
"application-structure": applicationStructureRule,
|
|
6538
6698
|
"data-testid-case": dataTestIdCaseRule,
|
|
6539
6699
|
"jsx-hygiene": jsxHygieneRule,
|