pasika 0.3.6 → 0.3.8

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.
@@ -1,7 +1,7 @@
1
- // eslint/pasika/rules/filename-case.ts
1
+ // eslint/rules/filename-case.ts
2
2
  import path2 from "path";
3
3
 
4
- // eslint/pasika/rules/component-conventions.ts
4
+ // eslint/rules/component-conventions.ts
5
5
  import path from "path";
6
6
  import ts from "typescript";
7
7
  var isPascalCase = (name) => /^[A-Z][A-Za-z0-9]*$/.test(name);
@@ -128,7 +128,7 @@ function getTestId(root) {
128
128
  return { value: value.text, attribute };
129
129
  }
130
130
 
131
- // eslint/pasika/rules/filename-case.ts
131
+ // eslint/rules/filename-case.ts
132
132
  var NEXT_ROUTING_FILES = /* @__PURE__ */ new Set([
133
133
  "page",
134
134
  "layout",
@@ -221,7 +221,7 @@ function report(context, filename, ext) {
221
221
  };
222
222
  }
223
223
 
224
- // eslint/pasika/rules/import-boundaries.ts
224
+ // eslint/rules/import-boundaries.ts
225
225
  import path3 from "path";
226
226
  var sourceRoot = path3.resolve("src");
227
227
  var rootSupportFolders = /* @__PURE__ */ new Set(["config", "constants", "hooks", "locales", "schemas", "types", "utils"]);
@@ -344,7 +344,7 @@ var importBoundariesRule = {
344
344
  }
345
345
  };
346
346
 
347
- // eslint/pasika/rules/no-mixed-concerns.ts
347
+ // eslint/rules/no-mixed-concerns.ts
348
348
  function getExportName(declaration) {
349
349
  if (declaration?.type === "FunctionDeclaration" && declaration.id) {
350
350
  return declaration.id.name ?? null;
@@ -404,7 +404,7 @@ var noMixedConcernsRule = {
404
404
  }
405
405
  };
406
406
 
407
- // eslint/pasika/rules/no-arbitrary-tailwind.ts
407
+ // eslint/rules/no-arbitrary-tailwind.ts
408
408
  var ARBITRARY_VALUE_RE = /(?:^|(?<=\s))(?:[a-z]+(?:-[a-z]+)*)-\[[^\]]+\](?![-\w]*:)/g;
409
409
  var CLASS_HELPERS = /* @__PURE__ */ new Set(["cn", "clsx", "twMerge", "twJoin"]);
410
410
  var noArbitraryTailwindRule = {
@@ -473,7 +473,7 @@ var noArbitraryTailwindRule = {
473
473
  }
474
474
  };
475
475
 
476
- // eslint/pasika/rules/enforce-cn-merge.ts
476
+ // eslint/rules/enforce-cn-merge.ts
477
477
  function classCount(str) {
478
478
  return str.split(/\s+/).filter(Boolean).length;
479
479
  }
@@ -547,7 +547,7 @@ var enforceCnMergeRule = {
547
547
  }
548
548
  };
549
549
 
