pasika 0.8.0 → 0.9.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.
@@ -200,6 +200,7 @@ declare const pasikaPlugin: {
200
200
  "config-extraction": eslint.Rule.RuleModule;
201
201
  "value-extraction": eslint.Rule.RuleModule;
202
202
  "constant-casing": eslint.Rule.RuleModule;
203
+ "prefer-enum": eslint.Rule.RuleModule;
203
204
  "type-extraction": eslint.Rule.RuleModule;
204
205
  "zod-schema-validation": eslint.Rule.RuleModule;
205
206
  "schema-casing": eslint.Rule.RuleModule;
@@ -2170,8 +2170,47 @@ var constantCasingRule = {
2170
2170
  }
2171
2171
  };
2172
2172
 
2173
- // eslint/rules/import-through-index.ts
2173
+ // eslint/rules/prefer-enum.ts
2174
2174
  import path18 from "path";
2175
+ function isConstAssertion(node) {
2176
+ const typeAnnotation = node.typeAnnotation;
2177
+ return typeAnnotation?.type === "TSTypeReference" && typeAnnotation.typeName?.type === "Identifier" && typeAnnotation.typeName.name === "const";
2178
+ }
2179
+ function isEnumConvertibleProperty(property) {
2180
+ if (property.type !== "Property" || property.computed) return false;
2181
+ const { value } = property;
2182
+ return value.type === "Literal" && (typeof value.value === "string" || typeof value.value === "number");
2183
+ }
2184
+ var preferEnumRule = {
2185
+ meta: {
2186
+ schema: [],
2187
+ type: "problem",
2188
+ docs: {
2189
+ description: "Require a fixed set of named string/number values to be a TypeScript enum, not an `as const` object literal."
2190
+ }
2191
+ },
2192
+ create(context) {
2193
+ const filename = path18.resolve(context.filename);
2194
+ const sourceRoot = sourceRootOf(context);
2195
+ if (!filename.startsWith(sourceRoot + path18.sep)) return {};
2196
+ return {
2197
+ TSAsExpression(node) {
2198
+ if (!isConstAssertion(node)) return;
2199
+ const expression = node.expression;
2200
+ if (!expression || expression.type !== "ObjectExpression") return;
2201
+ if (expression.properties.length === 0) return;
2202
+ if (!expression.properties.every(isEnumConvertibleProperty)) return;
2203
+ context.report({
2204
+ node,
2205
+ message: "A fixed set of named values must be a TypeScript enum, not an object literal marked as const. See docs/next-codebase-guide/rules/constants-rule.md"
2206
+ });
2207
+ }
2208
+ };
2209
+ }
2210
+ };
2211
+
2212
+ // eslint/rules/import-through-index.ts
2213
+ import path19 from "path";
2175
2214
  var importThroughIndexRule = {
2176
2215
  meta: {
2177
2216
  schema: [],
@@ -2181,7 +2220,7 @@ var importThroughIndexRule = {
2181
2220
  }
2182
2221
  },
2183
2222
  create(context) {
2184
- const filename = path18.resolve(context.filename);
2223
+ const filename = path19.resolve(context.filename);
2185
2224
  const sourceRoot = sourceRootOf2(context, filename);
2186
2225
  return {
2187
2226
  Program(node) {
@@ -2193,7 +2232,7 @@ var importThroughIndexRule = {
2193
2232
  (segment) => ["constants", "types", "schemas"].includes(segment)
2194
2233
  );
2195
2234
  const supportFolder = supportFolderIndex >= 0 ? targetSegments[supportFolderIndex] : void 0;
2196
- if (!supportFolder || path18.basename(target).startsWith("index.")) continue;
2235
+ if (!supportFolder || path19.basename(target).startsWith("index.")) continue;
2197
2236
  const folderIndex = targetSegments.slice(0, supportFolderIndex + 1);
2198
2237
  const expected = `@/${folderIndex.join("/")}`;
2199
2238
  context.report({
@@ -2215,14 +2254,14 @@ function importSpecifiers(source) {
2215
2254
  return specifiers;
2216
2255
  }
2217
2256
  function sourceRootOf2(context, filename) {
2218
- const marker = `${path18.sep}src${path18.sep}`;
2257
+ const marker = `${path19.sep}src${path19.sep}`;
2219
2258
  const srcIndex = filename.lastIndexOf(marker);
2220
2259
  if (srcIndex >= 0) return filename.slice(0, srcIndex + marker.length - 1);
2221
- return path18.resolve(context.cwd ?? process.cwd(), "src");
2260
+ return path19.resolve(context.cwd ?? process.cwd(), "src");
2222
2261
  }
2223
2262
 
2224
2263
  // eslint/rules/util-file-name.ts
2225
- import path19 from "path";
2264
+ import path20 from "path";
2226
2265
  function toKebabCase2(value) {
2227
2266
  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();
2228
2267
  }
@@ -2235,7 +2274,7 @@ var utilFileNameRule = {
2235
2274
  }
2236
2275
  },
2237
2276
  create(context) {
2238
- const filename = path19.resolve(context.filename);
2277
+ const filename = path20.resolve(context.filename);
2239
2278
  const segments = filename.replace(/\\/g, "/").split("/");
2240
2279
  if (!segments.includes("utils")) return {};
2241
2280
  let module;
@@ -2249,13 +2288,13 @@ var utilFileNameRule = {
2249
2288
  const functionName = functions[0]?.name;
2250
2289
  if (!functionName) return {};
2251
2290
  const expected = toKebabCase2(functionName);
2252
- const actual = path19.basename(filename, path19.extname(filename));
2291
+ const actual = path20.basename(filename, path20.extname(filename));
2253
2292
  if (!expected || actual === expected) return {};
2254
2293
  return {
2255
2294
  Program(node) {
2256
2295
  context.report({
2257
2296
  node,
2258
- message: `A utility file exporting ${functionName} must be named ${expected}.${path19.extname(filename).slice(1)}.`
2297
+ message: `A utility file exporting ${functionName} must be named ${expected}.${path20.extname(filename).slice(1)}.`
2259
2298
  });
2260
2299
  }
2261
2300
  };
@@ -2263,7 +2302,7 @@ var utilFileNameRule = {
2263
2302
  };
2264
2303
 
2265
2304
  // eslint/rules/no-util-barrel.ts
2266
- import path20 from "path";
2305
+ import path21 from "path";
2267
2306
  var noUtilBarrelRule = {
2268
2307
  meta: {
2269
2308
  schema: [],
@@ -2273,7 +2312,7 @@ var noUtilBarrelRule = {
2273
2312
  }
2274
2313
  },
2275
2314
  create(context) {
2276
- const filename = path20.resolve(context.filename);
2315
+ const filename = path21.resolve(context.filename);
2277
2316
  const sourceRoot = sourceRootOf3(context, filename);
2278
2317
  return {
2279
2318
  Program(node) {
@@ -2282,7 +2321,7 @@ var noUtilBarrelRule = {
2282
2321
  if (!target) continue;
2283
2322
  const segments = target.replace(/\\/g, "/").split("/");
2284
2323
  const utilsIndex = segments.lastIndexOf("utils");
2285
- if (utilsIndex < 0 || !path20.basename(target).startsWith("index.")) continue;
2324
+ if (utilsIndex < 0 || !path21.basename(target).startsWith("index.")) continue;
2286
2325
  context.report({
2287
2326
  node,
2288
2327
  message: `Import utilities directly instead of through "${specifier}". See docs/next-codebase-guide/rules/utilities-rule.md`
@@ -2302,10 +2341,10 @@ function importSpecifiers2(source) {
2302
2341
  return specifiers;
2303
2342
  }
2304
2343
  function sourceRootOf3(context, filename) {
2305
- const marker = `${path20.sep}src${path20.sep}`;
2344
+ const marker = `${path21.sep}src${path21.sep}`;
2306
2345
  const srcIndex = filename.lastIndexOf(marker);
2307
2346
  if (srcIndex >= 0) return filename.slice(0, srcIndex + marker.length - 1);
2308
- return path20.resolve(context.cwd ?? process.cwd(), "src");
2347
+ return path21.resolve(context.cwd ?? process.cwd(), "src");
2309
2348
  }
2310
2349
 
2311
2350
  // eslint/rules/jsx-hygiene.ts
@@ -2398,7 +2437,7 @@ var jsxHygieneRule = {
2398
2437
  };
2399
2438
 
2400
2439
  // eslint/rules/interactive-component.ts
2401
- import path21 from "path";
2440
+ import path22 from "path";
2402
2441
  var INTERACTIVE_TAGS = /* @__PURE__ */ new Set([
2403
2442
  "a",
2404
2443
  "button",
@@ -2553,8 +2592,8 @@ var interactiveComponentRule = {
2553
2592
  },
2554
2593
  create(context) {
2555
2594
  if (!context.filename.endsWith(".tsx") && !context.filename.endsWith(".jsx")) return {};
2556
- const filename = path21.resolve(context.filename);
2557
- const base = path21.basename(filename, path21.extname(filename));
2595
+ const filename = path22.resolve(context.filename);
2596
+ const base = path22.basename(filename, path22.extname(filename));
2558
2597
  if (NEXT_ROUTING_FILES3.has(base)) return {};
2559
2598
  return {
2560
2599
  JSXElement(node) {
@@ -2805,12 +2844,12 @@ var cvaBooleanVariantsRule = {
2805
2844
  };
2806
2845
 
2807
2846
  // eslint/rules/cross-feature-import.ts
2808
- import path22 from "path";
2847
+ import path23 from "path";
2809
2848
  var FEATURES_SEGMENT = "features";
2810
2849
  function featureNameOf(resolvedPath, sourceRoot) {
2811
- const relative = path22.relative(sourceRoot, resolvedPath);
2850
+ const relative = path23.relative(sourceRoot, resolvedPath);
2812
2851
  if (relative.startsWith("..")) return void 0;
2813
- const segments = relative.split(path22.sep);
2852
+ const segments = relative.split(path23.sep);
2814
2853
  if (segments[0] !== FEATURES_SEGMENT || segments.length < 2) return void 0;
2815
2854
  return segments[1];
2816
2855
  }
@@ -2826,9 +2865,9 @@ var crossFeatureImportRule = {
2826
2865
  const filename = context.filename;
2827
2866
  if (!filename.endsWith(".tsx") && !filename.endsWith(".jsx")) return {};
2828
2867
  const sourceRoot = sourceRootOf(context);
2829
- const fileRelative = path22.relative(sourceRoot, filename);
2868
+ const fileRelative = path23.relative(sourceRoot, filename);
2830
2869
  if (fileRelative.startsWith("..")) return {};
2831
- const fileSegments = fileRelative.split(path22.sep);
2870
+ const fileSegments = fileRelative.split(path23.sep);
2832
2871
  const isInCompositions = fileSegments[0] === "compositions";
2833
2872
  const isInApp = fileSegments[0] === "app";
2834
2873
  const isConfig = fileSegments[0] === "config";
@@ -2842,9 +2881,9 @@ var crossFeatureImportRule = {
2842
2881
  if (typeof source.value !== "string") return;
2843
2882
  let resolved;
2844
2883
  if (source.value.startsWith("@/")) {
2845
- resolved = path22.resolve(sourceRoot, source.value.slice(2));
2884
+ resolved = path23.resolve(sourceRoot, source.value.slice(2));
2846
2885
  } else if (source.value.startsWith(".")) {
2847
- resolved = path22.resolve(path22.dirname(filename), source.value);
2886
+ resolved = path23.resolve(path23.dirname(filename), source.value);
2848
2887
  }
2849
2888
  if (!resolved) return;
2850
2889
  const feature = featureNameOf(resolved, sourceRoot);
@@ -2863,7 +2902,7 @@ var crossFeatureImportRule = {
2863
2902
  };
2864
2903
 
2865
2904
  // eslint/rules/pure-function-extract.ts
2866
- import path23 from "path";
2905
+ import path24 from "path";
2867
2906
  function isComponentLikeName(name) {
2868
2907
  return /^[A-Z]/.test(name);
2869
2908
  }
@@ -2892,9 +2931,9 @@ var pureFunctionExtractRule = {
2892
2931
  const filename = context.filename;
2893
2932
  if (!filename.endsWith(".tsx") && !filename.endsWith(".jsx")) return {};
2894
2933
  const sourceRoot = sourceRootOf(context);
2895
- const relative = path23.relative(sourceRoot, filename);
2934
+ const relative = path24.relative(sourceRoot, filename);
2896
2935
  if (relative.startsWith("..")) return {};
2897
- const segments = relative.split(path23.sep);
2936
+ const segments = relative.split(path24.sep);
2898
2937
  if (segments[0] === "utils") return {};
2899
2938
  if (segments[0] === "app") return {};
2900
2939
  const supportFolders = /* @__PURE__ */ new Set(["hooks", "types", "schemas", "constants", "utils"]);
@@ -2934,7 +2973,7 @@ var pureFunctionExtractRule = {
2934
2973
  };
2935
2974
 
2936
2975
  // eslint/rules/hook-complexity.ts
2937
- import path24 from "path";
2976
+ import path25 from "path";
2938
2977
  import ts4 from "typescript";
2939
2978
  var REACT_HOOKS = /* @__PURE__ */ new Set([
2940
2979
  "useState",
@@ -2987,9 +3026,9 @@ var hookComplexityRule = {
2987
3026
  create(context) {
2988
3027
  const filename = context.filename;
2989
3028
  const sourceRoot = sourceRootOf(context);
2990
- const relative = path24.relative(sourceRoot, filename);
3029
+ const relative = path25.relative(sourceRoot, filename);
2991
3030
  if (relative.startsWith("..")) return {};
2992
- const segments = relative.split(path24.sep);
3031
+ const segments = relative.split(path25.sep);
2993
3032
  const sourceText = context.sourceCode.text;
2994
3033
  function checkHook(node, name, body, exported) {
2995
3034
  if (!exported) return;
@@ -3031,9 +3070,9 @@ var hookComplexityRule = {
3031
3070
  };
3032
3071
 
3033
3072
  // eslint/rules/locale-dotted-path.ts
3034
- import path25 from "path";
3073
+ import path26 from "path";
3035
3074
  function isInLocalesDir(filename) {
3036
- const segments = path25.resolve(filename).split(path25.sep);
3075
+ const segments = path26.resolve(filename).split(path26.sep);
3037
3076
  const srcIdx = segments.lastIndexOf("src");
3038
3077
  return srcIdx !== -1 && segments[srcIdx + 1] === "locales";
3039
3078
  }
@@ -3082,16 +3121,22 @@ var localeDottedPathRule = {
3082
3121
  };
3083
3122
 
3084
3123
  // eslint/rules/locales-location.ts
3085
- import path26 from "path";
3124
+ import path27 from "path";
3086
3125
  function isLocalesFile(filename) {
3087
- const segments = path26.resolve(filename).split(path26.sep);
3126
+ const segments = path27.resolve(filename).split(path27.sep);
3088
3127
  const srcIdx = segments.lastIndexOf("src");
3089
3128
  return srcIdx !== -1 && segments[srcIdx + 1] === "locales";
3090
3129
  }
3130
+ function isTestFile(filename) {
3131
+ return /\.(?:test|spec)\.[cm]?tsx?$/.test(filename);
3132
+ }
3091
3133
  var LOCALE_NAME_RE = /^[a-z][a-zA-Z0-9]*$/;
3092
3134
  function looksLikeLocaleKey(name) {
3093
3135
  return LOCALE_NAME_RE.test(name);
3094
3136
  }
3137
+ function looksLikeUserFacingString(value) {
3138
+ return typeof value === "string" && /^\p{Lu}/u.test(value);
3139
+ }
3095
3140
  var localesLocationRule = {
3096
3141
  meta: {
3097
3142
  schema: [],
@@ -3101,9 +3146,9 @@ var localesLocationRule = {
3101
3146
  }
3102
3147
  },
3103
3148
  create(context) {
3104
- if (isLocalesFile(context.filename)) return {};
3149
+ if (isLocalesFile(context.filename) || isTestFile(context.filename)) return {};
3105
3150
  const filename = context.filename;
3106
- const segments = path26.resolve(filename).split(path26.sep);
3151
+ const segments = path27.resolve(filename).split(path27.sep);
3107
3152
  const srcIdx = segments.lastIndexOf("src");
3108
3153
  if (srcIdx === -1) return {};
3109
3154
  const folder = segments[srcIdx + 1];
@@ -3111,8 +3156,10 @@ var localesLocationRule = {
3111
3156
  return {
3112
3157
  VariableDeclarator(node) {
3113
3158
  if (node.id.type === "Identifier" && node.init?.type === "ObjectExpression" && node.init.properties.length > 0 && looksLikeLocaleKey(node.id.name)) {
3114
- const hasStringValues = node.init.properties.some((p) => p.type === "Property" && p.value.type === "Literal");
3115
- if (hasStringValues) {
3159
+ const hasUserFacingStringValues = node.init.properties.some(
3160
+ (p) => p.type === "Property" && p.value.type === "Literal" && looksLikeUserFacingString(p.value.value)
3161
+ );
3162
+ if (hasUserFacingStringValues) {
3116
3163
  context.report({
3117
3164
  node,
3118
3165
  message: "User-facing strings must live in src/locales/, not inline in component files."
@@ -3125,7 +3172,7 @@ var localesLocationRule = {
3125
3172
  };
3126
3173
 
3127
3174
  // eslint/rules/hook-extraction.ts
3128
- import path27 from "path";
3175
+ import path28 from "path";
3129
3176
  var hookExtractionRule = {
3130
3177
  meta: {
3131
3178
  schema: [],
@@ -3136,7 +3183,7 @@ var hookExtractionRule = {
3136
3183
  },
3137
3184
  create(context) {
3138
3185
  const sourceRoot = sourceRootOf(context);
3139
- const file = path27.resolve(context.filename);
3186
+ const file = path28.resolve(context.filename);
3140
3187
  const segments = segmentsOf(file, sourceRoot);
3141
3188
  if (segments.length === 0) return {};
3142
3189
  const index = getProjectIndex(sourceRoot);
@@ -3162,7 +3209,7 @@ var hookExtractionRule = {
3162
3209
  };
3163
3210
 
3164
3211
  // eslint/rules/value-extraction.ts
3165
- import path28 from "path";
3212
+ import path29 from "path";
3166
3213
  var valueExtractionRule = {
3167
3214
  meta: {
3168
3215
  schema: [],
@@ -3173,7 +3220,7 @@ var valueExtractionRule = {
3173
3220
  },
3174
3221
  create(context) {
3175
3222
  const sourceRoot = sourceRootOf(context);
3176
- const file = path28.resolve(context.filename);
3223
+ const file = path29.resolve(context.filename);
3177
3224
  const segments = segmentsOf(file, sourceRoot);
3178
3225
  if (segments.length === 0 || segments[0] !== "app") return {};
3179
3226
  const index = getProjectIndex(sourceRoot);
@@ -3194,7 +3241,7 @@ var valueExtractionRule = {
3194
3241
  };
3195
3242
 
3196
3243
  // eslint/rules/config-extraction.ts
3197
- import path29 from "path";
3244
+ import path30 from "path";
3198
3245
  var configExtractionRule = {
3199
3246
  meta: {
3200
3247
  schema: [],
@@ -3205,7 +3252,7 @@ var configExtractionRule = {
3205
3252
  },
3206
3253
  create(context) {
3207
3254
  const sourceRoot = sourceRootOf(context);
3208
- const file = path29.resolve(context.filename);
3255
+ const file = path30.resolve(context.filename);
3209
3256
  const segments = segmentsOf(file, sourceRoot);
3210
3257
  if (segments.length < 3 || segments[0] !== "config") return {};
3211
3258
  if (SUPPORT_FOLDERS2.has(segments[2] ?? "")) return {};
@@ -3243,7 +3290,7 @@ var configExtractionRule = {
3243
3290
  };
3244
3291
 
3245
3292
  // eslint/rules/component-nesting.ts
3246
- import path30 from "path";
3293
+ import path31 from "path";
3247
3294
  var componentNestingRule = {
3248
3295
  meta: {
3249
3296
  schema: [],
@@ -3254,7 +3301,7 @@ var componentNestingRule = {
3254
3301
  },
3255
3302
  create(context) {
3256
3303
  const sourceRoot = sourceRootOf(context);
3257
- const file = path30.resolve(context.filename);
3304
+ const file = path31.resolve(context.filename);
3258
3305
  const segments = segmentsOf(file, sourceRoot);
3259
3306
  if (segments.length !== 4 || segments[0] !== "features") return {};
3260
3307
  const index = getProjectIndex(sourceRoot);
@@ -3287,7 +3334,7 @@ var componentNestingRule = {
3287
3334
  };
3288
3335
 
3289
3336
  // eslint/rules/stay-flat.ts
3290
- import path31 from "path";
3337
+ import path32 from "path";
3291
3338
  var stayFlatRule = {
3292
3339
  meta: {
3293
3340
  schema: [],
@@ -3298,7 +3345,7 @@ var stayFlatRule = {
3298
3345
  },
3299
3346
  create(context) {
3300
3347
  const sourceRoot = sourceRootOf(context);
3301
- const file = path31.resolve(context.filename);
3348
+ const file = path32.resolve(context.filename);
3302
3349
  const segments = segmentsOf(file, sourceRoot);
3303
3350
  if (segments.length !== 3 || segments[0] !== "features") return {};
3304
3351
  const index = getProjectIndex(sourceRoot);
@@ -3338,7 +3385,7 @@ var stayFlatRule = {
3338
3385
  };
3339
3386
 
3340
3387
  // eslint/rules/type-extraction.ts
3341
- import path32 from "path";
3388
+ import path33 from "path";
3342
3389
  var typeExtractionRule = {
3343
3390
  meta: {
3344
3391
  schema: [],
@@ -3349,7 +3396,7 @@ var typeExtractionRule = {
3349
3396
  },
3350
3397
  create(context) {
3351
3398
  const sourceRoot = sourceRootOf(context);
3352
- const file = path32.resolve(context.filename);
3399
+ const file = path33.resolve(context.filename);
3353
3400
  const segments = segmentsOf(file, sourceRoot);
3354
3401
  if (segments.length === 0) return {};
3355
3402
  const index = getProjectIndex(sourceRoot);
@@ -3395,7 +3442,7 @@ var typeExtractionRule = {
3395
3442
  };
3396
3443
 
3397
3444
  // eslint/rules/locale-placement.ts
3398
- import path33 from "path";
3445
+ import path34 from "path";
3399
3446
  import { readFileSync as readFileSync4 } from "fs";
3400
3447
  import ts5 from "typescript";
3401
3448
  var LOCALE_ACCESS = /\blocales\.(?<key>[A-Za-z_$][\w$]*)/g;
@@ -3443,7 +3490,7 @@ var localePlacementRule = {
3443
3490
  },
3444
3491
  create(context) {
3445
3492
  const sourceRoot = sourceRootOf(context);
3446
- const file = path33.resolve(context.filename);
3493
+ const file = path34.resolve(context.filename);
3447
3494
  const segments = segmentsOf(file, sourceRoot);
3448
3495
  if (segments.length === 0) return {};
3449
3496
  const index = getProjectIndex(sourceRoot);
@@ -3521,7 +3568,7 @@ var localePlacementRule = {
3521
3568
  };
3522
3569
 
3523
3570
  // eslint/rules/sole-state-owner.ts
3524
- import path34 from "path";
3571
+ import path35 from "path";
3525
3572
  import ts6 from "typescript";
3526
3573
  function findStateHooks(node) {
3527
3574
  const hooks = [];
@@ -3601,7 +3648,7 @@ var soleStateOwnerRule = {
3601
3648
  }
3602
3649
  },
3603
3650
  create(context) {
3604
- const filename = path34.resolve(context.filename);
3651
+ const filename = path35.resolve(context.filename);
3605
3652
  if (!filename.endsWith(".tsx") && !filename.endsWith(".jsx")) return {};
3606
3653
  const text = context.sourceCode.text;
3607
3654
  const components = parseComponentInfo(text, filename);
@@ -3680,7 +3727,7 @@ function usesOutsideJsx(declaration, hook, children) {
3680
3727
  }
3681
3728
 
3682
3729
  // eslint/rules/locale-key-shape.ts
3683
- import path35 from "path";
3730
+ import path36 from "path";
3684
3731
  var MAX_KEY_LENGTH = 30;
3685
3732
  var ROLE_POSTFIXES = /* @__PURE__ */ new Set([
3686
3733
  "Button",
@@ -3730,7 +3777,7 @@ var ROLE_POSTFIXES = /* @__PURE__ */ new Set([
3730
3777
  var CAMEL_CASE = /^[a-z][a-zA-Z0-9]*$/;
3731
3778
  var ENGLISH = /^[A-Za-z0-9_]*$/;
3732
3779
  function isLocalesFile2(filename) {
3733
- const segments = path35.resolve(filename).split(path35.sep);
3780
+ const segments = path36.resolve(filename).split(path36.sep);
3734
3781
  const srcIdx = segments.lastIndexOf("src");
3735
3782
  return srcIdx !== -1 && segments[srcIdx + 1] === "locales";
3736
3783
  }
@@ -3801,7 +3848,7 @@ var localeKeyShapeRule = {
3801
3848
  };
3802
3849
 
3803
3850
  // eslint/rules/shared-style-dedup.ts
3804
- import path36 from "path";
3851
+ import path37 from "path";
3805
3852
  import { readFileSync as readFileSync5, statSync as statSync3 } from "fs";
3806
3853
  var CLASS_NAME = /className="(?<classes>[^"]+)"/g;
3807
3854
  var comboCache;
@@ -3839,7 +3886,7 @@ var sharedStyleDedupRule = {
3839
3886
  },
3840
3887
  create(context) {
3841
3888
  const sourceRoot = sourceRootOf(context);
3842
- const file = path36.resolve(context.filename);
3889
+ const file = path37.resolve(context.filename);
3843
3890
  const segments = segmentsOf(file, sourceRoot);
3844
3891
  if (segments.length === 0) return {};
3845
3892
  const index = getProjectIndex(sourceRoot);
@@ -4043,7 +4090,7 @@ var zodSchemaValidationRule = {
4043
4090
  };
4044
4091
 
4045
4092
  // eslint/rules/schema-casing.ts
4046
- import path37 from "path";
4093
+ import path38 from "path";
4047
4094
  function isCamelCase(name) {
4048
4095
  return /^[a-z][a-zA-Z0-9]*$/.test(name);
4049
4096
  }
@@ -4071,9 +4118,9 @@ var schemaCasingRule = {
4071
4118
  }
4072
4119
  },
4073
4120
  create(context) {
4074
- const filename = path37.resolve(context.filename);
4121
+ const filename = path38.resolve(context.filename);
4075
4122
  const sourceRoot = sourceRootOf(context);
4076
- if (!filename.startsWith(sourceRoot + path37.sep)) return {};
4123
+ if (!filename.startsWith(sourceRoot + path38.sep)) return {};
4077
4124
  let zodLocalName;
4078
4125
  return {
4079
4126
  ImportDeclaration(node) {
@@ -4105,7 +4152,7 @@ var schemaCasingRule = {
4105
4152
  };
4106
4153
 
4107
4154
  // eslint/rules/component-casing.ts
4108
- import path38 from "path";
4155
+ import path39 from "path";
4109
4156
  function isPascalCase6(name) {
4110
4157
  return /^[A-Z][A-Za-z0-9]*$/.test(name);
4111
4158
  }
@@ -4118,10 +4165,10 @@ var componentCasingRule = {
4118
4165
  }
4119
4166
  },
4120
4167
  create(context) {
4121
- const filename = path38.resolve(context.filename);
4168
+ const filename = path39.resolve(context.filename);
4122
4169
  const sourceRoot = sourceRootOf(context);
4123
- if (!filename.startsWith(sourceRoot + path38.sep)) return {};
4124
- if (path38.extname(filename) !== ".tsx") return {};
4170
+ if (!filename.startsWith(sourceRoot + path39.sep)) return {};
4171
+ if (path39.extname(filename) !== ".tsx") return {};
4125
4172
  return {
4126
4173
  Program(node) {
4127
4174
  for (const declaration of findJsxReturningDeclarations(context.sourceCode.text, filename)) {
@@ -4138,7 +4185,7 @@ var componentCasingRule = {
4138
4185
  };
4139
4186
 
4140
4187
  // eslint/rules/source-under-src.ts
4141
- import path39 from "path";
4188
+ import path40 from "path";
4142
4189
  var NON_SOURCE_ROOT_DIRS = /* @__PURE__ */ new Set([
4143
4190
  ".agents",
4144
4191
  ".cache",
@@ -4179,14 +4226,14 @@ var sourceUnderSrcRule = {
4179
4226
  }
4180
4227
  },
4181
4228
  create(context) {
4182
- const filename = path39.resolve(context.filename);
4229
+ const filename = path40.resolve(context.filename);
4183
4230
  if (!MODULE_EXTENSION.test(filename)) return {};
4184
- const relative = path39.relative(context.cwd, filename).replace(/\\/g, "/");
4231
+ const relative = path40.relative(context.cwd, filename).replace(/\\/g, "/");
4185
4232
  if (relative === "src" || relative.startsWith("src/")) return {};
4186
4233
  const topLevel = relative.split("/")[0] ?? "";
4187
4234
  if (NON_SOURCE_ROOT_DIRS.has(topLevel)) return {};
4188
4235
  if (!relative.includes("/")) {
4189
- const basename = path39.basename(filename);
4236
+ const basename = path40.basename(filename);
4190
4237
  if (CONFIG_FILE.test(basename) || DECLARATION_FILE.test(basename) || basename.startsWith(".")) return {};
4191
4238
  }
4192
4239
  return {
@@ -4203,7 +4250,7 @@ var sourceUnderSrcRule = {
4203
4250
 
4204
4251
  // eslint/rules/zirka-baseline.ts
4205
4252
  import fs5 from "fs";
4206
- import path40 from "path";
4253
+ import path41 from "path";
4207
4254
  var ESLINT_CONFIG = /^eslint\.config\.(?:ts|mts|cts|js|mjs|cjs)$/;
4208
4255
  var PRETTIER_CONFIGS = [
4209
4256
  "prettier.config.mjs",
@@ -4222,10 +4269,10 @@ var zirkaBaselineRule = {
4222
4269
  }
4223
4270
  },
4224
4271
  create(context) {
4225
- const filename = path40.resolve(context.filename);
4226
- const basename = path40.basename(filename);
4272
+ const filename = path41.resolve(context.filename);
4273
+ const basename = path41.basename(filename);
4227
4274
  if (!ESLINT_CONFIG.test(basename)) return {};
4228
- const projectRoot = path40.dirname(filename);
4275
+ const projectRoot = path41.dirname(filename);
4229
4276
  const report3 = (message) => {
4230
4277
  context.report({
4231
4278
  node: context.sourceCode.ast,
@@ -4240,7 +4287,7 @@ var zirkaBaselineRule = {
4240
4287
  'ESLint config must take its configuration from zirka (import { styleguide } from "zirka") instead of restating rules locally.'
4241
4288
  );
4242
4289
  }
4243
- const tsconfigPath = path40.join(projectRoot, "tsconfig.json");
4290
+ const tsconfigPath = path41.join(projectRoot, "tsconfig.json");
4244
4291
  if (!fs5.existsSync(tsconfigPath)) {
4245
4292
  report3('No tsconfig.json found. Create one extending the zirka TypeScript base config ("zirka/typescript").');
4246
4293
  } else {
@@ -4258,13 +4305,13 @@ var zirkaBaselineRule = {
4258
4305
  report3('tsconfig.json must extend the zirka TypeScript base config ("zirka/typescript").');
4259
4306
  }
4260
4307
  }
4261
- const prettierConfigFile = PRETTIER_CONFIGS.find((name) => fs5.existsSync(path40.join(projectRoot, name)));
4308
+ const prettierConfigFile = PRETTIER_CONFIGS.find((name) => fs5.existsSync(path41.join(projectRoot, name)));
4262
4309
  if (!prettierConfigFile) {
4263
4310
  report3(
4264
4311
  "No prettier config found. Create one that takes its configuration from zirka (styleguide({ prettier: true }).prettierConfig)."
4265
4312
  );
4266
4313
  } else {
4267
- const content = fs5.readFileSync(path40.join(projectRoot, prettierConfigFile), "utf8");
4314
+ const content = fs5.readFileSync(path41.join(projectRoot, prettierConfigFile), "utf8");
4268
4315
  if (!content.includes("zirka")) {
4269
4316
  report3(
4270
4317
  "The prettier config must take its configuration from zirka (styleguide({ prettier: true }).prettierConfig) instead of restating it locally."
@@ -4334,7 +4381,7 @@ var docKindSuffixRule = {
4334
4381
  };
4335
4382
 
4336
4383
  // eslint/rules/documentation/title-matches-file-name.ts
4337
- import path41 from "path";
4384
+ import path42 from "path";
4338
4385
  function toExpectedFileName(title) {
4339
4386
  return `${title.toLowerCase().replaceAll(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "")}.md`;
4340
4387
  }
@@ -4354,7 +4401,7 @@ var titleMatchesFileNameRule = {
4354
4401
  if (!filename.endsWith(".md")) return;
4355
4402
  const title = getTextContent(node).trim();
4356
4403
  const expectedFileName = toExpectedFileName(title);
4357
- const actualFileName = path41.basename(filename);
4404
+ const actualFileName = path42.basename(filename);
4358
4405
  if (!title) {
4359
4406
  context.report({
4360
4407
  node,
@@ -4797,20 +4844,20 @@ var referenceBlockHeadingsRule = {
4797
4844
 
4798
4845
  // eslint/rules/documentation/support-document-placement.ts
4799
4846
  import { existsSync as existsSync2 } from "fs";
4800
- import path42 from "path";
4847
+ import path43 from "path";
4801
4848
  function checkPlacement(filename, kind) {
4802
- const parentFolder = path42.basename(path42.dirname(filename));
4849
+ const parentFolder = path43.basename(path43.dirname(filename));
4803
4850
  const expectedParent = `${kind}s`;
4804
4851
  if (parentFolder !== expectedParent) {
4805
4852
  return `${kind} lives in "${parentFolder}/" instead of "${expectedParent}/"`;
4806
4853
  }
4807
- const guideFolderPath = path42.dirname(path42.dirname(filename));
4808
- const guideFolder = path42.basename(guideFolderPath);
4854
+ const guideFolderPath = path43.dirname(path43.dirname(filename));
4855
+ const guideFolder = path43.basename(guideFolderPath);
4809
4856
  if (!guideFolder.endsWith("-guide")) {
4810
4857
  return `${kind} owner folder "${guideFolder}/" does not use the "*-guide/" suffix`;
4811
4858
  }
4812
4859
  const entryPoint = `${guideFolder}.md`;
4813
- if (!existsSync2(path42.join(guideFolderPath, entryPoint))) {
4860
+ if (!existsSync2(path43.join(guideFolderPath, entryPoint))) {
4814
4861
  return `${kind} owner folder "${guideFolder}/" has no "${entryPoint}" entry point`;
4815
4862
  }
4816
4863
  return void 0;
@@ -4869,11 +4916,11 @@ var noTemplatePromptRule = {
4869
4916
  };
4870
4917
 
4871
4918
  // eslint/rules/documentation/guide-folder-entry-point.ts
4872
- import path44 from "path";
4919
+ import path45 from "path";
4873
4920
 
4874
4921
  // eslint/rules/documentation/project-index.ts
4875
4922
  import { readdirSync as readdirSync3, readFileSync as readFileSync6, statSync as statSync4 } from "fs";
4876
- import path43 from "path";
4923
+ import path44 from "path";
4877
4924
  var KIND_BY_SUFFIX = [
4878
4925
  ["-rule.md", "rule"],
4879
4926
  ["-guide.md", "guide"],
@@ -4882,7 +4929,7 @@ var KIND_BY_SUFFIX = [
4882
4929
  ];
4883
4930
  function listMarkdownFiles(dir) {
4884
4931
  return readdirSync3(dir).flatMap((entry) => {
4885
- const entryPath = path43.join(dir, entry);
4932
+ const entryPath = path44.join(dir, entry);
4886
4933
  if (statSync4(entryPath).isDirectory()) {
4887
4934
  return entry.startsWith("_") ? [] : listMarkdownFiles(entryPath);
4888
4935
  }
@@ -4900,11 +4947,11 @@ function getProjectDocs(docsRoot) {
4900
4947
  if (cached) return cached;
4901
4948
  const files = listMarkdownFiles(docsRoot);
4902
4949
  const docs = files.sort((a, b) => a.localeCompare(b)).map((filePath) => {
4903
- const fileName = path43.basename(filePath);
4950
+ const fileName = path44.basename(filePath);
4904
4951
  const kind = KIND_BY_SUFFIX.find(([suffix]) => fileName.endsWith(suffix))?.[1];
4905
4952
  return {
4906
4953
  filePath,
4907
- doc: path43.relative(docsRoot, filePath).split(path43.sep).join("/"),
4954
+ doc: path44.relative(docsRoot, filePath).split(path44.sep).join("/"),
4908
4955
  fileName,
4909
4956
  kind,
4910
4957
  title: extractTitle(filePath)
@@ -4914,12 +4961,12 @@ function getProjectDocs(docsRoot) {
4914
4961
  return docs;
4915
4962
  }
4916
4963
  function findDocsRoot(filePath) {
4917
- let dir = path43.dirname(filePath);
4964
+ let dir = path44.dirname(filePath);
4918
4965
  for (; ; ) {
4919
- if (path43.basename(dir) === "docs" && statSync4(dir).isDirectory()) {
4966
+ if (path44.basename(dir) === "docs" && statSync4(dir).isDirectory()) {
4920
4967
  return dir;
4921
4968
  }
4922
- const parent = path43.dirname(dir);
4969
+ const parent = path44.dirname(dir);
4923
4970
  if (parent === dir) return void 0;
4924
4971
  dir = parent;
4925
4972
  }
@@ -4943,13 +4990,13 @@ var guideFolderEntryPointRule = {
4943
4990
  if (!docsRoot) return;
4944
4991
  const docs = getProjectDocs(docsRoot);
4945
4992
  const guideFolders = new Set(
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))
4993
+ docs.filter((doc) => ["rules", "references"].includes(path45.basename(path45.dirname(doc.filePath)))).map((doc) => path45.dirname(path45.dirname(doc.filePath))).filter((folder) => path45.resolve(folder) !== path45.resolve(docsRoot))
4947
4994
  );
4948
- const currentDir = path44.dirname(filename);
4995
+ const currentDir = path45.dirname(filename);
4949
4996
  if (guideFolders.has(currentDir)) {
4950
- const expectedEntryPoint = `${path44.basename(currentDir)}.md`;
4997
+ const expectedEntryPoint = `${path45.basename(currentDir)}.md`;
4951
4998
  const hasEntryPoint = docs.some(
4952
- (doc) => doc.kind === "guide" && path44.dirname(doc.filePath) === currentDir && doc.fileName === expectedEntryPoint
4999
+ (doc) => doc.kind === "guide" && path45.dirname(doc.filePath) === currentDir && doc.fileName === expectedEntryPoint
4953
5000
  );
4954
5001
  if (!hasEntryPoint) {
4955
5002
  context.report({
@@ -5174,7 +5221,7 @@ var noNestedHowToRule = {
5174
5221
 
5175
5222
  // eslint/rules/documentation/glossary-term-linking.ts
5176
5223
  import { readFileSync as readFileSync7 } from "fs";
5177
- import path45 from "path";
5224
+ import path46 from "path";
5178
5225
  function extractGlossaryTerms(filePath) {
5179
5226
  const content = readFileSync7(filePath, "utf8");
5180
5227
  const terms = [];
@@ -5228,9 +5275,9 @@ var glossaryTermLinkingRule = {
5228
5275
  const docsRoot = findDocsRoot(filename);
5229
5276
  if (!docsRoot) return;
5230
5277
  const docs = getProjectDocs(docsRoot);
5231
- const guideDir = path45.dirname(filename);
5278
+ const guideDir = path46.dirname(filename);
5232
5279
  const guideReferences = docs.filter(
5233
- (doc) => doc.kind === "reference" && path45.dirname(doc.filePath) === guideDir
5280
+ (doc) => doc.kind === "reference" && path46.dirname(doc.filePath) === guideDir
5234
5281
  );
5235
5282
  if (guideReferences.length === 0) return;
5236
5283
  const glossaryTerms = [];
@@ -5255,7 +5302,7 @@ var glossaryTermLinkingRule = {
5255
5302
 
5256
5303
  // eslint/rules/documentation/guide-mentions-documents.ts
5257
5304
  import { existsSync as existsSync3 } from "fs";
5258
- import path46 from "path";
5305
+ import path47 from "path";
5259
5306
  function visitSteps3(node, check) {
5260
5307
  if (node.type === "list" && node.ordered) {
5261
5308
  for (const child of node.children) check(child);
@@ -5288,12 +5335,12 @@ var guideMentionsDocumentsRule = {
5288
5335
  if (!filename.endsWith("-guide.md")) return;
5289
5336
  const docsRoot = findDocsRoot(filename);
5290
5337
  if (!docsRoot) return;
5291
- const guideDir = path46.dirname(filename);
5292
- if (path46.basename(filename, ".md") !== path46.basename(guideDir)) return;
5338
+ const guideDir = path47.dirname(filename);
5339
+ if (path47.basename(filename, ".md") !== path47.basename(guideDir)) return;
5293
5340
  const docs = getProjectDocs(docsRoot);
5294
5341
  const owned = docs.filter((doc) => {
5295
- const parent = path46.dirname(doc.filePath);
5296
- return parent === path46.join(guideDir, "rules") || parent === path46.join(guideDir, "references");
5342
+ const parent = path47.dirname(doc.filePath);
5343
+ return parent === path47.join(guideDir, "rules") || parent === path47.join(guideDir, "references");
5297
5344
  });
5298
5345
  const allLinks = [];
5299
5346
  collectMarkdownLinks(node, allLinks);
@@ -5320,7 +5367,7 @@ var guideMentionsDocumentsRule = {
5320
5367
  for (const link of allLinks) {
5321
5368
  const target = linkTarget(link.url);
5322
5369
  if (!target.endsWith(".md")) continue;
5323
- const resolved = path46.normalize(path46.join(guideDir, target));
5370
+ const resolved = path47.normalize(path47.join(guideDir, target));
5324
5371
  if (!existsSync3(resolved)) {
5325
5372
  context.report({
5326
5373
  node: link,
@@ -5870,11 +5917,11 @@ var themeVariableNamespaceRule = {
5870
5917
 
5871
5918
  // eslint/rules/tailwind/css-entry-point.ts
5872
5919
  import { statSync as statSync6 } from "fs";
5873
- import path49 from "path";
5920
+ import path50 from "path";
5874
5921
 
5875
5922
  // eslint/rules/tailwind/source-files.ts
5876
5923
  import { readdirSync as readdirSync4, readFileSync as readFileSync8, statSync as statSync5 } from "fs";
5877
- import path47 from "path";
5924
+ import path48 from "path";
5878
5925
  var CSS_EXTENSIONS = [".css"];
5879
5926
  var MODULE_EXTENSIONS3 = [".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs"];
5880
5927
  var SOURCE_EXTENSIONS = [...MODULE_EXTENSIONS3, ...CSS_EXTENSIONS];
@@ -5887,7 +5934,7 @@ function findFiles(dir, extensions) {
5887
5934
  }
5888
5935
  return entries.flatMap((entry) => {
5889
5936
  if (entry.startsWith(".") || entry === "node_modules") return [];
5890
- const entryPath = path47.join(dir, entry);
5937
+ const entryPath = path48.join(dir, entry);
5891
5938
  let stats;
5892
5939
  try {
5893
5940
  stats = statSync5(entryPath);
@@ -5895,7 +5942,7 @@ function findFiles(dir, extensions) {
5895
5942
  return [];
5896
5943
  }
5897
5944
  if (stats.isDirectory()) return findFiles(entryPath, extensions);
5898
- return extensions.includes(path47.extname(entry)) ? [entryPath] : [];
5945
+ return extensions.includes(path48.extname(entry)) ? [entryPath] : [];
5899
5946
  });
5900
5947
  }
5901
5948
  function cachedTextReader() {
@@ -5918,7 +5965,7 @@ function escapeRegExp(text) {
5918
5965
  }
5919
5966
 
5920
5967
  // eslint/rules/tailwind/stylesheet-graph.ts
5921
- import path48 from "path";
5968
+ import path49 from "path";
5922
5969
  function registersTailwind(text) {
5923
5970
  return /@import\s+(?:url\(\s*)?["']tailwindcss["']\s*\)?/i.test(text);
5924
5971
  }
@@ -5932,25 +5979,25 @@ function moduleImports(text, fileName) {
5932
5979
  return new RegExp(`(?:import|require)\\s*\\(?\\s*["'][^"']*${escaped}["']`, "i").test(text);
5933
5980
  }
5934
5981
  function resolveSpecifier2(fromFile, spec, sourceRoot) {
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));
5982
+ if (spec.startsWith("/")) return path49.resolve(spec);
5983
+ if (spec.startsWith("./") || spec.startsWith("../")) return path49.resolve(path49.dirname(fromFile), spec);
5984
+ if (spec.startsWith("@/")) return path49.resolve(sourceRoot, spec.slice(2));
5938
5985
  return void 0;
5939
5986
  }
5940
5987
  function buildStylesheetGraph(options) {
5941
5988
  const { cssFiles, sourceRoot, textOf } = options;
5942
- const cssSet = new Set(cssFiles.map((file) => path48.normalize(file)));
5989
+ const cssSet = new Set(cssFiles.map((file) => path49.normalize(file)));
5943
5990
  const globals = cssFiles.filter((file) => registersTailwind(textOf(file)));
5944
5991
  const reachable = /* @__PURE__ */ new Set();
5945
5992
  const queue = [...globals];
5946
- for (const global of globals) reachable.add(path48.normalize(global));
5993
+ for (const global of globals) reachable.add(path49.normalize(global));
5947
5994
  while (queue.length > 0) {
5948
5995
  const from = queue.shift();
5949
5996
  if (!from) continue;
5950
5997
  for (const spec of importedSpecifiers(textOf(from))) {
5951
5998
  const target = resolveSpecifier2(from, spec, sourceRoot);
5952
5999
  if (!target) continue;
5953
- const normalized = path48.normalize(target);
6000
+ const normalized = path49.normalize(target);
5954
6001
  if (cssSet.has(normalized) && !reachable.has(normalized)) {
5955
6002
  reachable.add(normalized);
5956
6003
  queue.push(normalized);
@@ -5962,7 +6009,7 @@ function buildStylesheetGraph(options) {
5962
6009
  for (const spec of importedSpecifiers(textOf(global))) {
5963
6010
  const target = resolveSpecifier2(global, spec, sourceRoot);
5964
6011
  if (!target) continue;
5965
- const normalized = path48.normalize(target);
6012
+ const normalized = path49.normalize(target);
5966
6013
  if (cssSet.has(normalized)) directChildren.add(normalized);
5967
6014
  }
5968
6015
  }
@@ -5995,7 +6042,7 @@ var cssEntryPointRule = {
5995
6042
  return {
5996
6043
  "StyleSheet:exit"(node) {
5997
6044
  if (globals.length === 0) return;
5998
- const current = path49.normalize(path49.resolve(context.filename));
6045
+ const current = path50.normalize(path50.resolve(context.filename));
5999
6046
  if (globals.includes(current)) {
6000
6047
  if (globals.length > 1) {
6001
6048
  context.report({
@@ -6004,7 +6051,7 @@ var cssEntryPointRule = {
6004
6051
  });
6005
6052
  return;
6006
6053
  }
6007
- const basename = path49.basename(current);
6054
+ const basename = path50.basename(current);
6008
6055
  const importCount = moduleFiles.filter((modulePath) => moduleImports(textOf(modulePath), basename)).length;
6009
6056
  if (importCount !== 1) {
6010
6057
  context.report({
@@ -6333,7 +6380,7 @@ var nextjsStackRule = {
6333
6380
 
6334
6381
  // eslint/rules/package-json/vitest-coverage.ts
6335
6382
  import { existsSync as existsSync4, readFileSync as readFileSync9 } from "fs";
6336
- import path50 from "path";
6383
+ import path51 from "path";
6337
6384
  function memberName4(member) {
6338
6385
  return member.name.type === "String" ? member.name.value : member.name.name;
6339
6386
  }
@@ -6402,7 +6449,7 @@ var vitestCoverageRule = {
6402
6449
  message: 'package.json must declare a "test:unit:coverage" script that runs Vitest with coverage.'
6403
6450
  });
6404
6451
  }
6405
- const configName = VITEST_CONFIG_NAMES.find((name) => existsSync4(path50.join(context.cwd, name)));
6452
+ const configName = VITEST_CONFIG_NAMES.find((name) => existsSync4(path51.join(context.cwd, name)));
6406
6453
  if (!configName) {
6407
6454
  context.report({
6408
6455
  node,
@@ -6410,7 +6457,7 @@ var vitestCoverageRule = {
6410
6457
  });
6411
6458
  return;
6412
6459
  }
6413
- const content = readFileSync9(path50.join(context.cwd, configName), "utf8");
6460
+ const content = readFileSync9(path51.join(context.cwd, configName), "utf8");
6414
6461
  for (const metric of THRESHOLD_METRICS) {
6415
6462
  if (!new RegExp(`\\b${metric}\\s*:\\s*[1-9]\\d*`).test(content)) {
6416
6463
  context.report({ node, message: `${configName} must set a coverage threshold above zero for ${metric}.` });
@@ -6457,7 +6504,7 @@ var nextjsPackageJsonRules = {
6457
6504
 
6458
6505
  // eslint/rules/husky/husky-hook.ts
6459
6506
  import { existsSync as existsSync5, readFileSync as readFileSync10 } from "fs";
6460
- import path51 from "path";
6507
+ import path52 from "path";
6461
6508
  var VITEST_CONFIG_NAMES2 = [
6462
6509
  "vitest.config.ts",
6463
6510
  "vitest.config.mts",
@@ -6483,7 +6530,7 @@ var huskyHookRule = {
6483
6530
  const root = node.body;
6484
6531
  if (root.type !== "Object") return;
6485
6532
  if (!context.filename.endsWith("package.json")) return;
6486
- const hookPath = path51.join(context.cwd, ".husky", "pre-commit");
6533
+ const hookPath = path52.join(context.cwd, ".husky", "pre-commit");
6487
6534
  if (!existsSync5(hookPath)) {
6488
6535
  context.report({
6489
6536
  node,
@@ -6507,7 +6554,7 @@ var huskyHookRule = {
6507
6554
  }
6508
6555
  requireNamedScript("typecheck");
6509
6556
  requireNamedScript("test:unit:coverage");
6510
- const vitestConfigName = VITEST_CONFIG_NAMES2.find((name) => existsSync5(path51.join(context.cwd, name)));
6557
+ const vitestConfigName = VITEST_CONFIG_NAMES2.find((name) => existsSync5(path52.join(context.cwd, name)));
6511
6558
  if (vitestConfigName !== void 0) {
6512
6559
  const coverageIndex = content.indexOf("npm run test:unit:coverage");
6513
6560
  const localAddIndex = content.indexOf(`git add ${vitestConfigName}`);
@@ -6521,7 +6568,7 @@ var huskyHookRule = {
6521
6568
  if (!content.includes("libyear --limit-major-individual=1")) {
6522
6569
  context.report({ node, message: ".husky/pre-commit must run npx libyear --limit-major-individual=1." });
6523
6570
  }
6524
- const suppressionsPath = path51.join(context.cwd, "eslint-suppressions.json");
6571
+ const suppressionsPath = path52.join(context.cwd, "eslint-suppressions.json");
6525
6572
  if (existsSync5(suppressionsPath)) {
6526
6573
  requireNamedScript("lint:prune");
6527
6574
  const pruneIndex = content.indexOf("npm run lint:prune");
@@ -6594,7 +6641,7 @@ var vulykDependencyRule = {
6594
6641
 
6595
6642
  // eslint/rules/vulyk/vulyk-docs.ts
6596
6643
  import { existsSync as existsSync6, readFileSync as readFileSync11 } from "fs";
6597
- import path52 from "path";
6644
+ import path53 from "path";
6598
6645
  var PASIKA_REPO = "Bredansky/pasika";
6599
6646
  var BASE_REQUIRED_DOCS = [
6600
6647
  { name: "documentation-guide", path: "docs/documentation-guide" },
@@ -6627,8 +6674,8 @@ var vulykDocsRule = {
6627
6674
  if (!context.filename.endsWith("package.json")) return;
6628
6675
  const root = node.body;
6629
6676
  if (root.type !== "Object") return;
6630
- const projectRoot = path52.dirname(path52.resolve(context.filename));
6631
- const configPath = path52.join(projectRoot, "vulyk.config.ts");
6677
+ const projectRoot = path53.dirname(path53.resolve(context.filename));
6678
+ const configPath = path53.join(projectRoot, "vulyk.config.ts");
6632
6679
  if (!existsSync6(configPath)) {
6633
6680
  context.report({
6634
6681
  node,
@@ -6653,7 +6700,7 @@ var vulykDocsRule = {
6653
6700
  });
6654
6701
  }
6655
6702
  }
6656
- const agentsPath = path52.join(projectRoot, "AGENTS.md");
6703
+ const agentsPath = path53.join(projectRoot, "AGENTS.md");
6657
6704
  if (!existsSync6(agentsPath)) {
6658
6705
  context.report({
6659
6706
  node,
@@ -6686,6 +6733,7 @@ var pasikaNextjsAppRules = {
6686
6733
  "config-extraction": configExtractionRule,
6687
6734
  "value-extraction": valueExtractionRule,
6688
6735
  "constant-casing": constantCasingRule,
6736
+ "prefer-enum": preferEnumRule,
6689
6737
  "type-extraction": typeExtractionRule,
6690
6738
  "zod-schema-validation": zodSchemaValidationRule,
6691
6739
  "schema-casing": schemaCasingRule,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pasika",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "description": "Reusable agent setup package",
5
5
  "repository": {
6
6
  "type": "git",