pasika 0.3.8 → 0.4.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/README.md +54 -33
- package/dist/eslint/pasika/index.d.ts +49 -27
- package/dist/eslint/pasika/index.js +574 -202
- package/package.json +25 -20
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
// eslint/index.ts
|
|
2
|
+
import css from "@eslint/css";
|
|
3
|
+
import jsonPlugin from "@eslint/json";
|
|
4
|
+
import markdown from "@eslint/markdown";
|
|
5
|
+
|
|
1
6
|
// eslint/rules/filename-case.ts
|
|
2
7
|
import path2 from "path";
|
|
3
8
|
|
|
@@ -547,6 +552,43 @@ var enforceCnMergeRule = {
|
|
|
547
552
|
}
|
|
548
553
|
};
|
|
549
554
|
|
|
555
|
+
// eslint/rules/cn-helper.ts
|
|
556
|
+
function isIdentifier(node, name) {
|
|
557
|
+
return node?.type === "Identifier" && node.name === name;
|
|
558
|
+
}
|
|
559
|
+
var cnHelperRule = {
|
|
560
|
+
meta: {
|
|
561
|
+
schema: [],
|
|
562
|
+
type: "problem",
|
|
563
|
+
docs: {
|
|
564
|
+
description: "Require the cn helper to merge clsx and tailwind-merge."
|
|
565
|
+
}
|
|
566
|
+
},
|
|
567
|
+
create(context) {
|
|
568
|
+
return {
|
|
569
|
+
FunctionDeclaration(node) {
|
|
570
|
+
if (isIdentifier(node.id, "cn")) checkBody(context, node.body);
|
|
571
|
+
},
|
|
572
|
+
VariableDeclarator(node) {
|
|
573
|
+
if (node.init?.type === "ArrowFunctionExpression" && isIdentifier(node.id, "cn")) {
|
|
574
|
+
checkBody(context, node.init.body);
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
};
|
|
578
|
+
}
|
|
579
|
+
};
|
|
580
|
+
function checkBody(context, body) {
|
|
581
|
+
const source = context.sourceCode.getText(body);
|
|
582
|
+
const usesClsx = /\bclsx\b/.test(source);
|
|
583
|
+
const usesTwMerge = /\btwMerge\b|\btailwind-merge\b/.test(source);
|
|
584
|
+
if (!usesClsx || !usesTwMerge) {
|
|
585
|
+
context.report({
|
|
586
|
+
node: body,
|
|
587
|
+
message: "cn must be built from clsx and tailwind-merge (e.g. cn = twMerge(clsx(inputs)))."
|
|
588
|
+
});
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
|
|
550
592
|
// eslint/rules/enforce-cva-variant-props.ts
|
|
551
593
|
var enforceCvaVariantPropsRule = {
|
|
552
594
|
meta: {
|
|
@@ -3224,48 +3266,96 @@ var sourceUnderSrcRule = {
|
|
|
3224
3266
|
}
|
|
3225
3267
|
};
|
|
3226
3268
|
|
|
3227
|
-
// eslint/rules/
|
|
3269
|
+
// eslint/rules/zirka-baseline.ts
|
|
3228
3270
|
import fs4 from "fs";
|
|
3229
3271
|
import path33 from "path";
|
|
3230
|
-
var
|
|
3272
|
+
var ESLINT_CONFIG = /^eslint\.config\.(?:ts|mts|cts|js|mjs|cjs)$/;
|
|
3273
|
+
var PRETTIER_CONFIGS = [
|
|
3274
|
+
"prettier.config.mjs",
|
|
3275
|
+
"prettier.config.cjs",
|
|
3276
|
+
"prettier.config.js",
|
|
3277
|
+
"prettier.config.ts",
|
|
3278
|
+
"prettier.config.mts",
|
|
3279
|
+
"prettier.config.cts"
|
|
3280
|
+
];
|
|
3281
|
+
var zirkaBaselineRule = {
|
|
3231
3282
|
meta: {
|
|
3232
3283
|
schema: [],
|
|
3233
3284
|
type: "problem",
|
|
3234
3285
|
docs: {
|
|
3235
|
-
description: "Require eslint
|
|
3286
|
+
description: "Require eslint, prettier, and TypeScript configuration to come from zirka."
|
|
3236
3287
|
}
|
|
3237
3288
|
},
|
|
3238
3289
|
create(context) {
|
|
3239
3290
|
const filename = path33.resolve(context.filename);
|
|
3240
3291
|
const basename = path33.basename(filename);
|
|
3241
|
-
if (
|
|
3292
|
+
if (!ESLINT_CONFIG.test(basename)) return {};
|
|
3293
|
+
const projectRoot = path33.dirname(filename);
|
|
3294
|
+
const report3 = (message) => {
|
|
3295
|
+
context.report({
|
|
3296
|
+
node: context.sourceCode.ast,
|
|
3297
|
+
loc: { line: 1, column: 0 },
|
|
3298
|
+
message
|
|
3299
|
+
});
|
|
3300
|
+
};
|
|
3242
3301
|
return {
|
|
3243
|
-
Program(
|
|
3244
|
-
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
loc: { line: 1, column: 0 },
|
|
3249
|
-
message: "ESLint config must reference zirka. Use the pasika/zirka baseline configuration."
|
|
3250
|
-
});
|
|
3302
|
+
Program() {
|
|
3303
|
+
if (!referencesZirka(context.sourceCode)) {
|
|
3304
|
+
report3(
|
|
3305
|
+
'ESLint config must take its configuration from zirka (import { styleguide } from "zirka") instead of restating rules locally.'
|
|
3306
|
+
);
|
|
3251
3307
|
}
|
|
3252
|
-
const
|
|
3253
|
-
if (!fs4.existsSync(
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
|
|
3308
|
+
const tsconfigPath = path33.join(projectRoot, "tsconfig.json");
|
|
3309
|
+
if (!fs4.existsSync(tsconfigPath)) {
|
|
3310
|
+
report3('No tsconfig.json found. Create one extending the zirka TypeScript base config ("zirka/typescript").');
|
|
3311
|
+
} else {
|
|
3312
|
+
let extendsValue;
|
|
3313
|
+
try {
|
|
3314
|
+
const parsed = JSON.parse(fs4.readFileSync(tsconfigPath, "utf8"));
|
|
3315
|
+
extendsValue = typeof parsed === "object" && parsed !== null && "extends" in parsed ? parsed.extends : void 0;
|
|
3316
|
+
} catch {
|
|
3317
|
+
report3(
|
|
3318
|
+
'tsconfig.json must be valid JSON and extend the zirka TypeScript base config ("zirka/typescript").'
|
|
3319
|
+
);
|
|
3320
|
+
return;
|
|
3321
|
+
}
|
|
3322
|
+
if (typeof extendsValue !== "string" || !extendsValue.startsWith("zirka")) {
|
|
3323
|
+
report3('tsconfig.json must extend the zirka TypeScript base config ("zirka/typescript").');
|
|
3324
|
+
}
|
|
3325
|
+
}
|
|
3326
|
+
const prettierConfigFile = PRETTIER_CONFIGS.find((name) => fs4.existsSync(path33.join(projectRoot, name)));
|
|
3327
|
+
if (!prettierConfigFile) {
|
|
3328
|
+
report3(
|
|
3329
|
+
"No prettier config found. Create one that takes its configuration from zirka (styleguide({ prettier: true }).prettierConfig)."
|
|
3330
|
+
);
|
|
3331
|
+
} else {
|
|
3332
|
+
const content = fs4.readFileSync(path33.join(projectRoot, prettierConfigFile), "utf8");
|
|
3333
|
+
if (!content.includes("zirka")) {
|
|
3334
|
+
report3(
|
|
3335
|
+
"The prettier config must take its configuration from zirka (styleguide({ prettier: true }).prettierConfig) instead of restating it locally."
|
|
3336
|
+
);
|
|
3337
|
+
}
|
|
3259
3338
|
}
|
|
3260
3339
|
}
|
|
3261
3340
|
};
|
|
3262
3341
|
}
|
|
3263
3342
|
};
|
|
3343
|
+
function referencesZirka(sourceCode) {
|
|
3344
|
+
for (const statement of sourceCode.ast.body) {
|
|
3345
|
+
if (statement.type === "ImportDeclaration" && typeof statement.source.value === "string" && statement.source.value.startsWith("zirka")) {
|
|
3346
|
+
return true;
|
|
3347
|
+
}
|
|
3348
|
+
}
|
|
3349
|
+
return /require\(\s*["']zirka["']\s*\)/.test(sourceCode.getText());
|
|
3350
|
+
}
|
|
3351
|
+
|
|
3352
|
+
// constants/rfc2119.ts
|
|
3353
|
+
var RFC_2119_KEYWORDS = ["MUST NOT", "MUST", "SHOULD NOT", "SHOULD", "MAY"];
|
|
3354
|
+
var RFC_2119_PATTERN = new RegExp(`\\b(?<keyword>${RFC_2119_KEYWORDS.join("|")})\\b`);
|
|
3264
3355
|
|
|
3265
|
-
// eslint/rules/
|
|
3266
|
-
var RFC_PATTERN = /\b(?<keyword>MUST NOT|MUST|SHALL NOT|SHALL|SHOULD NOT|SHOULD|MAY|RECOMMENDED|NOT RECOMMENDED|OPTIONAL|REQUIRED)\b/;
|
|
3356
|
+
// eslint/rules/documentation/helpers.ts
|
|
3267
3357
|
function containsRfcKeyword(text) {
|
|
3268
|
-
const match =
|
|
3358
|
+
const match = RFC_2119_PATTERN.exec(text);
|
|
3269
3359
|
return match?.groups?.keyword ?? null;
|
|
3270
3360
|
}
|
|
3271
3361
|
function getFilename(context) {
|
|
@@ -3282,7 +3372,7 @@ function getLine(node) {
|
|
|
3282
3372
|
return node.position?.start.line ?? 0;
|
|
3283
3373
|
}
|
|
3284
3374
|
|
|
3285
|
-
// eslint/rules/
|
|
3375
|
+
// eslint/rules/documentation/doc-kind-suffix.ts
|
|
3286
3376
|
var docKindSuffixRule = {
|
|
3287
3377
|
meta: {
|
|
3288
3378
|
type: "problem",
|
|
@@ -3308,7 +3398,7 @@ var docKindSuffixRule = {
|
|
|
3308
3398
|
}
|
|
3309
3399
|
};
|
|
3310
3400
|
|
|
3311
|
-
// eslint/rules/
|
|
3401
|
+
// eslint/rules/documentation/title-matches-file-name.ts
|
|
3312
3402
|
import path34 from "path";
|
|
3313
3403
|
function toExpectedFileName(title) {
|
|
3314
3404
|
return `${title.toLowerCase().replaceAll(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "")}.md`;
|
|
@@ -3346,90 +3436,10 @@ var titleMatchesFileNameRule = {
|
|
|
3346
3436
|
}
|
|
3347
3437
|
};
|
|
3348
3438
|
|
|
3349
|
-
// eslint/rules/
|
|
3350
|
-
var overviewPresentRule = {
|
|
3351
|
-
meta: {
|
|
3352
|
-
type: "problem",
|
|
3353
|
-
docs: {
|
|
3354
|
-
description: "Overview must follow the title in a documentation file.",
|
|
3355
|
-
recommended: true
|
|
3356
|
-
}
|
|
3357
|
-
},
|
|
3358
|
-
create(context) {
|
|
3359
|
-
return {
|
|
3360
|
-
root(node) {
|
|
3361
|
-
const filename = getFilename(context);
|
|
3362
|
-
if (!filename.endsWith(".md")) return;
|
|
3363
|
-
let titleLine = 0;
|
|
3364
|
-
for (const child of node.children) {
|
|
3365
|
-
if (child.type === "heading" && child.depth === 1) {
|
|
3366
|
-
titleLine = getLine(child);
|
|
3367
|
-
break;
|
|
3368
|
-
}
|
|
3369
|
-
}
|
|
3370
|
-
if (!titleLine) return;
|
|
3371
|
-
let hasOverview = false;
|
|
3372
|
-
for (const child of node.children) {
|
|
3373
|
-
if (child.type === "paragraph" && getLine(child) > titleLine && getTextContent(child).trim()) {
|
|
3374
|
-
hasOverview = true;
|
|
3375
|
-
break;
|
|
3376
|
-
}
|
|
3377
|
-
}
|
|
3378
|
-
if (!hasOverview) {
|
|
3379
|
-
context.report({
|
|
3380
|
-
node,
|
|
3381
|
-
message: "no overview follows the title"
|
|
3382
|
-
});
|
|
3383
|
-
}
|
|
3384
|
-
}
|
|
3385
|
-
};
|
|
3386
|
-
}
|
|
3387
|
-
};
|
|
3388
|
-
|
|
3389
|
-
// eslint/rules/md/overview-length.ts
|
|
3439
|
+
// eslint/rules/documentation/overview.ts
|
|
3390
3440
|
function countSentences(text) {
|
|
3391
3441
|
return text.split(/[.!?](?:\s+|$)/).filter((part) => part.trim() !== "").length;
|
|
3392
3442
|
}
|
|
3393
|
-
var overviewLengthRule = {
|
|
3394
|
-
meta: {
|
|
3395
|
-
type: "problem",
|
|
3396
|
-
docs: {
|
|
3397
|
-
description: "Overview must contain at most two sentences.",
|
|
3398
|
-
recommended: true
|
|
3399
|
-
}
|
|
3400
|
-
},
|
|
3401
|
-
create(context) {
|
|
3402
|
-
return {
|
|
3403
|
-
root(node) {
|
|
3404
|
-
const filename = getFilename(context);
|
|
3405
|
-
if (!filename.endsWith(".md")) return;
|
|
3406
|
-
let titleLine = 0;
|
|
3407
|
-
for (const child of node.children) {
|
|
3408
|
-
if (child.type === "heading" && child.depth === 1) {
|
|
3409
|
-
titleLine = getLine(child);
|
|
3410
|
-
break;
|
|
3411
|
-
}
|
|
3412
|
-
}
|
|
3413
|
-
if (!titleLine) return;
|
|
3414
|
-
for (const child of node.children) {
|
|
3415
|
-
if (child.type !== "paragraph" || getLine(child) <= titleLine) continue;
|
|
3416
|
-
const text = getTextContent(child).trim();
|
|
3417
|
-
if (!text || text.startsWith("#")) continue;
|
|
3418
|
-
const sentenceCount = countSentences(text);
|
|
3419
|
-
if (sentenceCount > 2) {
|
|
3420
|
-
context.report({
|
|
3421
|
-
node: child,
|
|
3422
|
-
message: `overview uses ${String(sentenceCount)} sentences, at most two are allowed`
|
|
3423
|
-
});
|
|
3424
|
-
}
|
|
3425
|
-
break;
|
|
3426
|
-
}
|
|
3427
|
-
}
|
|
3428
|
-
};
|
|
3429
|
-
}
|
|
3430
|
-
};
|
|
3431
|
-
|
|
3432
|
-
// eslint/rules/md/guide-overview-no-links.ts
|
|
3433
3443
|
function containsLink(node) {
|
|
3434
3444
|
if (node.type === "link") return true;
|
|
3435
3445
|
if ("children" in node) {
|
|
@@ -3437,11 +3447,11 @@ function containsLink(node) {
|
|
|
3437
3447
|
}
|
|
3438
3448
|
return false;
|
|
3439
3449
|
}
|
|
3440
|
-
var
|
|
3450
|
+
var overviewRule = {
|
|
3441
3451
|
meta: {
|
|
3442
3452
|
type: "problem",
|
|
3443
3453
|
docs: {
|
|
3444
|
-
description: "
|
|
3454
|
+
description: "Overview must exist, contain at most two sentences, and not link to other documents.",
|
|
3445
3455
|
recommended: true
|
|
3446
3456
|
}
|
|
3447
3457
|
},
|
|
@@ -3449,7 +3459,7 @@ var guideOverviewNoLinksRule = {
|
|
|
3449
3459
|
return {
|
|
3450
3460
|
root(node) {
|
|
3451
3461
|
const filename = getFilename(context);
|
|
3452
|
-
if (!filename.endsWith("
|
|
3462
|
+
if (!filename.endsWith(".md")) return;
|
|
3453
3463
|
let titleLine = 0;
|
|
3454
3464
|
for (const child of node.children) {
|
|
3455
3465
|
if (child.type === "heading" && child.depth === 1) {
|
|
@@ -3458,24 +3468,38 @@ var guideOverviewNoLinksRule = {
|
|
|
3458
3468
|
}
|
|
3459
3469
|
}
|
|
3460
3470
|
if (!titleLine) return;
|
|
3471
|
+
let sentenceCount = 0;
|
|
3472
|
+
let found = false;
|
|
3461
3473
|
for (const child of node.children) {
|
|
3474
|
+
if (child.type === "heading" && getLine(child) > titleLine) break;
|
|
3462
3475
|
if (child.type !== "paragraph" || getLine(child) <= titleLine) continue;
|
|
3463
3476
|
const text = getTextContent(child).trim();
|
|
3464
3477
|
if (!text || text.startsWith("#")) continue;
|
|
3478
|
+
found = true;
|
|
3465
3479
|
if (containsLink(child)) {
|
|
3466
3480
|
context.report({
|
|
3467
3481
|
node: child,
|
|
3468
|
-
message: "
|
|
3482
|
+
message: "overview links another document"
|
|
3469
3483
|
});
|
|
3470
3484
|
}
|
|
3471
|
-
|
|
3485
|
+
sentenceCount += countSentences(text);
|
|
3486
|
+
if (sentenceCount > 2) {
|
|
3487
|
+
context.report({
|
|
3488
|
+
node: child,
|
|
3489
|
+
message: `overview uses ${String(sentenceCount)} sentences, at most two are allowed`
|
|
3490
|
+
});
|
|
3491
|
+
break;
|
|
3492
|
+
}
|
|
3493
|
+
}
|
|
3494
|
+
if (!found) {
|
|
3495
|
+
context.report({ node, message: "no overview follows the title" });
|
|
3472
3496
|
}
|
|
3473
3497
|
}
|
|
3474
3498
|
};
|
|
3475
3499
|
}
|
|
3476
3500
|
};
|
|
3477
3501
|
|
|
3478
|
-
// eslint/rules/
|
|
3502
|
+
// eslint/rules/documentation/guide-step-single-sentence.ts
|
|
3479
3503
|
function countSentences2(text) {
|
|
3480
3504
|
return text.split(/[.!?](?:\s+|$)/).filter((part) => part.trim() !== "").length;
|
|
3481
3505
|
}
|
|
@@ -3513,7 +3537,7 @@ var guideStepSingleSentenceRule = {
|
|
|
3513
3537
|
}
|
|
3514
3538
|
};
|
|
3515
3539
|
|
|
3516
|
-
// eslint/rules/
|
|
3540
|
+
// eslint/rules/documentation/guide-step-single-link.ts
|
|
3517
3541
|
function countDocLinks(node) {
|
|
3518
3542
|
if (node.type === "link" && node.url.endsWith(".md")) return 1;
|
|
3519
3543
|
if ("children" in node) {
|
|
@@ -3556,7 +3580,7 @@ var guideStepSingleLinkRule = {
|
|
|
3556
3580
|
}
|
|
3557
3581
|
};
|
|
3558
3582
|
|
|
3559
|
-
// eslint/rules/
|
|
3583
|
+
// eslint/rules/documentation/guide-states-no-requirement.ts
|
|
3560
3584
|
var guideStatesNoRequirementRule = {
|
|
3561
3585
|
meta: {
|
|
3562
3586
|
type: "problem",
|
|
@@ -3582,7 +3606,7 @@ var guideStatesNoRequirementRule = {
|
|
|
3582
3606
|
}
|
|
3583
3607
|
};
|
|
3584
3608
|
|
|
3585
|
-
// eslint/rules/
|
|
3609
|
+
// eslint/rules/documentation/requirement-present.ts
|
|
3586
3610
|
function hasRequirement(node) {
|
|
3587
3611
|
if (node.type === "listItem") {
|
|
3588
3612
|
if (containsRfcKeyword(getTextContent(node))) return true;
|
|
@@ -3621,7 +3645,7 @@ var requirementPresentRule = {
|
|
|
3621
3645
|
}
|
|
3622
3646
|
};
|
|
3623
3647
|
|
|
3624
|
-
// eslint/rules/
|
|
3648
|
+
// eslint/rules/documentation/rule-paired-examples.ts
|
|
3625
3649
|
var rulePairedExamplesRule = {
|
|
3626
3650
|
meta: {
|
|
3627
3651
|
type: "problem",
|
|
@@ -3657,7 +3681,7 @@ var rulePairedExamplesRule = {
|
|
|
3657
3681
|
}
|
|
3658
3682
|
};
|
|
3659
3683
|
|
|
3660
|
-
// eslint/rules/
|
|
3684
|
+
// eslint/rules/documentation/example-heading-description.ts
|
|
3661
3685
|
var exampleHeadingDescriptionRule = {
|
|
3662
3686
|
meta: {
|
|
3663
3687
|
type: "problem",
|
|
@@ -3685,7 +3709,7 @@ var exampleHeadingDescriptionRule = {
|
|
|
3685
3709
|
}
|
|
3686
3710
|
};
|
|
3687
3711
|
|
|
3688
|
-
// eslint/rules/
|
|
3712
|
+
// eslint/rules/documentation/policy-no-examples.ts
|
|
3689
3713
|
var policyNoExamplesRule = {
|
|
3690
3714
|
meta: {
|
|
3691
3715
|
type: "problem",
|
|
@@ -3712,7 +3736,7 @@ var policyNoExamplesRule = {
|
|
|
3712
3736
|
}
|
|
3713
3737
|
};
|
|
3714
3738
|
|
|
3715
|
-
// eslint/rules/
|
|
3739
|
+
// eslint/rules/documentation/no-cross-document-link.ts
|
|
3716
3740
|
function linkedKind(filename) {
|
|
3717
3741
|
if (filename.endsWith("-rule.md")) return "rule";
|
|
3718
3742
|
if (filename.endsWith("-reference.md")) return "reference";
|
|
@@ -3744,7 +3768,7 @@ var noCrossDocumentLinkRule = {
|
|
|
3744
3768
|
}
|
|
3745
3769
|
};
|
|
3746
3770
|
|
|
3747
|
-
// eslint/rules/
|
|
3771
|
+
// eslint/rules/documentation/reference-no-rfc-vocabulary.ts
|
|
3748
3772
|
var referenceNoRfcVocabularyRule = {
|
|
3749
3773
|
meta: {
|
|
3750
3774
|
type: "problem",
|
|
@@ -3770,7 +3794,7 @@ var referenceNoRfcVocabularyRule = {
|
|
|
3770
3794
|
}
|
|
3771
3795
|
};
|
|
3772
3796
|
|
|
3773
|
-
// eslint/rules/
|
|
3797
|
+
// eslint/rules/documentation/reference-block-headings.ts
|
|
3774
3798
|
var referenceBlockHeadingsRule = {
|
|
3775
3799
|
meta: {
|
|
3776
3800
|
type: "problem",
|
|
@@ -3801,7 +3825,7 @@ var referenceBlockHeadingsRule = {
|
|
|
3801
3825
|
}
|
|
3802
3826
|
};
|
|
3803
3827
|
|
|
3804
|
-
// eslint/rules/
|
|
3828
|
+
// eslint/rules/documentation/support-document-placement.ts
|
|
3805
3829
|
import path35 from "path";
|
|
3806
3830
|
var supportDocumentPlacementRule = {
|
|
3807
3831
|
meta: {
|
|
@@ -3834,7 +3858,7 @@ var supportDocumentPlacementRule = {
|
|
|
3834
3858
|
}
|
|
3835
3859
|
};
|
|
3836
3860
|
|
|
3837
|
-
// eslint/rules/
|
|
3861
|
+
// eslint/rules/documentation/no-template-prompt.ts
|
|
3838
3862
|
var TEMPLATE_PROMPT = /^\s*\[[A-Z0-9].*\]\s*$/;
|
|
3839
3863
|
var noTemplatePromptRule = {
|
|
3840
3864
|
meta: {
|
|
@@ -3858,10 +3882,10 @@ var noTemplatePromptRule = {
|
|
|
3858
3882
|
}
|
|
3859
3883
|
};
|
|
3860
3884
|
|
|
3861
|
-
// eslint/rules/
|
|
3885
|
+
// eslint/rules/documentation/guide-folder-entry-point.ts
|
|
3862
3886
|
import path37 from "path";
|
|
3863
3887
|
|
|
3864
|
-
// eslint/rules/
|
|
3888
|
+
// eslint/rules/documentation/project-index.ts
|
|
3865
3889
|
import { readdirSync as readdirSync2, readFileSync as readFileSync4, statSync as statSync3 } from "fs";
|
|
3866
3890
|
import path36 from "path";
|
|
3867
3891
|
var KIND_BY_SUFFIX = [
|
|
@@ -3915,7 +3939,7 @@ function findDocsRoot(filePath) {
|
|
|
3915
3939
|
}
|
|
3916
3940
|
}
|
|
3917
3941
|
|
|
3918
|
-
// eslint/rules/
|
|
3942
|
+
// eslint/rules/documentation/guide-folder-entry-point.ts
|
|
3919
3943
|
var guideFolderEntryPointRule = {
|
|
3920
3944
|
meta: {
|
|
3921
3945
|
type: "problem",
|
|
@@ -3953,7 +3977,7 @@ var guideFolderEntryPointRule = {
|
|
|
3953
3977
|
}
|
|
3954
3978
|
};
|
|
3955
3979
|
|
|
3956
|
-
// eslint/rules/
|
|
3980
|
+
// eslint/rules/documentation/rfc-only-in-bullets.ts
|
|
3957
3981
|
function checkOutsideBullets(node, context, insideBullet) {
|
|
3958
3982
|
if (node.type === "listItem") {
|
|
3959
3983
|
for (const child of node.children) {
|
|
@@ -3996,7 +4020,7 @@ var rfcOnlyInBulletsRule = {
|
|
|
3996
4020
|
}
|
|
3997
4021
|
};
|
|
3998
4022
|
|
|
3999
|
-
// eslint/rules/
|
|
4023
|
+
// eslint/rules/documentation/rfc-keyword-in-every-bullet.ts
|
|
4000
4024
|
function checkBullets(node, context) {
|
|
4001
4025
|
if (node.type === "listItem" && !containsRfcKeyword(getTextContent(node))) {
|
|
4002
4026
|
context.report({
|
|
@@ -4029,7 +4053,7 @@ var rfcKeywordInEveryBulletRule = {
|
|
|
4029
4053
|
}
|
|
4030
4054
|
};
|
|
4031
4055
|
|
|
4032
|
-
// eslint/rules/
|
|
4056
|
+
// eslint/rules/documentation/policy-subject-headings.ts
|
|
4033
4057
|
var policySubjectHeadingsRule = {
|
|
4034
4058
|
meta: {
|
|
4035
4059
|
type: "problem",
|
|
@@ -4082,7 +4106,7 @@ var policySubjectHeadingsRule = {
|
|
|
4082
4106
|
}
|
|
4083
4107
|
};
|
|
4084
4108
|
|
|
4085
|
-
// eslint/rules/
|
|
4109
|
+
// eslint/rules/documentation/guide-link-anchors.ts
|
|
4086
4110
|
function visitSteps2(node, check) {
|
|
4087
4111
|
if (node.type === "list" && node.ordered) {
|
|
4088
4112
|
for (const child of node.children) check(child);
|
|
@@ -4126,7 +4150,7 @@ var guideLinkAnchorsRule = {
|
|
|
4126
4150
|
}
|
|
4127
4151
|
};
|
|
4128
4152
|
|
|
4129
|
-
// eslint/rules/
|
|
4153
|
+
// eslint/rules/documentation/no-nested-how-to.ts
|
|
4130
4154
|
var noNestedHowToRule = {
|
|
4131
4155
|
meta: {
|
|
4132
4156
|
type: "problem",
|
|
@@ -4162,7 +4186,7 @@ var noNestedHowToRule = {
|
|
|
4162
4186
|
}
|
|
4163
4187
|
};
|
|
4164
4188
|
|
|
4165
|
-
// eslint/rules/
|
|
4189
|
+
// eslint/rules/documentation/glossary-term-linking.ts
|
|
4166
4190
|
import { readFileSync as readFileSync5 } from "fs";
|
|
4167
4191
|
import path38 from "path";
|
|
4168
4192
|
function extractGlossaryTerms(filePath) {
|
|
@@ -4243,13 +4267,91 @@ var glossaryTermLinkingRule = {
|
|
|
4243
4267
|
}
|
|
4244
4268
|
};
|
|
4245
4269
|
|
|
4246
|
-
// eslint/rules/
|
|
4247
|
-
|
|
4270
|
+
// eslint/rules/documentation/guide-mentions-documents.ts
|
|
4271
|
+
import { existsSync } from "fs";
|
|
4272
|
+
import path39 from "path";
|
|
4273
|
+
function visitSteps3(node, check) {
|
|
4274
|
+
if (node.type === "list" && node.ordered) {
|
|
4275
|
+
for (const child of node.children) check(child);
|
|
4276
|
+
}
|
|
4277
|
+
if ("children" in node) {
|
|
4278
|
+
for (const child of node.children) visitSteps3(child, check);
|
|
4279
|
+
}
|
|
4280
|
+
}
|
|
4281
|
+
function collectMarkdownLinks(node, out) {
|
|
4282
|
+
if (node.type === "link" && node.url.endsWith(".md")) out.push(node);
|
|
4283
|
+
if ("children" in node) {
|
|
4284
|
+
for (const child of node.children) collectMarkdownLinks(child, out);
|
|
4285
|
+
}
|
|
4286
|
+
}
|
|
4287
|
+
function linkTarget(url) {
|
|
4288
|
+
return url.split("#")[0] ?? url;
|
|
4289
|
+
}
|
|
4290
|
+
var guideMentionsDocumentsRule = {
|
|
4291
|
+
meta: {
|
|
4292
|
+
type: "problem",
|
|
4293
|
+
docs: {
|
|
4294
|
+
description: "A Guide entry point must reference each owned Rule from a How To step, mention every Reference, and not link a missing document.",
|
|
4295
|
+
recommended: true
|
|
4296
|
+
}
|
|
4297
|
+
},
|
|
4298
|
+
create(context) {
|
|
4299
|
+
return {
|
|
4300
|
+
root(node) {
|
|
4301
|
+
const filename = getFilename(context);
|
|
4302
|
+
if (!filename.endsWith("-guide.md")) return;
|
|
4303
|
+
const docsRoot = findDocsRoot(filename);
|
|
4304
|
+
if (!docsRoot) return;
|
|
4305
|
+
const guideDir = path39.dirname(filename);
|
|
4306
|
+
if (path39.basename(filename, ".md") !== path39.basename(guideDir)) return;
|
|
4307
|
+
const docs = getProjectDocs(docsRoot);
|
|
4308
|
+
const owned = docs.filter((doc) => {
|
|
4309
|
+
const parent = path39.dirname(doc.filePath);
|
|
4310
|
+
return parent === path39.join(guideDir, "rules") || parent === path39.join(guideDir, "references");
|
|
4311
|
+
});
|
|
4312
|
+
const allLinks = [];
|
|
4313
|
+
collectMarkdownLinks(node, allLinks);
|
|
4314
|
+
const stepLinks = [];
|
|
4315
|
+
visitSteps3(node, (item) => {
|
|
4316
|
+
collectMarkdownLinks(item, stepLinks);
|
|
4317
|
+
});
|
|
4318
|
+
const mentionsOf = (links, fileName) => links.some((link) => link.url.split("/").pop() === fileName);
|
|
4319
|
+
for (const doc of owned) {
|
|
4320
|
+
if (doc.kind === "rule") {
|
|
4321
|
+
if (!mentionsOf(stepLinks, doc.fileName)) {
|
|
4322
|
+
context.report({
|
|
4323
|
+
node,
|
|
4324
|
+
message: `Guide entry point does not reference a Rule it owns from a How To step: ${doc.doc}`
|
|
4325
|
+
});
|
|
4326
|
+
}
|
|
4327
|
+
} else if (!mentionsOf(allLinks, doc.fileName)) {
|
|
4328
|
+
context.report({
|
|
4329
|
+
node,
|
|
4330
|
+
message: `Guide entry point does not mention a document it owns: ${doc.doc}`
|
|
4331
|
+
});
|
|
4332
|
+
}
|
|
4333
|
+
}
|
|
4334
|
+
for (const link of allLinks) {
|
|
4335
|
+
const target = linkTarget(link.url);
|
|
4336
|
+
if (!target.endsWith(".md")) continue;
|
|
4337
|
+
const resolved = path39.normalize(path39.join(guideDir, target));
|
|
4338
|
+
if (!existsSync(resolved)) {
|
|
4339
|
+
context.report({
|
|
4340
|
+
node: link,
|
|
4341
|
+
message: `Guide links a document that does not exist: ${link.url}`
|
|
4342
|
+
});
|
|
4343
|
+
}
|
|
4344
|
+
}
|
|
4345
|
+
}
|
|
4346
|
+
};
|
|
4347
|
+
}
|
|
4348
|
+
};
|
|
4349
|
+
|
|
4350
|
+
// eslint/rules/documentation/index.ts
|
|
4351
|
+
var documentationRules = {
|
|
4248
4352
|
"doc-kind-suffix": docKindSuffixRule,
|
|
4249
4353
|
"title-matches-file-name": titleMatchesFileNameRule,
|
|
4250
|
-
|
|
4251
|
-
"overview-length": overviewLengthRule,
|
|
4252
|
-
"guide-overview-no-links": guideOverviewNoLinksRule,
|
|
4354
|
+
overview: overviewRule,
|
|
4253
4355
|
"guide-step-single-sentence": guideStepSingleSentenceRule,
|
|
4254
4356
|
"guide-step-single-link": guideStepSingleLinkRule,
|
|
4255
4357
|
"guide-states-no-requirement": guideStatesNoRequirementRule,
|
|
@@ -4268,10 +4370,11 @@ var mdRules = {
|
|
|
4268
4370
|
"policy-subject-headings": policySubjectHeadingsRule,
|
|
4269
4371
|
"guide-link-anchors": guideLinkAnchorsRule,
|
|
4270
4372
|
"no-nested-how-to": noNestedHowToRule,
|
|
4271
|
-
"glossary-term-linking": glossaryTermLinkingRule
|
|
4373
|
+
"glossary-term-linking": glossaryTermLinkingRule,
|
|
4374
|
+
"guide-mentions-documents": guideMentionsDocumentsRule
|
|
4272
4375
|
};
|
|
4273
4376
|
|
|
4274
|
-
// eslint/rules/
|
|
4377
|
+
// eslint/rules/tailwind/helpers.ts
|
|
4275
4378
|
function walkNodes(node, visit) {
|
|
4276
4379
|
visit(node);
|
|
4277
4380
|
if ("children" in node && node.children) {
|
|
@@ -4328,7 +4431,7 @@ function selectorNames(node) {
|
|
|
4328
4431
|
return names;
|
|
4329
4432
|
}
|
|
4330
4433
|
|
|
4331
|
-
// eslint/rules/
|
|
4434
|
+
// eslint/rules/tailwind/theme-reset.ts
|
|
4332
4435
|
var themeResetRule = {
|
|
4333
4436
|
meta: {
|
|
4334
4437
|
schema: [],
|
|
@@ -4358,7 +4461,7 @@ var themeResetRule = {
|
|
|
4358
4461
|
}
|
|
4359
4462
|
};
|
|
4360
4463
|
|
|
4361
|
-
// eslint/rules/
|
|
4464
|
+
// eslint/rules/tailwind/root-variables.ts
|
|
4362
4465
|
var rootVariablesRule = {
|
|
4363
4466
|
meta: {
|
|
4364
4467
|
schema: [],
|
|
@@ -4401,7 +4504,7 @@ var rootVariablesRule = {
|
|
|
4401
4504
|
}
|
|
4402
4505
|
};
|
|
4403
4506
|
|
|
4404
|
-
// eslint/rules/
|
|
4507
|
+
// eslint/rules/tailwind/apply-usage.ts
|
|
4405
4508
|
var applyUsageRule = {
|
|
4406
4509
|
meta: {
|
|
4407
4510
|
schema: [],
|
|
@@ -4431,7 +4534,7 @@ var applyUsageRule = {
|
|
|
4431
4534
|
}
|
|
4432
4535
|
};
|
|
4433
4536
|
|
|
4434
|
-
// eslint/rules/
|
|
4537
|
+
// eslint/rules/tailwind/base-layer-pair.ts
|
|
4435
4538
|
var baseLayerPairRule = {
|
|
4436
4539
|
meta: {
|
|
4437
4540
|
schema: [],
|
|
@@ -4469,7 +4572,7 @@ var baseLayerPairRule = {
|
|
|
4469
4572
|
}
|
|
4470
4573
|
};
|
|
4471
4574
|
|
|
4472
|
-
// eslint/rules/
|
|
4575
|
+
// eslint/rules/tailwind/stylesheet-ordering.ts
|
|
4473
4576
|
var SECTION_ORDER = ["imports", "custom-variant", "root", "theme", "utility", "base styles", "keyframes"];
|
|
4474
4577
|
var stylesheetOrderingRule = {
|
|
4475
4578
|
meta: {
|
|
@@ -4526,7 +4629,7 @@ var stylesheetOrderingRule = {
|
|
|
4526
4629
|
}
|
|
4527
4630
|
};
|
|
4528
4631
|
|
|
4529
|
-
// eslint/rules/
|
|
4632
|
+
// eslint/rules/tailwind/css-variable-naming.ts
|
|
4530
4633
|
var cssVariableNamingRule = {
|
|
4531
4634
|
meta: {
|
|
4532
4635
|
schema: [],
|
|
@@ -4558,7 +4661,7 @@ var cssVariableNamingRule = {
|
|
|
4558
4661
|
}
|
|
4559
4662
|
};
|
|
4560
4663
|
|
|
4561
|
-
// eslint/rules/
|
|
4664
|
+
// eslint/rules/tailwind/custom-utility-apply.ts
|
|
4562
4665
|
function rawProperty(raw) {
|
|
4563
4666
|
const match = /^\s*(?<property>[a-z][a-z-]*)\s*:/.exec(raw);
|
|
4564
4667
|
return match?.groups?.property;
|
|
@@ -4600,7 +4703,7 @@ var customUtilityApplyRule = {
|
|
|
4600
4703
|
}
|
|
4601
4704
|
};
|
|
4602
4705
|
|
|
4603
|
-
// eslint/rules/
|
|
4706
|
+
// eslint/rules/tailwind/surface-utility.ts
|
|
4604
4707
|
var surfaceUtilityRule = {
|
|
4605
4708
|
meta: {
|
|
4606
4709
|
schema: [],
|
|
@@ -4633,7 +4736,7 @@ var surfaceUtilityRule = {
|
|
|
4633
4736
|
}
|
|
4634
4737
|
};
|
|
4635
4738
|
|
|
4636
|
-
// eslint/rules/
|
|
4739
|
+
// eslint/rules/tailwind/theme-variable-namespace.ts
|
|
4637
4740
|
var themeVariableNamespaceRule = {
|
|
4638
4741
|
meta: {
|
|
4639
4742
|
schema: [],
|
|
@@ -4672,7 +4775,7 @@ var themeVariableNamespaceRule = {
|
|
|
4672
4775
|
}
|
|
4673
4776
|
};
|
|
4674
4777
|
|
|
4675
|
-
// eslint/rules/
|
|
4778
|
+
// eslint/rules/tailwind/global-css-location.ts
|
|
4676
4779
|
var globalCssLocationRule = {
|
|
4677
4780
|
meta: {
|
|
4678
4781
|
schema: [],
|
|
@@ -4703,7 +4806,7 @@ var globalCssLocationRule = {
|
|
|
4703
4806
|
}
|
|
4704
4807
|
};
|
|
4705
4808
|
|
|
4706
|
-
// eslint/rules/
|
|
4809
|
+
// eslint/rules/tailwind/global-stylesheet.ts
|
|
4707
4810
|
var globalStylesheetRule = {
|
|
4708
4811
|
meta: {
|
|
4709
4812
|
schema: [],
|
|
@@ -4736,8 +4839,8 @@ var globalStylesheetRule = {
|
|
|
4736
4839
|
}
|
|
4737
4840
|
};
|
|
4738
4841
|
|
|
4739
|
-
// eslint/rules/
|
|
4740
|
-
var
|
|
4842
|
+
// eslint/rules/tailwind/index.ts
|
|
4843
|
+
var tailwindRules = {
|
|
4741
4844
|
"theme-reset": themeResetRule,
|
|
4742
4845
|
"root-variables": rootVariablesRule,
|
|
4743
4846
|
"apply-usage": applyUsageRule,
|
|
@@ -4751,10 +4854,50 @@ var cssRules = {
|
|
|
4751
4854
|
"global-stylesheet": globalStylesheetRule
|
|
4752
4855
|
};
|
|
4753
4856
|
|
|
4754
|
-
// eslint/rules/json/
|
|
4857
|
+
// eslint/rules/package-json/exact-version.ts
|
|
4755
4858
|
function memberName(member) {
|
|
4756
4859
|
return member.name.type === "String" ? member.name.value : member.name.name;
|
|
4757
4860
|
}
|
|
4861
|
+
var EXACT_VERSION_PATTERN = /^\d+\.\d+\.\d+$/;
|
|
4862
|
+
function memberValue(member) {
|
|
4863
|
+
return member.value.type === "String" ? member.value.value : null;
|
|
4864
|
+
}
|
|
4865
|
+
var exactVersionRule = {
|
|
4866
|
+
meta: {
|
|
4867
|
+
schema: [],
|
|
4868
|
+
type: "problem",
|
|
4869
|
+
docs: {
|
|
4870
|
+
description: "Require dependency and devDependency versions to be pinned exactly."
|
|
4871
|
+
}
|
|
4872
|
+
},
|
|
4873
|
+
create(context) {
|
|
4874
|
+
return {
|
|
4875
|
+
Document(node) {
|
|
4876
|
+
const root = node.body;
|
|
4877
|
+
if (root.type !== "Object") return;
|
|
4878
|
+
for (const key of ["dependencies", "devDependencies"]) {
|
|
4879
|
+
const section = root.members.find((member) => memberName(member) === key);
|
|
4880
|
+
if (section?.value.type !== "Object") continue;
|
|
4881
|
+
for (const member of section.value.members) {
|
|
4882
|
+
const version = memberValue(member);
|
|
4883
|
+
if (version === null) continue;
|
|
4884
|
+
if (!EXACT_VERSION_PATTERN.test(version)) {
|
|
4885
|
+
context.report({
|
|
4886
|
+
node: member,
|
|
4887
|
+
message: `${memberName(member)} must pin an exact version (e.g. "1.2.3"), not a range or cap such as "${version}".`
|
|
4888
|
+
});
|
|
4889
|
+
}
|
|
4890
|
+
}
|
|
4891
|
+
}
|
|
4892
|
+
}
|
|
4893
|
+
};
|
|
4894
|
+
}
|
|
4895
|
+
};
|
|
4896
|
+
|
|
4897
|
+
// eslint/rules/package-json/no-vulyk-dependency.ts
|
|
4898
|
+
function memberName2(member) {
|
|
4899
|
+
return member.name.type === "String" ? member.name.value : member.name.name;
|
|
4900
|
+
}
|
|
4758
4901
|
var noVulykDependencyRule = {
|
|
4759
4902
|
meta: {
|
|
4760
4903
|
schema: [],
|
|
@@ -4769,9 +4912,9 @@ var noVulykDependencyRule = {
|
|
|
4769
4912
|
const root = node.body;
|
|
4770
4913
|
if (root.type !== "Object") return;
|
|
4771
4914
|
for (const key of ["dependencies", "devDependencies"]) {
|
|
4772
|
-
const section = root.members.find((member) =>
|
|
4915
|
+
const section = root.members.find((member) => memberName2(member) === key);
|
|
4773
4916
|
if (section?.value.type !== "Object") continue;
|
|
4774
|
-
const vulyk = section.value.members.find((member) =>
|
|
4917
|
+
const vulyk = section.value.members.find((member) => memberName2(member) === "vulyk");
|
|
4775
4918
|
if (vulyk) {
|
|
4776
4919
|
context.report({
|
|
4777
4920
|
node: vulyk,
|
|
@@ -4784,16 +4927,39 @@ var noVulykDependencyRule = {
|
|
|
4784
4927
|
}
|
|
4785
4928
|
};
|
|
4786
4929
|
|
|
4787
|
-
// eslint/rules/json/
|
|
4788
|
-
|
|
4930
|
+
// eslint/rules/package-json/nextjs-stack.ts
|
|
4931
|
+
var NEXTJS_STACK_DEPENDENCIES = [
|
|
4932
|
+
"next",
|
|
4933
|
+
"react",
|
|
4934
|
+
"react-dom",
|
|
4935
|
+
"zod",
|
|
4936
|
+
"class-variance-authority",
|
|
4937
|
+
"clsx",
|
|
4938
|
+
"tailwind-merge"
|
|
4939
|
+
];
|
|
4940
|
+
var NEXTJS_STACK_DEV_DEPENDENCIES = [
|
|
4941
|
+
"typescript",
|
|
4942
|
+
"tailwindcss",
|
|
4943
|
+
"eslint",
|
|
4944
|
+
"prettier",
|
|
4945
|
+
"husky",
|
|
4946
|
+
"lint-staged",
|
|
4947
|
+
"zirka"
|
|
4948
|
+
];
|
|
4949
|
+
function memberName3(member) {
|
|
4789
4950
|
return member.name.type === "String" ? member.name.value : member.name.name;
|
|
4790
4951
|
}
|
|
4791
|
-
|
|
4952
|
+
function sectionPackages(root, section) {
|
|
4953
|
+
const member = root.type === "Object" ? root.members.find((entry) => memberName3(entry) === section) : void 0;
|
|
4954
|
+
if (member?.value.type !== "Object") return /* @__PURE__ */ new Set();
|
|
4955
|
+
return new Set(member.value.members.map(memberName3));
|
|
4956
|
+
}
|
|
4957
|
+
var nextjsStackRule = {
|
|
4792
4958
|
meta: {
|
|
4793
4959
|
schema: [],
|
|
4794
4960
|
type: "problem",
|
|
4795
4961
|
docs: {
|
|
4796
|
-
description: "Require
|
|
4962
|
+
description: "Require the framework's runtime packages in dependencies and toolchain packages in devDependencies."
|
|
4797
4963
|
}
|
|
4798
4964
|
},
|
|
4799
4965
|
create(context) {
|
|
@@ -4801,18 +4967,20 @@ var zirkaInstalledRule = {
|
|
|
4801
4967
|
Document(node) {
|
|
4802
4968
|
const root = node.body;
|
|
4803
4969
|
if (root.type !== "Object") return;
|
|
4804
|
-
const
|
|
4805
|
-
|
|
4806
|
-
|
|
4807
|
-
if (
|
|
4808
|
-
|
|
4809
|
-
|
|
4810
|
-
|
|
4970
|
+
const dependencies = sectionPackages(root, "dependencies");
|
|
4971
|
+
const devDependencies = sectionPackages(root, "devDependencies");
|
|
4972
|
+
for (const pkg of NEXTJS_STACK_DEPENDENCIES) {
|
|
4973
|
+
if (dependencies.has(pkg)) continue;
|
|
4974
|
+
context.report({
|
|
4975
|
+
node,
|
|
4976
|
+
message: `${pkg} must be listed in package.json as a dependency.`
|
|
4977
|
+
});
|
|
4811
4978
|
}
|
|
4812
|
-
|
|
4979
|
+
for (const pkg of NEXTJS_STACK_DEV_DEPENDENCIES) {
|
|
4980
|
+
if (devDependencies.has(pkg)) continue;
|
|
4813
4981
|
context.report({
|
|
4814
4982
|
node,
|
|
4815
|
-
message:
|
|
4983
|
+
message: `${pkg} must be listed in package.json as a devDependency.`
|
|
4816
4984
|
});
|
|
4817
4985
|
}
|
|
4818
4986
|
}
|
|
@@ -4820,76 +4988,280 @@ var zirkaInstalledRule = {
|
|
|
4820
4988
|
}
|
|
4821
4989
|
};
|
|
4822
4990
|
|
|
4823
|
-
// eslint/rules/json/index.ts
|
|
4824
|
-
var
|
|
4991
|
+
// eslint/rules/package-json/index.ts
|
|
4992
|
+
var repoPackageJsonRules = {
|
|
4825
4993
|
"no-vulyk-dependency": noVulykDependencyRule,
|
|
4826
|
-
"
|
|
4994
|
+
"exact-version": exactVersionRule
|
|
4995
|
+
};
|
|
4996
|
+
var nextPackageJsonRules = {
|
|
4997
|
+
"nextjs-stack": nextjsStackRule
|
|
4998
|
+
};
|
|
4999
|
+
|
|
5000
|
+
// eslint/rules/husky/husky-hook.ts
|
|
5001
|
+
import { existsSync as existsSync2, readFileSync as readFileSync6 } from "fs";
|
|
5002
|
+
import path40 from "path";
|
|
5003
|
+
function memberName4(member) {
|
|
5004
|
+
return member.name.type === "String" ? member.name.value : member.name.name;
|
|
5005
|
+
}
|
|
5006
|
+
var huskyHookRule = {
|
|
5007
|
+
meta: {
|
|
5008
|
+
schema: [],
|
|
5009
|
+
type: "problem",
|
|
5010
|
+
docs: {
|
|
5011
|
+
description: "Require a pre-commit hook that runs lint-staged, typecheck, and the libyear drift check."
|
|
5012
|
+
}
|
|
5013
|
+
},
|
|
5014
|
+
create(context) {
|
|
5015
|
+
return {
|
|
5016
|
+
Document(node) {
|
|
5017
|
+
const root = node.body;
|
|
5018
|
+
if (root.type !== "Object") return;
|
|
5019
|
+
const scriptName = context.filename;
|
|
5020
|
+
if (!scriptName.endsWith("package.json")) return;
|
|
5021
|
+
const hookPath = path40.join(process.cwd(), ".husky", "pre-commit");
|
|
5022
|
+
if (!existsSync2(hookPath)) {
|
|
5023
|
+
context.report({
|
|
5024
|
+
node,
|
|
5025
|
+
message: "No .husky/pre-commit hook found. Configure husky to run checks before commits."
|
|
5026
|
+
});
|
|
5027
|
+
return;
|
|
5028
|
+
}
|
|
5029
|
+
const content = readFileSync6(hookPath, "utf8");
|
|
5030
|
+
if (!content.includes("lint-staged")) {
|
|
5031
|
+
context.report({ node, message: ".husky/pre-commit must run lint-staged." });
|
|
5032
|
+
}
|
|
5033
|
+
if (!content.includes("typecheck")) {
|
|
5034
|
+
context.report({ node, message: ".husky/pre-commit must run npm run typecheck." });
|
|
5035
|
+
}
|
|
5036
|
+
if (!content.includes("libyear --limit-major-individual=1")) {
|
|
5037
|
+
context.report({ node, message: ".husky/pre-commit must run npx libyear --limit-major-individual=1." });
|
|
5038
|
+
}
|
|
5039
|
+
const scripts = root.members.find((member) => memberName4(member) === "scripts");
|
|
5040
|
+
if (scripts?.value.type === "Object") {
|
|
5041
|
+
const prepare = scripts.value.members.find((member) => memberName4(member) === "prepare");
|
|
5042
|
+
if (prepare?.value.type === "String" && !prepare.value.value.includes("husky")) {
|
|
5043
|
+
context.report({
|
|
5044
|
+
node: prepare,
|
|
5045
|
+
message: 'package.json "prepare" script must run husky (e.g. "prepare": "husky").'
|
|
5046
|
+
});
|
|
5047
|
+
}
|
|
5048
|
+
}
|
|
5049
|
+
}
|
|
5050
|
+
};
|
|
5051
|
+
}
|
|
5052
|
+
};
|
|
5053
|
+
|
|
5054
|
+
// eslint/rules/husky/index.ts
|
|
5055
|
+
var huskyRules = {
|
|
5056
|
+
"husky-hook": huskyHookRule
|
|
5057
|
+
};
|
|
5058
|
+
|
|
5059
|
+
// eslint/rules/vulyk/vulyk-docs.ts
|
|
5060
|
+
import { existsSync as existsSync3, readFileSync as readFileSync7 } from "fs";
|
|
5061
|
+
import path41 from "path";
|
|
5062
|
+
var PASIKA_REPO = "Bredansky/pasika";
|
|
5063
|
+
var vulykDocsRule = {
|
|
5064
|
+
meta: {
|
|
5065
|
+
schema: [],
|
|
5066
|
+
type: "problem",
|
|
5067
|
+
docs: {
|
|
5068
|
+
description: "Require vulyk.config.ts to track the framework's docs from pasika and the generated AGENTS.md."
|
|
5069
|
+
}
|
|
5070
|
+
},
|
|
5071
|
+
create(context) {
|
|
5072
|
+
return {
|
|
5073
|
+
Document(node) {
|
|
5074
|
+
if (!context.filename.endsWith("package.json")) return;
|
|
5075
|
+
const projectRoot = path41.dirname(path41.resolve(context.filename));
|
|
5076
|
+
const configPath = path41.join(projectRoot, "vulyk.config.ts");
|
|
5077
|
+
if (!existsSync3(configPath)) {
|
|
5078
|
+
context.report({
|
|
5079
|
+
node,
|
|
5080
|
+
message: "No vulyk.config.ts found. Run npx vulyk@latest init to create one that tracks the framework's docs."
|
|
5081
|
+
});
|
|
5082
|
+
return;
|
|
5083
|
+
}
|
|
5084
|
+
const config = readFileSync7(configPath, "utf8");
|
|
5085
|
+
if (!config.includes(PASIKA_REPO)) {
|
|
5086
|
+
context.report({
|
|
5087
|
+
node,
|
|
5088
|
+
message: "vulyk.config.ts must track the framework's docs from the pasika repository."
|
|
5089
|
+
});
|
|
5090
|
+
}
|
|
5091
|
+
const agentsPath = path41.join(projectRoot, "AGENTS.md");
|
|
5092
|
+
if (!existsSync3(agentsPath)) {
|
|
5093
|
+
context.report({
|
|
5094
|
+
node,
|
|
5095
|
+
message: "No AGENTS.md found. Run npx vulyk@latest agents to generate the agent file that routes to the tracked docs."
|
|
5096
|
+
});
|
|
5097
|
+
}
|
|
5098
|
+
}
|
|
5099
|
+
};
|
|
5100
|
+
}
|
|
5101
|
+
};
|
|
5102
|
+
|
|
5103
|
+
// eslint/rules/vulyk/index.ts
|
|
5104
|
+
var vulykRules = {
|
|
5105
|
+
"vulyk-docs": vulykDocsRule
|
|
4827
5106
|
};
|
|
4828
5107
|
|
|
4829
5108
|
// eslint/index.ts
|
|
4830
|
-
var
|
|
4831
|
-
"
|
|
4832
|
-
"
|
|
4833
|
-
"application-structure": applicationStructureRule,
|
|
5109
|
+
var typescriptAppRules = {
|
|
5110
|
+
"filename-case": filenameCaseRule,
|
|
5111
|
+
"import-boundaries": importBoundariesRule,
|
|
4834
5112
|
"named-exports": namedExportsRule,
|
|
4835
|
-
"
|
|
5113
|
+
"support-file-placement": supportFilePlacementRule,
|
|
4836
5114
|
"support-folder-shape": supportFolderShapeRule,
|
|
4837
5115
|
"import-through-index": importThroughIndexRule,
|
|
4838
5116
|
"util-file-name": utilFileNameRule,
|
|
4839
5117
|
"no-util-barrel": noUtilBarrelRule,
|
|
5118
|
+
"enforce-barrel-exports": enforceBarrelExportsRule,
|
|
5119
|
+
"config-extraction": configExtractionRule,
|
|
5120
|
+
"value-extraction": valueExtractionRule,
|
|
5121
|
+
"type-extraction": typeExtractionRule,
|
|
5122
|
+
"zod-schema-validation": zodSchemaValidationRule,
|
|
5123
|
+
"source-under-src": sourceUnderSrcRule,
|
|
5124
|
+
"zirka-baseline": zirkaBaselineRule
|
|
5125
|
+
};
|
|
5126
|
+
var nextjsAppRules = {
|
|
5127
|
+
"component-placement": componentPlacementRule,
|
|
5128
|
+
"application-structure": applicationStructureRule,
|
|
5129
|
+
"data-testid-case": dataTestIdCaseRule,
|
|
4840
5130
|
"jsx-hygiene": jsxHygieneRule,
|
|
4841
5131
|
"interactive-component": interactiveComponentRule,
|
|
4842
5132
|
"ui-state": uiStateRule,
|
|
4843
|
-
"filename-case": filenameCaseRule,
|
|
4844
|
-
"import-boundaries": importBoundariesRule,
|
|
4845
5133
|
"no-mixed-concerns": noMixedConcernsRule,
|
|
4846
5134
|
"no-arbitrary-tailwind": noArbitraryTailwindRule,
|
|
4847
5135
|
"enforce-cn-merge": enforceCnMergeRule,
|
|
5136
|
+
"cn-helper": cnHelperRule,
|
|
4848
5137
|
"enforce-cva-variant-props": enforceCvaVariantPropsRule,
|
|
4849
5138
|
"cva-appearance-props": cvaAppearancePropsRule,
|
|
4850
5139
|
"cva-boolean-variants": cvaBooleanVariantsRule,
|
|
4851
|
-
"enforce-barrel-exports": enforceBarrelExportsRule,
|
|
4852
5140
|
"cross-feature-import": crossFeatureImportRule,
|
|
4853
5141
|
"pure-function-extract": pureFunctionExtractRule,
|
|
4854
5142
|
"hook-complexity": hookComplexityRule,
|
|
4855
5143
|
"locale-dotted-path": localeDottedPathRule,
|
|
4856
5144
|
"locales-location": localesLocationRule,
|
|
4857
5145
|
"hook-extraction": hookExtractionRule,
|
|
4858
|
-
"value-extraction": valueExtractionRule,
|
|
4859
|
-
"config-extraction": configExtractionRule,
|
|
4860
5146
|
"component-nesting": componentNestingRule,
|
|
4861
5147
|
"stay-flat": stayFlatRule,
|
|
4862
|
-
"type-extraction": typeExtractionRule,
|
|
4863
5148
|
"locale-placement": localePlacementRule,
|
|
4864
5149
|
"sole-state-owner": soleStateOwnerRule,
|
|
4865
5150
|
"locale-key-shape": localeKeyShapeRule,
|
|
4866
5151
|
"shared-style-dedup": sharedStyleDedupRule,
|
|
4867
|
-
"repeated-structure": repeatedStructureRule
|
|
4868
|
-
|
|
4869
|
-
|
|
4870
|
-
|
|
5152
|
+
"repeated-structure": repeatedStructureRule
|
|
5153
|
+
};
|
|
5154
|
+
var pasikaRules = {
|
|
5155
|
+
...typescriptAppRules,
|
|
5156
|
+
...nextjsAppRules
|
|
4871
5157
|
};
|
|
4872
|
-
|
|
4873
|
-
|
|
4874
|
-
|
|
4875
|
-
var
|
|
4876
|
-
var
|
|
4877
|
-
var
|
|
5158
|
+
function ruleIds(rules2) {
|
|
5159
|
+
return Object.keys(rules2).map((name) => `pasika/${name}`);
|
|
5160
|
+
}
|
|
5161
|
+
var typescriptAppRuleIds = ruleIds(typescriptAppRules);
|
|
5162
|
+
var nextjsAppRuleIds = ruleIds(nextjsAppRules);
|
|
5163
|
+
var pasikaRuleIds = ruleIds(pasikaRules);
|
|
5164
|
+
var documentationRuleIds = ruleIds(documentationRules);
|
|
5165
|
+
var tailwindRuleIds = ruleIds(tailwindRules);
|
|
5166
|
+
var repoPackageJsonRuleIds = ruleIds(repoPackageJsonRules);
|
|
5167
|
+
var nextPackageJsonRuleIds = ruleIds(nextPackageJsonRules);
|
|
5168
|
+
var huskyRuleIds = ruleIds(huskyRules);
|
|
5169
|
+
var vulykRuleIds = ruleIds(vulykRules);
|
|
5170
|
+
var allPasikaRuleIds = [
|
|
5171
|
+
...pasikaRuleIds,
|
|
5172
|
+
...documentationRuleIds,
|
|
5173
|
+
...tailwindRuleIds,
|
|
5174
|
+
...repoPackageJsonRuleIds,
|
|
5175
|
+
...nextPackageJsonRuleIds,
|
|
5176
|
+
...huskyRuleIds,
|
|
5177
|
+
...vulykRuleIds
|
|
5178
|
+
];
|
|
5179
|
+
var typescriptAppBlock = {
|
|
4878
5180
|
files: ["src/**/*.{cjs,cts,js,jsx,mjs,mts,ts,tsx}"],
|
|
4879
5181
|
plugins: {
|
|
4880
|
-
pasika: { rules:
|
|
5182
|
+
pasika: { rules: typescriptAppRules }
|
|
4881
5183
|
},
|
|
4882
|
-
rules: Object.fromEntries(
|
|
5184
|
+
rules: Object.fromEntries(typescriptAppRuleIds.map((id) => [id, "error"]))
|
|
4883
5185
|
};
|
|
5186
|
+
var nextjsAppBlock = {
|
|
5187
|
+
files: ["src/**/*.{cjs,cts,js,jsx,mjs,mts,ts,tsx}"],
|
|
5188
|
+
plugins: {
|
|
5189
|
+
pasika: { rules: nextjsAppRules }
|
|
5190
|
+
},
|
|
5191
|
+
rules: Object.fromEntries(nextjsAppRuleIds.map((id) => [id, "error"]))
|
|
5192
|
+
};
|
|
5193
|
+
var tailwindGlobalsBlock = {
|
|
5194
|
+
files: ["src/**/globals.css"],
|
|
5195
|
+
plugins: {
|
|
5196
|
+
css,
|
|
5197
|
+
pasika: { rules: tailwindRules }
|
|
5198
|
+
},
|
|
5199
|
+
language: "css/css",
|
|
5200
|
+
languageOptions: { tolerant: true },
|
|
5201
|
+
rules: Object.fromEntries(
|
|
5202
|
+
tailwindRuleIds.filter((id) => id !== "pasika/global-css-location").map((id) => [id, "error"])
|
|
5203
|
+
)
|
|
5204
|
+
};
|
|
5205
|
+
var tailwindAnyCssBlock = {
|
|
5206
|
+
files: ["src/**/*.css"],
|
|
5207
|
+
plugins: {
|
|
5208
|
+
css,
|
|
5209
|
+
pasika: { rules: tailwindRules }
|
|
5210
|
+
},
|
|
5211
|
+
language: "css/css",
|
|
5212
|
+
languageOptions: { tolerant: true },
|
|
5213
|
+
rules: { "pasika/global-css-location": "error" }
|
|
5214
|
+
};
|
|
5215
|
+
var repoManifestBlock = {
|
|
5216
|
+
files: ["package.json"],
|
|
5217
|
+
plugins: {
|
|
5218
|
+
json: { languages: { json: jsonPlugin.languages.json } },
|
|
5219
|
+
pasika: { rules: { ...repoPackageJsonRules, ...huskyRules, ...vulykRules } }
|
|
5220
|
+
},
|
|
5221
|
+
language: "json/json",
|
|
5222
|
+
rules: Object.fromEntries([...repoPackageJsonRuleIds, ...huskyRuleIds, ...vulykRuleIds].map((id) => [id, "error"]))
|
|
5223
|
+
};
|
|
5224
|
+
var nextManifestBlock = {
|
|
5225
|
+
files: ["package.json"],
|
|
5226
|
+
plugins: {
|
|
5227
|
+
json: { languages: { json: jsonPlugin.languages.json } },
|
|
5228
|
+
pasika: { rules: nextPackageJsonRules }
|
|
5229
|
+
},
|
|
5230
|
+
language: "json/json",
|
|
5231
|
+
rules: Object.fromEntries(nextPackageJsonRuleIds.map((id) => [id, "error"]))
|
|
5232
|
+
};
|
|
5233
|
+
var zirkaBlock = {
|
|
5234
|
+
files: ["eslint.config.{ts,mts,cts,js,mjs,cjs}"],
|
|
5235
|
+
plugins: { pasika: { rules: { "zirka-baseline": zirkaBaselineRule } } },
|
|
5236
|
+
rules: { "pasika/zirka-baseline": "error" }
|
|
5237
|
+
};
|
|
5238
|
+
var docsBlock = {
|
|
5239
|
+
files: ["docs/**/*.md"],
|
|
5240
|
+
ignores: ["**/_*/**"],
|
|
5241
|
+
plugins: {
|
|
5242
|
+
markdown,
|
|
5243
|
+
pasika: { rules: documentationRules }
|
|
5244
|
+
},
|
|
5245
|
+
language: "markdown/gfm",
|
|
5246
|
+
rules: Object.fromEntries(documentationRuleIds.map((id) => [id, "error"]))
|
|
5247
|
+
};
|
|
5248
|
+
var typescriptApp = [repoManifestBlock, zirkaBlock, typescriptAppBlock, docsBlock];
|
|
5249
|
+
var nextjsApp = [
|
|
5250
|
+
...typescriptApp,
|
|
5251
|
+
nextManifestBlock,
|
|
5252
|
+
nextjsAppBlock,
|
|
5253
|
+
tailwindGlobalsBlock,
|
|
5254
|
+
tailwindAnyCssBlock
|
|
5255
|
+
];
|
|
4884
5256
|
export {
|
|
4885
5257
|
allPasikaRuleIds,
|
|
4886
|
-
|
|
4887
|
-
|
|
4888
|
-
|
|
4889
|
-
|
|
4890
|
-
|
|
4891
|
-
|
|
4892
|
-
|
|
4893
|
-
|
|
4894
|
-
|
|
5258
|
+
documentationRules,
|
|
5259
|
+
huskyRules,
|
|
5260
|
+
nextPackageJsonRules,
|
|
5261
|
+
nextjsApp,
|
|
5262
|
+
pasikaRules,
|
|
5263
|
+
repoPackageJsonRules,
|
|
5264
|
+
tailwindRules,
|
|
5265
|
+
typescriptApp,
|
|
5266
|
+
vulykRules
|
|
4895
5267
|
};
|