550
- // eslint/pasika/rules/enforce-cva-variant-props.ts
550
+ // eslint/rules/enforce-cva-variant-props.ts
551
551
  var enforceCvaVariantPropsRule = {
552
552
  meta: {
553
553
  schema: [],
@@ -610,7 +610,7 @@ var enforceCvaVariantPropsRule = {
610
610
  }
611
611
  };
612
612
 
613
- // eslint/pasika/rules/enforce-barrel-exports.ts
613
+ // eslint/rules/enforce-barrel-exports.ts
614
614
  import path4 from "path";
615
615
  import fs from "fs";
616
616
  function isPascalCase3(str) {
@@ -672,14 +672,14 @@ var enforceBarrelExportsRule = {
672
672
  }
673
673
  };
674
674
 
675
- // eslint/pasika/rules/component-placement.ts
675
+ // eslint/rules/component-placement.ts
676
676
  import path8 from "path";
677
677
 
678
- // eslint/pasika/project/index.ts
678
+ // eslint/project/index.ts
679
679
  import { readdirSync, statSync } from "fs";
680
680
  import path6 from "path";
681
681
 
682
- // eslint/pasika/project/parse-module.ts
682
+ // eslint/project/parse-module.ts
683
683
  import path5 from "path";
684
684
  import { readFileSync } from "fs";
685
685
  import ts2 from "typescript";
@@ -784,7 +784,7 @@ function parseModule(file) {
784
784
  return { file: path5.resolve(file), imports, exports };
785
785
  }
786
786
 
787
- // eslint/pasika/project/index.ts
787
+ // eslint/project/index.ts
788
788
  var MODULE_EXTENSIONS = [".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs"];
789
789
  var INDEX_BASENAMES = ["index.ts", "index.tsx", "index.mts", "index.cts", "index.js", "index.jsx"];
790
790
  var REVALIDATE_AFTER_MS = 2e3;
@@ -890,7 +890,7 @@ function getProjectIndex(sourceRoot2) {
890
890
  return index;
891
891
  }
892
892
 
893
- // eslint/pasika/project/ccf.ts
893
+ // eslint/project/ccf.ts
894
894
  import path7 from "path";
895
895
  var SUPPORT_FOLDERS2 = /* @__PURE__ */ new Set(["hooks", "types", "schemas", "constants", "utils"]);
896
896
  function segmentsOf(file, sourceRoot2) {
@@ -979,7 +979,7 @@ function describeConsumers(consumers, sourceRoot2) {
979
979
  return `${names.slice(0, shown).join(", ")} and ${String(names.length - shown)} more`;
980
980
  }
981
981
 
982
- // eslint/pasika/rules/component-placement.ts
982
+ // eslint/rules/component-placement.ts
983
983
  var REASON_TEXT = {
984
984
  ccf: "that is the closest folder its consumers share",
985
985
  "across-features": "its consumers span more than one feature, and no feature may import from another",
@@ -1032,7 +1032,7 @@ var componentPlacementRule = {
1032
1032
  }
1033
1033
  };
1034
1034
 
1035
- // eslint/pasika/rules/support-file-placement.ts
1035
+ // eslint/rules/support-file-placement.ts
1036
1036
  import path9 from "path";
1037
1037
  var CONFIG_OWNED_FOLDERS = /* @__PURE__ */ new Set(["types", "constants"]);
1038
1038
  var REASON_TEXT2 = {
@@ -1076,7 +1076,7 @@ var supportFilePlacementRule = {
1076
1076
  }
1077
1077
  };
1078
1078
 
1079
- // eslint/pasika/rules/application-structure.ts
1079
+ // eslint/rules/application-structure.ts
1080
1080
  import fs2 from "fs";
1081
1081
  import path10 from "path";
1082
1082
  var MODULE_EXTENSIONS2 = /* @__PURE__ */ new Set([".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs"]);
@@ -1260,7 +1260,7 @@ var applicationStructureRule = {
1260
1260
  }
1261
1261
  };
1262
1262
 
1263
- // eslint/pasika/rules/named-exports.ts
1263
+ // eslint/rules/named-exports.ts
1264
1264
  import path11 from "path";
1265
1265
  var FRAMEWORK_DEFAULT_EXPORT_FILES = /* @__PURE__ */ new Set([
1266
1266
  "default",
@@ -1299,7 +1299,7 @@ var namedExportsRule = {
1299
1299
  }
1300
1300
  };
1301
1301
 
1302
- // eslint/pasika/rules/data-testid-case.ts
1302
+ // eslint/rules/data-testid-case.ts
1303
1303
  import path12 from "path";
1304
1304
  var NEXT_ROUTING_FILES2 = /* @__PURE__ */ new Set([
1305
1305
  "page",
@@ -1366,7 +1366,7 @@ function toKebabCase(value) {
1366
1366
  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();
1367
1367
  }
1368
1368
 
1369
- // eslint/pasika/rules/support-folder-shape.ts
1369
+ // eslint/rules/support-folder-shape.ts
1370
1370
  import fs3 from "fs";
1371
1371
  import path13 from "path";
1372
1372
  var SUPPORT_FOLDERS3 = /* @__PURE__ */ new Set(["constants", "types", "schemas"]);
@@ -1419,7 +1419,7 @@ var supportFolderShapeRule = {
1419
1419
  }
1420
1420
  };
1421
1421
 
1422
- // eslint/pasika/rules/import-through-index.ts
1422
+ // eslint/rules/import-through-index.ts
1423
1423
  import path14 from "path";
1424
1424
  var importThroughIndexRule = {
1425
1425
  meta: {
@@ -1469,7 +1469,7 @@ function sourceRootOf(filename) {
1469
1469
  return srcIndex >= 0 ? filename.slice(0, srcIndex + marker.length - 1) : path14.resolve("src");
1470
1470
  }
1471
1471
 
1472
- // eslint/pasika/rules/util-file-name.ts
1472
+ // eslint/rules/util-file-name.ts
1473
1473
  import path15 from "path";
1474
1474
  function toKebabCase2(value) {
1475
1475
  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();
@@ -1510,7 +1510,7 @@ var utilFileNameRule = {
1510
1510
  }
1511
1511
  };
1512
1512
 
1513
- // eslint/pasika/rules/no-util-barrel.ts
1513
+ // eslint/rules/no-util-barrel.ts
1514
1514
  import path16 from "path";
1515
1515
  var noUtilBarrelRule = {
1516
1516
  meta: {
@@ -1555,7 +1555,7 @@ function sourceRootOf2(filename) {
1555
1555
  return srcIndex >= 0 ? filename.slice(0, srcIndex + marker.length - 1) : path16.resolve("src");
1556
1556
  }
1557
1557
 
1558
- // eslint/pasika/rules/jsx-hygiene.ts
1558
+ // eslint/rules/jsx-hygiene.ts
1559
1559
  import ts3 from "typescript";
1560
1560
  var ARITHMETIC_OPERATORS = /* @__PURE__ */ new Set(["+", "-", "*", "/", "%"]);
1561
1561
  function isCallExpression(node) {
@@ -1644,7 +1644,7 @@ var jsxHygieneRule = {
1644
1644
  }
1645
1645
  };
1646
1646
 
1647
- // eslint/pasika/rules/interactive-component.ts
1647
+ // eslint/rules/interactive-component.ts
1648
1648
  var INTERACTIVE_TAGS = /* @__PURE__ */ new Set([
1649
1649
  "a",
1650
1650
  "button",
@@ -1708,7 +1708,7 @@ var interactiveComponentRule = {
1708
1708
  }
1709
1709
  };
1710
1710
 
1711
- // eslint/pasika/rules/ui-state.ts
1711
+ // eslint/rules/ui-state.ts
1712
1712
  var STATE_PROPS = /* @__PURE__ */ new Set([
1713
1713
  "disabled",
1714
1714
  "loading",
@@ -1795,7 +1795,7 @@ var uiStateRule = {
1795
1795
  }
1796
1796
  };
1797
1797
 
1798
- // eslint/pasika/rules/cva-appearance-props.ts
1798
+ // eslint/rules/cva-appearance-props.ts
1799
1799
  var VISUAL_OPTION_NAMES = /* @__PURE__ */ new Set([
1800
1800
  "size",
1801
1801
  "variant",
@@ -1853,7 +1853,7 @@ var cvaAppearancePropsRule = {
1853
1853
  }
1854
1854
  };
1855
1855
 
1856
- // eslint/pasika/rules/cva-boolean-variants.ts
1856
+ // eslint/rules/cva-boolean-variants.ts
1857
1857
  function extractCvaInfo(node) {
1858
1858
  if (node.callee.type !== "Identifier" || node.callee.name !== "cva") {
1859
1859
  return void 0;
@@ -1927,7 +1927,7 @@ var cvaBooleanVariantsRule = {
1927
1927
  }
1928
1928
  };
1929
1929
 
1930
- // eslint/pasika/rules/cross-feature-import.ts
1930
+ // eslint/rules/cross-feature-import.ts
1931
1931
  import path17 from "path";
1932
1932
  var FEATURES_SEGMENT = "features";
1933
1933
  function featureNameOf(resolvedPath, sourceRoot2) {
@@ -1985,7 +1985,7 @@ var crossFeatureImportRule = {
1985
1985
  }
1986
1986
  };
1987
1987
 
1988
- // eslint/pasika/rules/pure-function-extract.ts
1988
+ // eslint/rules/pure-function-extract.ts
1989
1989
  import path18 from "path";
1990
1990
  function isComponentLikeName(name) {
1991
1991
  return /^[A-Z]/.test(name);
@@ -2056,7 +2056,7 @@ var pureFunctionExtractRule = {
2056
2056
  }
2057
2057
  };
2058
2058
 
2059
- // eslint/pasika/rules/hook-complexity.ts
2059
+ // eslint/rules/hook-complexity.ts
2060
2060
  import path19 from "path";
2061
2061
  import ts4 from "typescript";
2062
2062
  var REACT_HOOKS = /* @__PURE__ */ new Set([
@@ -2153,7 +2153,7 @@ var hookComplexityRule = {
2153
2153
  }
2154
2154
  };
2155
2155
 
2156
- // eslint/pasika/rules/locale-dotted-path.ts
2156
+ // eslint/rules/locale-dotted-path.ts
2157
2157
  import path20 from "path";
2158
2158
  function isInLocalesDir(filename) {
2159
2159
  const segments = path20.resolve(filename).split(path20.sep);
@@ -2204,7 +2204,7 @@ var localeDottedPathRule = {
2204
2204
  }
2205
2205
  };
2206
2206
 
2207
- // eslint/pasika/rules/locales-location.ts
2207
+ // eslint/rules/locales-location.ts
2208
2208
  import path21 from "path";
2209
2209
  function isLocalesFile(filename) {
2210
2210
  const segments = path21.resolve(filename).split(path21.sep);
@@ -2247,7 +2247,7 @@ var localesLocationRule = {
2247
2247
  }
2248
2248
  };
2249
2249
 
2250
- // eslint/pasika/rules/hook-extraction.ts
2250
+ // eslint/rules/hook-extraction.ts
2251
2251
  import path22 from "path";
2252
2252
  var hookExtractionRule = {
2253
2253
  meta: {
@@ -2284,7 +2284,7 @@ var hookExtractionRule = {
2284
2284
  }
2285
2285
  };
2286
2286
 
2287
- // eslint/pasika/rules/value-extraction.ts
2287
+ // eslint/rules/value-extraction.ts
2288
2288
  import path23 from "path";
2289
2289
  var valueExtractionRule = {
2290
2290
  meta: {
@@ -2316,7 +2316,7 @@ var valueExtractionRule = {
2316
2316
  }
2317
2317
  };
2318
2318
 
2319
- // eslint/pasika/rules/config-extraction.ts
2319
+ // eslint/rules/config-extraction.ts
2320
2320
  import path24 from "path";
2321
2321
  var configExtractionRule = {
2322
2322
  meta: {
@@ -2365,7 +2365,7 @@ var configExtractionRule = {
2365
2365
  }
2366
2366
  };
2367
2367
 
2368
- // eslint/pasika/rules/component-nesting.ts
2368
+ // eslint/rules/component-nesting.ts
2369
2369
  import path25 from "path";
2370
2370
  var componentNestingRule = {
2371
2371
  meta: {
@@ -2409,7 +2409,7 @@ var componentNestingRule = {
2409
2409
  }
2410
2410
  };
2411
2411
 
2412
- // eslint/pasika/rules/stay-flat.ts
2412
+ // eslint/rules/stay-flat.ts
2413
2413
  import path26 from "path";
2414
2414
  var stayFlatRule = {
2415
2415
  meta: {
@@ -2460,7 +2460,7 @@ var stayFlatRule = {
2460
2460
  }
2461
2461
  };
2462
2462
 
2463
- // eslint/pasika/rules/type-extraction.ts
2463
+ // eslint/rules/type-extraction.ts
2464
2464
  import path27 from "path";
2465
2465
  var typeExtractionRule = {
2466
2466
  meta: {
@@ -2517,7 +2517,7 @@ var typeExtractionRule = {
2517
2517
  }
2518
2518
  };
2519
2519
 
2520
- // eslint/pasika/rules/locale-placement.ts
2520
+ // eslint/rules/locale-placement.ts
2521
2521
  import path28 from "path";
2522
2522
  import { readFileSync as readFileSync2 } from "fs";
2523
2523
  import ts5 from "typescript";
@@ -2643,7 +2643,7 @@ var localePlacementRule = {
2643
2643
  }
2644
2644
  };
2645
2645
 
2646
- // eslint/pasika/rules/sole-state-owner.ts
2646
+ // eslint/rules/sole-state-owner.ts
2647
2647
  import path29 from "path";
2648
2648
  import ts6 from "typescript";
2649
2649
  function findStateHooks(node) {
@@ -2802,7 +2802,7 @@ function usesOutsideJsx(declaration, hook, children) {
2802
2802
  return outside;
2803
2803
  }
2804
2804
 
2805
- // eslint/pasika/rules/locale-key-shape.ts
2805
+ // eslint/rules/locale-key-shape.ts
2806
2806
  import path30 from "path";
2807
2807
  var MAX_KEY_LENGTH = 30;
2808
2808
  var ROLE_POSTFIXES = /* @__PURE__ */ new Set([
@@ -2914,7 +2914,7 @@ var localeKeyShapeRule = {
2914
2914
  }
2915
2915
  };
2916
2916
 
2917
- // eslint/pasika/rules/shared-style-dedup.ts
2917
+ // eslint/rules/shared-style-dedup.ts
2918
2918
  import path31 from "path";
2919
2919
  import { readFileSync as readFileSync3, statSync as statSync2 } from "fs";
2920
2920
  var CLASS_NAME = /className="(?<classes>[^"]+)"/g;
@@ -2979,7 +2979,7 @@ var sharedStyleDedupRule = {
2979
2979
  }
2980
2980
  };
2981
2981
 
2982
- // eslint/pasika/rules/repeated-structure.ts
2982
+ // eslint/rules/repeated-structure.ts
2983
2983
  function nodeKind(node) {
2984
2984
  return node.type;
2985
2985
  }
@@ -3087,7 +3087,7 @@ var repeatedStructureRule = {
3087
3087
  }
3088
3088
  };
3089
3089
 
3090
- // eslint/pasika/rules/zod-schema-validation.ts
3090
+ // eslint/rules/zod-schema-validation.ts
3091
3091
  var NON_SCHEMA_OBJECTS = /* @__PURE__ */ new Set(["JSON", "Date", "Number"]);
3092
3092
  var SCHEMA_METHODS = /* @__PURE__ */ new Set(["safeParse", "parse", "assert"]);
3093
3093
  function isRecord(value) {
@@ -3143,7 +3143,7 @@ var zodSchemaValidationRule = {
3143
3143
  if (delegatesToSchema(node.body)) return;
3144
3144
  context.report({
3145
3145
  loc: node.loc ?? { line: 1, column: 0 },
3146
- message: "This hand-written type guard validates an unknown value ad hoc. Use a Zod schema instead: schema.safeParse(value) returns a discriminated result whose .success narrows the type. See docs/agent-policy.md"
3146
+ message: "This hand-written type guard validates an unknown value ad hoc. Use a Zod schema instead: schema.safeParse(value) returns a discriminated result whose .success narrows the type. See docs/repository-policy.md"
3147
3147
  });
3148
3148
  }
3149
3149
  return {
@@ -3160,7 +3160,7 @@ var zodSchemaValidationRule = {
3160
3160
  }
3161
3161
  };
3162
3162
 
3163
- // eslint/pasika/rules/source-under-src.ts
3163
+ // eslint/rules/source-under-src.ts
3164
3164
  import path32 from "path";
3165
3165
  var NON_SOURCE_ROOT_DIRS = /* @__PURE__ */ new Set([
3166
3166
  ".agents",
@@ -3180,8 +3180,8 @@ var NON_SOURCE_ROOT_DIRS = /* @__PURE__ */ new Set([
3180
3180
  "coverage",
3181
3181
  "dist",
3182
3182
  "docs",
3183
- "enforcement",
3184
3183
  "eslint",
3184
+ "scripts",
3185
3185
  "node_modules",
3186
3186
  "public",
3187
3187
  "static",
@@ -3224,7 +3224,45 @@ var sourceUnderSrcRule = {
3224
3224
  }
3225
3225
  };
3226
3226
 
3227
- // eslint/pasika/rules/md/helpers.ts
3227
+ // eslint/rules/config-baseline.ts
3228
+ import fs4 from "fs";
3229
+ import path33 from "path";
3230
+ var configBaselineRule = {
3231
+ meta: {
3232
+ schema: [],
3233
+ type: "problem",
3234
+ docs: {
3235
+ description: "Require eslint config to reference zirka and tsconfig.json to exist."
3236
+ }
3237
+ },
3238
+ create(context) {
3239
+ const filename = path33.resolve(context.filename);
3240
+ const basename = path33.basename(filename);
3241
+ if (!/^eslint\.config\.(?:ts|mts|cts|js|mjs|cjs)$/.test(basename)) return {};
3242
+ return {
3243
+ Program(node) {
3244
+ const content = context.sourceCode.getText();
3245
+ if (!content.includes("zirka")) {
3246
+ context.report({
3247
+ node,
3248
+ loc: { line: 1, column: 0 },
3249
+ message: "ESLint config must reference zirka. Use the pasika/zirka baseline configuration."
3250
+ });
3251
+ }
3252
+ const projectRoot = path33.dirname(filename);
3253
+ if (!fs4.existsSync(path33.join(projectRoot, "tsconfig.json"))) {
3254
+ context.report({
3255
+ node,
3256
+ loc: { line: 1, column: 0 },
3257
+ message: "No tsconfig.json found. Create one extending the pasika baseline."
3258
+ });
3259
+ }
3260
+ }
3261
+ };
3262
+ }
3263
+ };
3264
+
3265
+ // eslint/rules/md/helpers.ts
3228
3266
  var RFC_PATTERN = /\b(?<keyword>MUST NOT|MUST|SHALL NOT|SHALL|SHOULD NOT|SHOULD|MAY|RECOMMENDED|NOT RECOMMENDED|OPTIONAL|REQUIRED)\b/;
3229
3267
  function containsRfcKeyword(text) {
3230
3268
  const match = RFC_PATTERN.exec(text);
@@ -3244,7 +3282,7 @@ function getLine(node) {
3244
3282
  return node.position?.start.line ?? 0;
3245
3283
  }
3246
3284
 
3247
- // eslint/pasika/rules/md/doc-kind-suffix.ts
3285
+ // eslint/rules/md/doc-kind-suffix.ts
3248
3286
  var docKindSuffixRule = {
3249
3287
  meta: {
3250
3288
  type: "problem",
@@ -3270,8 +3308,8 @@ var docKindSuffixRule = {
3270
3308
  }
3271
3309
  };
3272
3310
 
3273
- // eslint/pasika/rules/md/title-matches-file-name.ts
3274
- import path33 from "path";
3311
+ // eslint/rules/md/title-matches-file-name.ts
3312
+ import path34 from "path";
3275
3313
  function toExpectedFileName(title) {
3276
3314
  return `${title.toLowerCase().replaceAll(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "")}.md`;
3277
3315
  }
@@ -3291,7 +3329,7 @@ var titleMatchesFileNameRule = {
3291
3329
  if (!filename.endsWith(".md")) return;
3292
3330
  const title = getTextContent(node).trim();
3293
3331
  const expectedFileName = toExpectedFileName(title);
3294
- const actualFileName = path33.basename(filename);
3332
+ const actualFileName = path34.basename(filename);
3295
3333
  if (!title) {
3296
3334
  context.report({
3297
3335
  node,
@@ -3308,7 +3346,7 @@ var titleMatchesFileNameRule = {
3308
3346
  }
3309
3347
  };
3310
3348
 
3311
- // eslint/pasika/rules/md/overview-present.ts
3349
+ // eslint/rules/md/overview-present.ts
3312
3350
  var overviewPresentRule = {
3313
3351
  meta: {
3314
3352
  type: "problem",
@@ -3348,7 +3386,7 @@ var overviewPresentRule = {
3348
3386
  }
3349
3387
  };
3350
3388
 
3351
- // eslint/pasika/rules/md/overview-length.ts
3389
+ // eslint/rules/md/overview-length.ts
3352
3390
  function countSentences(text) {
3353
3391
  return text.split(/[.!?](?:\s+|$)/).filter((part) => part.trim() !== "").length;
3354
3392
  }
@@ -3391,7 +3429,7 @@ var overviewLengthRule = {
3391
3429
  }
3392
3430
  };
3393
3431
 
3394
- // eslint/pasika/rules/md/guide-overview-no-links.ts
3432
+ // eslint/rules/md/guide-overview-no-links.ts
3395
3433
  function containsLink(node) {
3396
3434
  if (node.type === "link") return true;
3397
3435
  if ("children" in node) {
@@ -3437,7 +3475,7 @@ var guideOverviewNoLinksRule = {
3437
3475
  }
3438
3476
  };
3439
3477
 
3440
- // eslint/pasika/rules/md/guide-step-single-sentence.ts
3478
+ // eslint/rules/md/guide-step-single-sentence.ts
3441
3479
  function countSentences2(text) {
3442
3480
  return text.split(/[.!?](?:\s+|$)/).filter((part) => part.trim() !== "").length;
3443
3481
  }
@@ -3475,7 +3513,7 @@ var guideStepSingleSentenceRule = {
3475
3513
  }
3476
3514
  };
3477
3515
 
3478
- // eslint/pasika/rules/md/guide-step-single-link.ts
3516
+ // eslint/rules/md/guide-step-single-link.ts
3479
3517
  function countDocLinks(node) {
3480
3518
  if (node.type === "link" && node.url.endsWith(".md")) return 1;
3481
3519
  if ("children" in node) {
@@ -3518,7 +3556,7 @@ var guideStepSingleLinkRule = {
3518
3556
  }
3519
3557
  };
3520
3558
 
3521
- // eslint/pasika/rules/md/guide-states-no-requirement.ts
3559
+ // eslint/rules/md/guide-states-no-requirement.ts
3522
3560
  var guideStatesNoRequirementRule = {
3523
3561
  meta: {
3524
3562
  type: "problem",
@@ -3544,7 +3582,7 @@ var guideStatesNoRequirementRule = {
3544
3582
  }
3545
3583
  };
3546
3584
 
3547
- // eslint/pasika/rules/md/requirement-present.ts
3585
+ // eslint/rules/md/requirement-present.ts
3548
3586
  function hasRequirement(node) {
3549
3587
  if (node.type === "listItem") {
3550
3588
  if (containsRfcKeyword(getTextContent(node))) return true;
@@ -3583,7 +3621,7 @@ var requirementPresentRule = {
3583
3621
  }
3584
3622
  };
3585
3623
 
3586
- // eslint/pasika/rules/md/rule-paired-examples.ts
3624
+ // eslint/rules/md/rule-paired-examples.ts
3587
3625
  var rulePairedExamplesRule = {
3588
3626
  meta: {
3589
3627
  type: "problem",
@@ -3619,7 +3657,7 @@ var rulePairedExamplesRule = {
3619
3657
  }
3620
3658
  };
3621
3659
 
3622
- // eslint/pasika/rules/md/example-heading-description.ts
3660
+ // eslint/rules/md/example-heading-description.ts
3623
3661
  var exampleHeadingDescriptionRule = {
3624
3662
  meta: {
3625
3663
  type: "problem",
@@ -3647,7 +3685,7 @@ var exampleHeadingDescriptionRule = {
3647
3685
  }
3648
3686
  };
3649
3687
 
3650
- // eslint/pasika/rules/md/policy-no-examples.ts
3688
+ // eslint/rules/md/policy-no-examples.ts
3651
3689
  var policyNoExamplesRule = {
3652
3690
  meta: {
3653
3691
  type: "problem",
@@ -3674,7 +3712,7 @@ var policyNoExamplesRule = {
3674
3712
  }
3675
3713
  };
3676
3714
 
3677
- // eslint/pasika/rules/md/no-cross-document-link.ts
3715
+ // eslint/rules/md/no-cross-document-link.ts
3678
3716
  function linkedKind(filename) {
3679
3717
  if (filename.endsWith("-rule.md")) return "rule";
3680
3718
  if (filename.endsWith("-reference.md")) return "reference";
@@ -3706,7 +3744,7 @@ var noCrossDocumentLinkRule = {
3706
3744
  }
3707
3745
  };
3708
3746
 
3709
- // eslint/pasika/rules/md/reference-no-rfc-vocabulary.ts
3747
+ // eslint/rules/md/reference-no-rfc-vocabulary.ts
3710
3748
  var referenceNoRfcVocabularyRule = {
3711
3749
  meta: {
3712
3750
  type: "problem",
@@ -3732,7 +3770,7 @@ var referenceNoRfcVocabularyRule = {
3732
3770
  }
3733
3771
  };
3734
3772
 
3735
- // eslint/pasika/rules/md/reference-block-headings.ts
3773
+ // eslint/rules/md/reference-block-headings.ts
3736
3774
  var referenceBlockHeadingsRule = {
3737
3775
  meta: {
3738
3776
  type: "problem",
@@ -3763,8 +3801,8 @@ var referenceBlockHeadingsRule = {
3763
3801
  }
3764
3802
  };
3765
3803
 
3766
- // eslint/pasika/rules/md/support-document-placement.ts
3767
- import path34 from "path";
3804
+ // eslint/rules/md/support-document-placement.ts
3805
+ import path35 from "path";
3768
3806
  var supportDocumentPlacementRule = {
3769
3807
  meta: {
3770
3808
  type: "problem",
@@ -3778,7 +3816,7 @@ var supportDocumentPlacementRule = {
3778
3816
  root(node) {
3779
3817
  const filename = getFilename(context);
3780
3818
  if (!filename.endsWith(".md")) return;
3781
- const parentFolder = path34.basename(path34.dirname(filename));
3819
+ const parentFolder = path35.basename(path35.dirname(filename));
3782
3820
  if (filename.endsWith("-rule.md") && parentFolder !== "rules") {
3783
3821
  context.report({
3784
3822
  node,
@@ -3796,7 +3834,7 @@ var supportDocumentPlacementRule = {
3796
3834
  }
3797
3835
  };
3798
3836
 
3799
- // eslint/pasika/rules/md/no-template-prompt.ts
3837
+ // eslint/rules/md/no-template-prompt.ts
3800
3838
  var TEMPLATE_PROMPT = /^\s*\[[A-Z0-9].*\]\s*$/;
3801
3839
  var noTemplatePromptRule = {
3802
3840
  meta: {
@@ -3820,12 +3858,12 @@ var noTemplatePromptRule = {
3820
3858
  }
3821
3859
  };
3822
3860
 
3823
- // eslint/pasika/rules/md/guide-folder-entry-point.ts
3824
- import path36 from "path";
3861
+ // eslint/rules/md/guide-folder-entry-point.ts
3862
+ import path37 from "path";
3825
3863
 
3826
- // eslint/pasika/rules/md/project-index.ts
3864
+ // eslint/rules/md/project-index.ts
3827
3865
  import { readdirSync as readdirSync2, readFileSync as readFileSync4, statSync as statSync3 } from "fs";
3828
- import path35 from "path";
3866
+ import path36 from "path";
3829
3867
  var KIND_BY_SUFFIX = [
3830
3868
  ["-rule.md", "rule"],
3831
3869
  ["-guide.md", "guide"],
@@ -3834,7 +3872,7 @@ var KIND_BY_SUFFIX = [
3834
3872
  ];
3835
3873
  function listMarkdownFiles(dir) {
3836
3874
  return readdirSync2(dir).flatMap((entry) => {
3837
- const entryPath = path35.join(dir, entry);
3875
+ const entryPath = path36.join(dir, entry);
3838
3876
  if (statSync3(entryPath).isDirectory()) {
3839
3877
  return entry.startsWith("_") ? [] : listMarkdownFiles(entryPath);
3840
3878
  }
@@ -3852,11 +3890,11 @@ function getProjectDocs(docsRoot) {
3852
3890
  if (cached) return cached;
3853
3891
  const files = listMarkdownFiles(docsRoot);
3854
3892
  const docs = files.sort((a, b) => a.localeCompare(b)).map((filePath) => {
3855
- const fileName = path35.basename(filePath);
3893
+ const fileName = path36.basename(filePath);
3856
3894
  const kind = KIND_BY_SUFFIX.find(([suffix]) => fileName.endsWith(suffix))?.[1];
3857
3895
  return {
3858
3896
  filePath,
3859
- doc: path35.relative(docsRoot, filePath).split(path35.sep).join("/"),
3897
+ doc: path36.relative(docsRoot, filePath).split(path36.sep).join("/"),
3860
3898
  fileName,
3861
3899
  kind,
3862
3900
  title: extractTitle(filePath)
@@ -3866,18 +3904,18 @@ function getProjectDocs(docsRoot) {
3866
3904
  return docs;
3867
3905
  }
3868
3906
  function findDocsRoot(filePath) {
3869
- let dir = path35.dirname(filePath);
3907
+ let dir = path36.dirname(filePath);
3870
3908
  for (; ; ) {
3871
- if (path35.basename(dir) === "docs" && statSync3(dir).isDirectory()) {
3909
+ if (path36.basename(dir) === "docs" && statSync3(dir).isDirectory()) {
3872
3910
  return dir;
3873
3911
  }
3874
- const parent = path35.dirname(dir);
3912
+ const parent = path36.dirname(dir);
3875
3913
  if (parent === dir) return void 0;
3876
3914
  dir = parent;
3877
3915
  }
3878
3916
  }
3879
3917
 
3880
- // eslint/pasika/rules/md/guide-folder-entry-point.ts
3918
+ // eslint/rules/md/guide-folder-entry-point.ts
3881
3919
  var guideFolderEntryPointRule = {
3882
3920
  meta: {
3883
3921
  type: "problem",
@@ -3895,13 +3933,13 @@ var guideFolderEntryPointRule = {
3895
3933
  if (!docsRoot) return;
3896
3934
  const docs = getProjectDocs(docsRoot);
3897
3935
  const guideFolders = new Set(
3898
- docs.filter((doc) => ["rules", "references"].includes(path36.basename(path36.dirname(doc.filePath)))).map((doc) => path36.dirname(path36.dirname(doc.filePath))).filter((folder) => path36.resolve(folder) !== path36.resolve(docsRoot))
3936
+ docs.filter((doc) => ["rules", "references"].includes(path37.basename(path37.dirname(doc.filePath)))).map((doc) => path37.dirname(path37.dirname(doc.filePath))).filter((folder) => path37.resolve(folder) !== path37.resolve(docsRoot))
3899
3937
  );
3900
- const currentDir = path36.dirname(filename);
3938
+ const currentDir = path37.dirname(filename);
3901
3939
  if (guideFolders.has(currentDir)) {
3902
- const expectedEntryPoint = `${path36.basename(currentDir)}.md`;
3940
+ const expectedEntryPoint = `${path37.basename(currentDir)}.md`;
3903
3941
  const hasEntryPoint = docs.some(
3904
- (doc) => doc.kind === "guide" && path36.dirname(doc.filePath) === currentDir && doc.fileName === expectedEntryPoint
3942
+ (doc) => doc.kind === "guide" && path37.dirname(doc.filePath) === currentDir && doc.fileName === expectedEntryPoint
3905
3943
  );
3906
3944
  if (!hasEntryPoint) {
3907
3945
  context.report({
@@ -3915,7 +3953,7 @@ var guideFolderEntryPointRule = {
3915
3953
  }
3916
3954
  };
3917
3955
 
3918
- // eslint/pasika/rules/md/rfc-only-in-bullets.ts
3956
+ // eslint/rules/md/rfc-only-in-bullets.ts
3919
3957
  function checkOutsideBullets(node, context, insideBullet) {
3920
3958
  if (node.type === "listItem") {
3921
3959
  for (const child of node.children) {
@@ -3958,7 +3996,7 @@ var rfcOnlyInBulletsRule = {
3958
3996
  }
3959
3997
  };
3960
3998
 
3961
- // eslint/pasika/rules/md/rfc-keyword-in-every-bullet.ts
3999
+ // eslint/rules/md/rfc-keyword-in-every-bullet.ts
3962
4000
  function checkBullets(node, context) {
3963
4001
  if (node.type === "listItem" && !containsRfcKeyword(getTextContent(node))) {
3964
4002
  context.report({
@@ -3991,7 +4029,7 @@ var rfcKeywordInEveryBulletRule = {
3991
4029
  }
3992
4030
  };
3993
4031
 
3994
- // eslint/pasika/rules/md/policy-subject-headings.ts
4032
+ // eslint/rules/md/policy-subject-headings.ts
3995
4033
  var policySubjectHeadingsRule = {
3996
4034
  meta: {
3997
4035
  type: "problem",
@@ -4044,7 +4082,7 @@ var policySubjectHeadingsRule = {
4044
4082
  }
4045
4083
  };
4046
4084
 
4047
- // eslint/pasika/rules/md/guide-link-anchors.ts
4085
+ // eslint/rules/md/guide-link-anchors.ts
4048
4086
  function visitSteps2(node, check) {
4049
4087
  if (node.type === "list" && node.ordered) {
4050
4088
  for (const child of node.children) check(child);
@@ -4088,7 +4126,7 @@ var guideLinkAnchorsRule = {
4088
4126
  }
4089
4127
  };
4090
4128
 
4091
- // eslint/pasika/rules/md/no-nested-how-to.ts
4129
+ // eslint/rules/md/no-nested-how-to.ts
4092
4130
  var noNestedHowToRule = {
4093
4131
  meta: {
4094
4132
  type: "problem",
@@ -4124,9 +4162,9 @@ var noNestedHowToRule = {
4124
4162
  }
4125
4163
  };
4126
4164
 
4127
- // eslint/pasika/rules/md/glossary-term-linking.ts
4165
+ // eslint/rules/md/glossary-term-linking.ts
4128
4166
  import { readFileSync as readFileSync5 } from "fs";
4129
- import path37 from "path";
4167
+ import path38 from "path";
4130
4168
  function extractGlossaryTerms(filePath) {
4131
4169
  const content = readFileSync5(filePath, "utf8");
4132
4170
  const terms = [];
@@ -4180,9 +4218,9 @@ var glossaryTermLinkingRule = {
4180
4218
  const docsRoot = findDocsRoot(filename);
4181
4219
  if (!docsRoot) return;
4182
4220
  const docs = getProjectDocs(docsRoot);
4183
- const guideDir = path37.dirname(filename);
4221
+ const guideDir = path38.dirname(filename);
4184
4222
  const guideReferences = docs.filter(
4185
- (doc) => doc.kind === "reference" && path37.dirname(doc.filePath) === guideDir
4223
+ (doc) => doc.kind === "reference" && path38.dirname(doc.filePath) === guideDir
4186
4224
  );
4187
4225
  if (guideReferences.length === 0) return;
4188
4226
  const glossaryTerms = [];
@@ -4205,7 +4243,7 @@ var glossaryTermLinkingRule = {
4205
4243
  }
4206
4244
  };
4207
4245
 
4208
- // eslint/pasika/rules/md/index.ts
4246
+ // eslint/rules/md/index.ts
4209
4247
  var mdRules = {
4210
4248
  "doc-kind-suffix": docKindSuffixRule,
4211
4249
  "title-matches-file-name": titleMatchesFileNameRule,
@@ -4233,7 +4271,7 @@ var mdRules = {
4233
4271
  "glossary-term-linking": glossaryTermLinkingRule
4234
4272
  };
4235
4273
 
4236
- // eslint/pasika/rules/css/helpers.ts
4274
+ // eslint/rules/css/helpers.ts
4237
4275
  function walkNodes(node, visit) {
4238
4276
  visit(node);
4239
4277
  if ("children" in node && node.children) {
@@ -4290,7 +4328,7 @@ function selectorNames(node) {
4290
4328
  return names;
4291
4329
  }
4292
4330
 
4293
- // eslint/pasika/rules/css/theme-reset.ts
4331
+ // eslint/rules/css/theme-reset.ts
4294
4332
  var themeResetRule = {
4295
4333
  meta: {
4296
4334
  schema: [],
@@ -4320,7 +4358,7 @@ var themeResetRule = {
4320
4358
  }
4321
4359
  };
4322
4360
 
4323
- // eslint/pasika/rules/css/root-variables.ts
4361
+ // eslint/rules/css/root-variables.ts
4324
4362
  var rootVariablesRule = {
4325
4363
  meta: {
4326
4364
  schema: [],
@@ -4363,7 +4401,7 @@ var rootVariablesRule = {
4363
4401
  }
4364
4402
  };
4365
4403
 
4366
- // eslint/pasika/rules/css/apply-usage.ts
4404
+ // eslint/rules/css/apply-usage.ts
4367
4405
  var applyUsageRule = {
4368
4406
  meta: {
4369
4407
  schema: [],
@@ -4393,7 +4431,7 @@ var applyUsageRule = {
4393
4431
  }
4394
4432
  };
4395
4433
 
4396
- // eslint/pasika/rules/css/base-layer-pair.ts
4434
+ // eslint/rules/css/base-layer-pair.ts
4397
4435
  var baseLayerPairRule = {
4398
4436
  meta: {
4399
4437
  schema: [],
@@ -4431,7 +4469,7 @@ var baseLayerPairRule = {
4431
4469
  }
4432
4470
  };
4433
4471
 
4434
- // eslint/pasika/rules/css/stylesheet-ordering.ts
4472
+ // eslint/rules/css/stylesheet-ordering.ts
4435
4473
  var SECTION_ORDER = ["imports", "custom-variant", "root", "theme", "utility", "base styles", "keyframes"];
4436
4474
  var stylesheetOrderingRule = {
4437
4475
  meta: {
@@ -4488,7 +4526,7 @@ var stylesheetOrderingRule = {
4488
4526
  }
4489
4527
  };
4490
4528
 
4491
- // eslint/pasika/rules/css/css-variable-naming.ts
4529
+ // eslint/rules/css/css-variable-naming.ts
4492
4530
  var cssVariableNamingRule = {
4493
4531
  meta: {
4494
4532
  schema: [],
@@ -4520,7 +4558,7 @@ var cssVariableNamingRule = {
4520
4558
  }
4521
4559
  };
4522
4560
 
4523
- // eslint/pasika/rules/css/custom-utility-apply.ts
4561
+ // eslint/rules/css/custom-utility-apply.ts
4524
4562
  function rawProperty(raw) {
4525
4563
  const match = /^\s*(?<property>[a-z][a-z-]*)\s*:/.exec(raw);
4526
4564
  return match?.groups?.property;
@@ -4562,7 +4600,7 @@ var customUtilityApplyRule = {
4562
4600
  }
4563
4601
  };
4564
4602
 
4565
- // eslint/pasika/rules/css/surface-utility.ts
4603
+ // eslint/rules/css/surface-utility.ts
4566
4604
  var surfaceUtilityRule = {
4567
4605
  meta: {
4568
4606
  schema: [],
@@ -4595,7 +4633,7 @@ var surfaceUtilityRule = {
4595
4633
  }
4596
4634
  };
4597
4635
 
4598
- // eslint/pasika/rules/css/theme-variable-namespace.ts
4636
+ // eslint/rules/css/theme-variable-namespace.ts
4599
4637
  var themeVariableNamespaceRule = {
4600
4638
  meta: {
4601
4639
  schema: [],
@@ -4634,7 +4672,7 @@ var themeVariableNamespaceRule = {
4634
4672
  }
4635
4673
  };
4636
4674
 
4637
- // eslint/pasika/rules/css/global-css-location.ts
4675
+ // eslint/rules/css/global-css-location.ts
4638
4676
  var globalCssLocationRule = {
4639
4677
  meta: {
4640
4678
  schema: [],
@@ -4665,7 +4703,40 @@ var globalCssLocationRule = {
4665
4703
  }
4666
4704
  };
4667
4705
 
4668
- // eslint/pasika/rules/css/index.ts
4706
+ // eslint/rules/css/global-stylesheet.ts
4707
+ var globalStylesheetRule = {
4708
+ meta: {
4709
+ schema: [],
4710
+ type: "problem",
4711
+ docs: {
4712
+ description: "Require a global stylesheet entry point that registers Tailwind."
4713
+ }
4714
+ },
4715
+ create(context) {
4716
+ return {
4717
+ "StyleSheet:exit"(node) {
4718
+ const registersTailwind = node.children.some(
4719
+ (child) => child.type === "Atrule" && child.name === "import" && JSON.stringify(child.prelude).includes("tailwindcss")
4720
+ );
4721
+ if (!registersTailwind) {
4722
+ const hasProjectCss = node.children.some((child) => {
4723
+ if (child.type === "Atrule" && child.name === "import") return false;
4724
+ if (child.type === "Comment") return false;
4725
+ return true;
4726
+ });
4727
+ if (hasProjectCss) {
4728
+ context.report({
4729
+ node,
4730
+ message: 'Global stylesheet must register Tailwind with @import "tailwindcss".'
4731
+ });
4732
+ }
4733
+ }
4734
+ }
4735
+ };
4736
+ }
4737
+ };
4738
+
4739
+ // eslint/rules/css/index.ts
4669
4740
  var cssRules = {
4670
4741
  "theme-reset": themeResetRule,
4671
4742
  "root-variables": rootVariablesRule,
@@ -4676,10 +4747,11 @@ var cssRules = {
4676
4747
  "custom-utility-apply": customUtilityApplyRule,
4677
4748
  "surface-utility": surfaceUtilityRule,
4678
4749
  "theme-variable-namespace": themeVariableNamespaceRule,
4679
- "global-css-location": globalCssLocationRule
4750
+ "global-css-location": globalCssLocationRule,
4751
+ "global-stylesheet": globalStylesheetRule
4680
4752
  };
4681
4753
 
4682
- // eslint/pasika/rules/json/no-vulyk-dependency.ts
4754
+ // eslint/rules/json/no-vulyk-dependency.ts
4683
4755
  function memberName(member) {
4684
4756
  return member.name.type === "String" ? member.name.value : member.name.name;
4685
4757
  }
@@ -4712,12 +4784,49 @@ var noVulykDependencyRule = {
4712
4784
  }
4713
4785
  };
4714
4786
 
4715
- // eslint/pasika/rules/json/index.ts
4787
+ // eslint/rules/json/zirka-installed.ts
4788
+ function memberName2(member) {
4789
+ return member.name.type === "String" ? member.name.value : member.name.name;
4790
+ }
4791
+ var zirkaInstalledRule = {
4792
+ meta: {
4793
+ schema: [],
4794
+ type: "problem",
4795
+ docs: {
4796
+ description: "Require zirka to be listed in package.json as a devDependency."
4797
+ }
4798
+ },
4799
+ create(context) {
4800
+ return {
4801
+ Document(node) {
4802
+ const root = node.body;
4803
+ if (root.type !== "Object") return;
4804
+ const allDeps = [];
4805
+ for (const key of ["dependencies", "devDependencies"]) {
4806
+ const section = root.members.find((member) => memberName2(member) === key);
4807
+ if (section?.value.type !== "Object") continue;
4808
+ for (const member of section.value.members) {
4809
+ allDeps.push(memberName2(member));
4810
+ }
4811
+ }
4812
+ if (!allDeps.includes("zirka")) {
4813
+ context.report({
4814
+ node,
4815
+ message: "zirka must be listed in package.json as a devDependency."
4816
+ });
4817
+ }
4818
+ }
4819
+ };
4820
+ }
4821
+ };
4822
+
4823
+ // eslint/rules/json/index.ts
4716
4824
  var jsonRules = {
4717
- "no-vulyk-dependency": noVulykDependencyRule
4825
+ "no-vulyk-dependency": noVulykDependencyRule,
4826
+ "zirka-installed": zirkaInstalledRule
4718
4827
  };
4719
4828
 
4720
- // eslint/pasika/index.ts
4829
+ // eslint/index.ts
4721
4830
  var pasikaRules = {
4722
4831
  "component-placement": componentPlacementRule,
4723
4832
  "support-file-placement": supportFilePlacementRule,
@@ -4757,7 +4866,8 @@ var pasikaRules = {
4757
4866
  "shared-style-dedup": sharedStyleDedupRule,
4758
4867
  "repeated-structure": repeatedStructureRule,
4759
4868
  "zod-schema-validation": zodSchemaValidationRule,
4760
- "source-under-src": sourceUnderSrcRule
4869
+ "source-under-src": sourceUnderSrcRule,
4870
+ "config-baseline": configBaselineRule
4761
4871
  };
4762
4872
  var pasikaRuleIds = Object.keys(pasikaRules).map((name) => `pasika/${name}`);
4763
4873
  var pasikaMdRuleIds = Object.keys(mdRules).map((name) => `pasika/${name}`);