pasika 0.3.8 → 0.3.9
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 +49 -31
- package/dist/eslint/pasika/index.d.ts +41 -23
- package/dist/eslint/pasika/index.js +329 -94
- package/package.json +25 -20
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# pasika
|
|
2
2
|
|
|
3
|
-
Documentation, the lint rules derived from it, and the
|
|
3
|
+
Documentation, the lint rules derived from it, and the checks that apply and diagnose both.
|
|
4
4
|
|
|
5
5
|
`pasika` owns the framework's documentation and turns it into checks. Every requirement in `docs/` is recorded in an enforcement registry that says which ESLint rule or `pasika` check governs it — or, when none does, how a reviewer or agent applies it by hand. CI fails when a requirement has no recorded answer.
|
|
6
6
|
|
|
@@ -8,20 +8,24 @@ Documentation, the lint rules derived from it, and the CLI that applies and diag
|
|
|
8
8
|
|
|
9
9
|
```text
|
|
10
10
|
docs/
|
|
11
|
-
repository-policy.md # agent-conduct requirements (Policy)
|
|
12
11
|
repository-policy.md # repo-wide code and documentation requirements (Policy)
|
|
13
12
|
code-organization-guide/ # placement, extraction, module conventions
|
|
14
13
|
documentation-guide/ # how documents themselves are written
|
|
15
14
|
framework-adoption-guide/ # adopting and updating the framework
|
|
16
15
|
styling-guide/ # Tailwind theme, composition, variants, states
|
|
17
|
-
|
|
16
|
+
scripts/
|
|
18
17
|
registry.json # requirement → enforcement, keyed by content hash
|
|
19
18
|
coverage.ts # reconciles the docs against the registry
|
|
19
|
+
utils/ # doc parsing, classification, registry IO
|
|
20
|
+
types/ # registry schema
|
|
21
|
+
constants/
|
|
22
|
+
rfc2119.ts # single source of truth for RFC 2119 vocabulary
|
|
20
23
|
eslint/
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
rules/ # the lint rules, with fixture tests beside them
|
|
25
|
+
rules/documentation/ # the documentation-guide rules, linting docs/ itself
|
|
26
|
+
rules/tailwind/ # the Tailwind stylesheet rules
|
|
27
|
+
rules/package-json/ # the package.json rules
|
|
28
|
+
rules/husky/ # the husky-hook rules
|
|
25
29
|
```
|
|
26
30
|
|
|
27
31
|
## Documentation
|
|
@@ -46,27 +50,36 @@ The `text` field is the bullet as written in the document (markdown links and co
|
|
|
46
50
|
|
|
47
51
|
Every requirement carries a `note` explaining how it is met: what the ref'd rule or doctor check does and where it falls short, or — with no `ref` — how a reviewer or agent applies it by hand. When a rule governs the requirement's subject without fully deciding it (e.g. its placement), the `ref` still names that rule and the `note` says what stays judgment, so a partial check never reads as a complete one.
|
|
48
52
|
|
|
49
|
-
`
|
|
53
|
+
`npm run coverage` fails when a requirement has no recorded answer, when its text changed, when it disappeared, when its `ref` names a rule or doctor check that does not exist, or when a requirement a rule governs has no test titled with its text. Confirm a reworded requirement with `npx tsx scripts/coverage.ts --accept`.
|
|
50
54
|
|
|
51
55
|
## Commands
|
|
52
56
|
|
|
53
57
|
The documentation guide itself is linted: the `pasika/*` markdown rules run over `docs/**/*.md` and report title, overview, structure, example-pairing, and RFC 2119 violations at the exact node.
|
|
54
58
|
|
|
59
|
+
The coverage checks are standalone scripts under `scripts/`, run with `tsx`; the drift check is the published `libyear` tool — there is no `pasika` binary:
|
|
60
|
+
|
|
55
61
|
```bash
|
|
56
|
-
|
|
57
|
-
|
|
62
|
+
npm run coverage # check that every requirement has recorded enforcement
|
|
63
|
+
npm run coverage -- --accept # record reworded and removed requirements
|
|
64
|
+
npx libyear --limit-major-individual=1 # fail when a dependency trails the latest by >1 major (drift check)
|
|
58
65
|
```
|
|
59
66
|
|
|
60
|
-
Both accept `--json` for agent use
|
|
67
|
+
Both acceptance and the report accept `--json` for agent use:
|
|
61
68
|
|
|
62
|
-
|
|
69
|
+
```bash
|
|
70
|
+
npx tsx scripts/coverage.ts # text report
|
|
71
|
+
npx tsx scripts/coverage.ts --json # full report as JSON
|
|
72
|
+
npx tsx scripts/coverage.ts --accept # record accepted changes
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
A requirement the report shows as `new` is classified with the hash it prints:
|
|
63
76
|
|
|
64
77
|
```bash
|
|
65
|
-
npx
|
|
66
|
-
npx
|
|
78
|
+
npx tsx scripts/coverage.ts --classify d311a1457a --ref pasika/import-boundaries --note "reports imports that cross a feature boundary"
|
|
79
|
+
npx tsx scripts/coverage.ts --classify 041b665bd7 --note "no check can compare against the previous state"
|
|
67
80
|
```
|
|
68
81
|
|
|
69
|
-
The
|
|
82
|
+
The script refuses a hash no requirement has, a `ref` naming a rule or doctor check that does not exist, and a classification without a note — so a mismatch cannot reach the registry by hand. Re-running it on an already-recorded requirement replaces the earlier entry. All of it reads and writes `scripts/registry.json`.
|
|
70
83
|
|
|
71
84
|
## ESLint ruleset
|
|
72
85
|
|
|
@@ -90,14 +103,14 @@ export default eslintConfig;
|
|
|
90
103
|
|
|
91
104
|
### Without Zirka
|
|
92
105
|
|
|
93
|
-
|
|
106
|
+
````ts
|
|
94
107
|
// eslint.config.ts
|
|
95
|
-
import {
|
|
108
|
+
import { pasikaNext } from "pasika/eslint";
|
|
96
109
|
|
|
97
|
-
export default
|
|
98
|
-
```
|
|
110
|
+
export default pasikaNext;
|
|
111
|
+
``` `pasikaNext` is the full flat-config array: the `src/**` TS/TSX and Tailwind stylesheet blocks plus everything in `pasikaRepo`. `pasikaRepo` is the repository-level preset — every block that does not touch `src/**` (the package.json manifest, husky hooks, and docs) — and is a strict subset of `pasikaNext`. The granular rule objects (`tailwindRules`, `repoPackageJsonRules`, `documentationRules`) stay exported for manual wiring.
|
|
99
112
|
|
|
100
|
-
|
|
113
|
+
Because the preset blocks wire ESLint's language plugins, using `pasikaNext` directly (without `zirka`) requires `@eslint/css`, `@eslint/json`, and `@eslint/markdown` to be installed in the consuming project — they are `peerDependencies` of `pasika`. A `zirka`-based setup gets them automatically.
|
|
101
114
|
|
|
102
115
|
### TS/TSX rules
|
|
103
116
|
|
|
@@ -140,11 +153,11 @@ export default [pasikaConfig];
|
|
|
140
153
|
| `pasika/shared-style-dedup` † | A className combo used by two or more components becomes a named utility |
|
|
141
154
|
| `pasika/repeated-structure` | A block of elements repeated two or more times is extracted as a named component |
|
|
142
155
|
| `pasika/sole-state-owner` | A contiguous JSX part that is the sole consumer of a useState hook is extracted into a named component |
|
|
143
|
-
| `pasika/
|
|
156
|
+
| `pasika/config-baseline` | `eslint.config.*` references zirka and `tsconfig.json` exists |
|
|
144
157
|
| `pasika/zod-schema-validation` | Runtime validation through Zod schemas, not hand-written type guards |
|
|
145
158
|
| `pasika/source-under-src` | Application source lives under `src/`, not in root-level folders |
|
|
146
159
|
|
|
147
|
-
###
|
|
160
|
+
### Tailwind rules
|
|
148
161
|
|
|
149
162
|
Applied to `src/**/globals.css` (and other stylesheets) through `@eslint/css` with tolerant Tailwind v4 parsing.
|
|
150
163
|
|
|
@@ -161,20 +174,21 @@ Applied to `src/**/globals.css` (and other stylesheets) through `@eslint/css` wi
|
|
|
161
174
|
| `pasika/theme-variable-namespace` | Utility class groups share a namespace prefix |
|
|
162
175
|
| `pasika/global-css-location` | Global CSS lives in the correct entry point |
|
|
163
176
|
|
|
164
|
-
###
|
|
177
|
+
### Package.json rules
|
|
165
178
|
|
|
166
|
-
Applied to `package.json` through `@eslint/json`.
|
|
179
|
+
Applied to `package.json` through `@eslint/json`. The framework-agnostic subset (`no-vulyk-dependency`, `exact-version`) applies to any repository, including pasika itself; `nextjs-stack` applies to a Next.js/React application.
|
|
167
180
|
|
|
168
|
-
| Rule | Enforces
|
|
169
|
-
| ---------------------------- |
|
|
170
|
-
| `pasika/no-
|
|
171
|
-
| `pasika/
|
|
181
|
+
| Rule | Enforces |
|
|
182
|
+
| ---------------------------- | ----------------------------------------------------------------------------------- |
|
|
183
|
+
| `pasika/no-vulyk-dependency` | `vulyk` is not in `dependencies` |
|
|
184
|
+
| `pasika/exact-version` | Dependency and devDependency versions are pinned exactly, never ranges |
|
|
185
|
+
| `pasika/nextjs-stack` | All Tech Stack Reference packages are listed in `package.json` (Next.js/React apps) |
|
|
172
186
|
|
|
173
187
|
### Documentation rules
|
|
174
188
|
|
|
175
|
-
The `pasika/*` markdown rules enforce the documentation guide over `docs/**/*.md` (24 rules): file-name suffixes and titles, overview presence and length, guide step structure, Incorrect/Correct pairing, policy document shape, reference block headings, RFC 2119 placement, template hygiene, link anchoring, and glossary-term linking. They run through `@eslint/markdown`; `
|
|
189
|
+
The `pasika/*` markdown rules enforce the documentation guide over `docs/**/*.md` (24 rules): file-name suffixes and titles, overview presence and length, guide step structure, Incorrect/Correct pairing, policy document shape, reference block headings, RFC 2119 placement, template hygiene, link anchoring, and glossary-term linking. They run through `@eslint/markdown`; `npm run coverage` verifies each has a test and a registry entry. Pasika's own `docs/` are linted by them in CI (`npm run lint`).
|
|
176
190
|
|
|
177
|
-
Run `
|
|
191
|
+
Run `npx tsx scripts/coverage.ts --json` for the exact requirement each rule covers.
|
|
178
192
|
|
|
179
193
|
### † Cross-file rules
|
|
180
194
|
|
|
@@ -185,6 +199,10 @@ Where a component, hook, value, type, or style belongs depends on which files us
|
|
|
185
199
|
|
|
186
200
|
All are inert in a repository with no `src/` tree.
|
|
187
201
|
|
|
202
|
+
## Runtime dependency on typescript
|
|
203
|
+
|
|
204
|
+
Many of the TS/TSX rules call the TypeScript compiler API directly at lint time, so the published package imports `typescript` at runtime. `tsup` keeps it external (unbundled); `pasika` lists it as a pinned `dependency` so an installing consumer gets a version known to work with the rules. There is no `typescript` `peerDependency`.
|
|
205
|
+
|
|
188
206
|
## Development
|
|
189
207
|
|
|
190
208
|
```bash
|
|
@@ -193,4 +211,4 @@ npm run typecheck
|
|
|
193
211
|
npm run test
|
|
194
212
|
npm run coverage
|
|
195
213
|
npm run build
|
|
196
|
-
|
|
214
|
+
````
|
|
@@ -74,7 +74,7 @@ type JsxOpeningElementNode = Rule.Node & {
|
|
|
74
74
|
parent?: JsxElementNode;
|
|
75
75
|
};
|
|
76
76
|
|
|
77
|
-
declare const
|
|
77
|
+
declare const documentationRules: {
|
|
78
78
|
"doc-kind-suffix": _eslint_markdown.MarkdownRuleDefinition;
|
|
79
79
|
"title-matches-file-name": _eslint_markdown.MarkdownRuleDefinition;
|
|
80
80
|
"overview-present": _eslint_markdown.MarkdownRuleDefinition;
|
|
@@ -101,7 +101,7 @@ declare const mdRules: {
|
|
|
101
101
|
"glossary-term-linking": _eslint_markdown.MarkdownRuleDefinition;
|
|
102
102
|
};
|
|
103
103
|
|
|
104
|
-
declare const
|
|
104
|
+
declare const tailwindRules: {
|
|
105
105
|
"theme-reset": _eslint_css.CSSRuleDefinition;
|
|
106
106
|
"root-variables": _eslint_css.CSSRuleDefinition;
|
|
107
107
|
"apply-usage": _eslint_css.CSSRuleDefinition;
|
|
@@ -115,26 +115,28 @@ declare const cssRules: {
|
|
|
115
115
|
"global-stylesheet": _eslint_css.CSSRuleDefinition;
|
|
116
116
|
};
|
|
117
117
|
|
|
118
|
-
|
|
118
|
+
/** Framework-agnostic package.json rules any repository should follow. */
|
|
119
|
+
declare const repoPackageJsonRules: {
|
|
119
120
|
"no-vulyk-dependency": _eslint_json.JSONRuleDefinition;
|
|
120
|
-
"
|
|
121
|
+
"exact-version": _eslint_json.JSONRuleDefinition;
|
|
122
|
+
};
|
|
123
|
+
/** Package.json rules specific to a Next.js (or React) application. */
|
|
124
|
+
declare const nextPackageJsonRules: {
|
|
125
|
+
"nextjs-stack": _eslint_json.JSONRuleDefinition;
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
declare const huskyRules: {
|
|
129
|
+
"husky-hook": _eslint_json.JSONRuleDefinition;
|
|
121
130
|
};
|
|
122
131
|
|
|
132
|
+
/** Every source rule, merged so the Next preset applies them all. */
|
|
123
133
|
declare const pasikaRules: {
|
|
124
134
|
"component-placement": eslint.Rule.RuleModule;
|
|
125
|
-
"support-file-placement": eslint.Rule.RuleModule;
|
|
126
135
|
"application-structure": eslint.Rule.RuleModule;
|
|
127
|
-
"named-exports": eslint.Rule.RuleModule;
|
|
128
136
|
"data-testid-case": eslint.Rule.RuleModule;
|
|
129
|
-
"support-folder-shape": eslint.Rule.RuleModule;
|
|
130
|
-
"import-through-index": eslint.Rule.RuleModule;
|
|
131
|
-
"util-file-name": eslint.Rule.RuleModule;
|
|
132
|
-
"no-util-barrel": eslint.Rule.RuleModule;
|
|
133
137
|
"jsx-hygiene": eslint.Rule.RuleModule;
|
|
134
138
|
"interactive-component": eslint.Rule.RuleModule;
|
|
135
139
|
"ui-state": eslint.Rule.RuleModule;
|
|
136
|
-
"filename-case": eslint.Rule.RuleModule;
|
|
137
|
-
"import-boundaries": eslint.Rule.RuleModule;
|
|
138
140
|
"no-mixed-concerns": eslint.Rule.RuleModule;
|
|
139
141
|
"no-arbitrary-tailwind": eslint.Rule.RuleModule;
|
|
140
142
|
"enforce-cn-merge": {
|
|
@@ -149,38 +151,54 @@ declare const pasikaRules: {
|
|
|
149
151
|
JSXAttribute(node: JsxAttributeNode): void;
|
|
150
152
|
};
|
|
151
153
|
};
|
|
154
|
+
"cn-helper": eslint.Rule.RuleModule;
|
|
152
155
|
"enforce-cva-variant-props": eslint.Rule.RuleModule;
|
|
153
156
|
"cva-appearance-props": eslint.Rule.RuleModule;
|
|
154
157
|
"cva-boolean-variants": eslint.Rule.RuleModule;
|
|
155
|
-
"enforce-barrel-exports": eslint.Rule.RuleModule;
|
|
156
158
|
"cross-feature-import": eslint.Rule.RuleModule;
|
|
157
159
|
"pure-function-extract": eslint.Rule.RuleModule;
|
|
158
160
|
"hook-complexity": eslint.Rule.RuleModule;
|
|
159
161
|
"locale-dotted-path": eslint.Rule.RuleModule;
|
|
160
162
|
"locales-location": eslint.Rule.RuleModule;
|
|
161
163
|
"hook-extraction": eslint.Rule.RuleModule;
|
|
162
|
-
"value-extraction": eslint.Rule.RuleModule;
|
|
163
|
-
"config-extraction": eslint.Rule.RuleModule;
|
|
164
164
|
"component-nesting": eslint.Rule.RuleModule;
|
|
165
165
|
"stay-flat": eslint.Rule.RuleModule;
|
|
166
|
-
"type-extraction": eslint.Rule.RuleModule;
|
|
167
166
|
"locale-placement": eslint.Rule.RuleModule;
|
|
168
167
|
"sole-state-owner": eslint.Rule.RuleModule;
|
|
169
168
|
"locale-key-shape": eslint.Rule.RuleModule;
|
|
170
169
|
"shared-style-dedup": eslint.Rule.RuleModule;
|
|
171
170
|
"repeated-structure": eslint.Rule.RuleModule;
|
|
171
|
+
"filename-case": eslint.Rule.RuleModule;
|
|
172
|
+
"import-boundaries": eslint.Rule.RuleModule;
|
|
173
|
+
"named-exports": eslint.Rule.RuleModule;
|
|
174
|
+
"support-file-placement": eslint.Rule.RuleModule;
|
|
175
|
+
"support-folder-shape": eslint.Rule.RuleModule;
|
|
176
|
+
"import-through-index": eslint.Rule.RuleModule;
|
|
177
|
+
"util-file-name": eslint.Rule.RuleModule;
|
|
178
|
+
"no-util-barrel": eslint.Rule.RuleModule;
|
|
179
|
+
"enforce-barrel-exports": eslint.Rule.RuleModule;
|
|
180
|
+
"config-extraction": eslint.Rule.RuleModule;
|
|
181
|
+
"value-extraction": eslint.Rule.RuleModule;
|
|
182
|
+
"type-extraction": eslint.Rule.RuleModule;
|
|
172
183
|
"zod-schema-validation": eslint.Rule.RuleModule;
|
|
173
184
|
"source-under-src": eslint.Rule.RuleModule;
|
|
174
185
|
"config-baseline": eslint.Rule.RuleModule;
|
|
175
186
|
};
|
|
176
187
|
|
|
177
|
-
/** Rule ids as they appear in configuration and in lint output. */
|
|
178
|
-
declare const pasikaRuleIds: string[];
|
|
179
|
-
declare const pasikaMdRuleIds: string[];
|
|
180
|
-
declare const pasikaCssRuleIds: string[];
|
|
181
|
-
declare const pasikaJsonRuleIds: string[];
|
|
182
188
|
/** Every rule id, as they appear in configuration and in lint output. */
|
|
183
189
|
declare const allPasikaRuleIds: string[];
|
|
184
|
-
|
|
190
|
+
/**
|
|
191
|
+
* Repository-level preset: every block that does NOT touch `src/**` — the
|
|
192
|
+
* package.json manifest (including husky hook requirements) and the
|
|
193
|
+
* documentation-guide markdown rules. This governs the repository itself,
|
|
194
|
+
* independent of any application source.
|
|
195
|
+
*/
|
|
196
|
+
declare const pasikaRepo: Linter.Config[];
|
|
197
|
+
/**
|
|
198
|
+
* Framework-wide preset: the full adopted-to-the-framework stack. Anything in
|
|
199
|
+
* `pasikaRepo` plus the `src/**` blocks — TS/TSX source rules and the Tailwind
|
|
200
|
+
* stylesheet rules. `pasikaRepo` is a strict subset of `pasikaNext`.
|
|
201
|
+
*/
|
|
202
|
+
declare const pasikaNext: Linter.Config[];
|
|
185
203
|
|
|
186
|
-
export { allPasikaRuleIds,
|
|
204
|
+
export { allPasikaRuleIds, documentationRules, huskyRules, nextPackageJsonRules, pasikaNext, pasikaRepo, pasikaRules, repoPackageJsonRules, tailwindRules };
|
|
@@ -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: {
|
|
@@ -3262,10 +3304,13 @@ var configBaselineRule = {
|
|
|
3262
3304
|
}
|
|
3263
3305
|
};
|
|
3264
3306
|
|
|
3265
|
-
//
|
|
3266
|
-
var
|
|
3307
|
+
// constants/rfc2119.ts
|
|
3308
|
+
var RFC_2119_KEYWORDS = ["MUST NOT", "MUST", "SHOULD NOT", "SHOULD", "MAY"];
|
|
3309
|
+
var RFC_2119_PATTERN = new RegExp(`\\b(?<keyword>${RFC_2119_KEYWORDS.join("|")})\\b`);
|
|
3310
|
+
|
|
3311
|
+
// eslint/rules/documentation/helpers.ts
|
|
3267
3312
|
function containsRfcKeyword(text) {
|
|
3268
|
-
const match =
|
|
3313
|
+
const match = RFC_2119_PATTERN.exec(text);
|
|
3269
3314
|
return match?.groups?.keyword ?? null;
|
|
3270
3315
|
}
|
|
3271
3316
|
function getFilename(context) {
|
|
@@ -3282,7 +3327,7 @@ function getLine(node) {
|
|
|
3282
3327
|
return node.position?.start.line ?? 0;
|
|
3283
3328
|
}
|
|
3284
3329
|
|
|
3285
|
-
// eslint/rules/
|
|
3330
|
+
// eslint/rules/documentation/doc-kind-suffix.ts
|
|
3286
3331
|
var docKindSuffixRule = {
|
|
3287
3332
|
meta: {
|
|
3288
3333
|
type: "problem",
|
|
@@ -3308,7 +3353,7 @@ var docKindSuffixRule = {
|
|
|
3308
3353
|
}
|
|
3309
3354
|
};
|
|
3310
3355
|
|
|
3311
|
-
// eslint/rules/
|
|
3356
|
+
// eslint/rules/documentation/title-matches-file-name.ts
|
|
3312
3357
|
import path34 from "path";
|
|
3313
3358
|
function toExpectedFileName(title) {
|
|
3314
3359
|
return `${title.toLowerCase().replaceAll(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "")}.md`;
|
|
@@ -3346,7 +3391,7 @@ var titleMatchesFileNameRule = {
|
|
|
3346
3391
|
}
|
|
3347
3392
|
};
|
|
3348
3393
|
|
|
3349
|
-
// eslint/rules/
|
|
3394
|
+
// eslint/rules/documentation/overview-present.ts
|
|
3350
3395
|
var overviewPresentRule = {
|
|
3351
3396
|
meta: {
|
|
3352
3397
|
type: "problem",
|
|
@@ -3386,7 +3431,7 @@ var overviewPresentRule = {
|
|
|
3386
3431
|
}
|
|
3387
3432
|
};
|
|
3388
3433
|
|
|
3389
|
-
// eslint/rules/
|
|
3434
|
+
// eslint/rules/documentation/overview-length.ts
|
|
3390
3435
|
function countSentences(text) {
|
|
3391
3436
|
return text.split(/[.!?](?:\s+|$)/).filter((part) => part.trim() !== "").length;
|
|
3392
3437
|
}
|
|
@@ -3429,7 +3474,7 @@ var overviewLengthRule = {
|
|
|
3429
3474
|
}
|
|
3430
3475
|
};
|
|
3431
3476
|
|
|
3432
|
-
// eslint/rules/
|
|
3477
|
+
// eslint/rules/documentation/guide-overview-no-links.ts
|
|
3433
3478
|
function containsLink(node) {
|
|
3434
3479
|
if (node.type === "link") return true;
|
|
3435
3480
|
if ("children" in node) {
|
|
@@ -3475,7 +3520,7 @@ var guideOverviewNoLinksRule = {
|
|
|
3475
3520
|
}
|
|
3476
3521
|
};
|
|
3477
3522
|
|
|
3478
|
-
// eslint/rules/
|
|
3523
|
+
// eslint/rules/documentation/guide-step-single-sentence.ts
|
|
3479
3524
|
function countSentences2(text) {
|
|
3480
3525
|
return text.split(/[.!?](?:\s+|$)/).filter((part) => part.trim() !== "").length;
|
|
3481
3526
|
}
|
|
@@ -3513,7 +3558,7 @@ var guideStepSingleSentenceRule = {
|
|
|
3513
3558
|
}
|
|
3514
3559
|
};
|
|
3515
3560
|
|
|
3516
|
-
// eslint/rules/
|
|
3561
|
+
// eslint/rules/documentation/guide-step-single-link.ts
|
|
3517
3562
|
function countDocLinks(node) {
|
|
3518
3563
|
if (node.type === "link" && node.url.endsWith(".md")) return 1;
|
|
3519
3564
|
if ("children" in node) {
|
|
@@ -3556,7 +3601,7 @@ var guideStepSingleLinkRule = {
|
|
|
3556
3601
|
}
|
|
3557
3602
|
};
|
|
3558
3603
|
|
|
3559
|
-
// eslint/rules/
|
|
3604
|
+
// eslint/rules/documentation/guide-states-no-requirement.ts
|
|
3560
3605
|
var guideStatesNoRequirementRule = {
|
|
3561
3606
|
meta: {
|
|
3562
3607
|
type: "problem",
|
|
@@ -3582,7 +3627,7 @@ var guideStatesNoRequirementRule = {
|
|
|
3582
3627
|
}
|
|
3583
3628
|
};
|
|
3584
3629
|
|
|
3585
|
-
// eslint/rules/
|
|
3630
|
+
// eslint/rules/documentation/requirement-present.ts
|
|
3586
3631
|
function hasRequirement(node) {
|
|
3587
3632
|
if (node.type === "listItem") {
|
|
3588
3633
|
if (containsRfcKeyword(getTextContent(node))) return true;
|
|
@@ -3621,7 +3666,7 @@ var requirementPresentRule = {
|
|
|
3621
3666
|
}
|
|
3622
3667
|
};
|
|
3623
3668
|
|
|
3624
|
-
// eslint/rules/
|
|
3669
|
+
// eslint/rules/documentation/rule-paired-examples.ts
|
|
3625
3670
|
var rulePairedExamplesRule = {
|
|
3626
3671
|
meta: {
|
|
3627
3672
|
type: "problem",
|
|
@@ -3657,7 +3702,7 @@ var rulePairedExamplesRule = {
|
|
|
3657
3702
|
}
|
|
3658
3703
|
};
|
|
3659
3704
|
|
|
3660
|
-
// eslint/rules/
|
|
3705
|
+
// eslint/rules/documentation/example-heading-description.ts
|
|
3661
3706
|
var exampleHeadingDescriptionRule = {
|
|
3662
3707
|
meta: {
|
|
3663
3708
|
type: "problem",
|
|
@@ -3685,7 +3730,7 @@ var exampleHeadingDescriptionRule = {
|
|
|
3685
3730
|
}
|
|
3686
3731
|
};
|
|
3687
3732
|
|
|
3688
|
-
// eslint/rules/
|
|
3733
|
+
// eslint/rules/documentation/policy-no-examples.ts
|
|
3689
3734
|
var policyNoExamplesRule = {
|
|
3690
3735
|
meta: {
|
|
3691
3736
|
type: "problem",
|
|
@@ -3712,7 +3757,7 @@ var policyNoExamplesRule = {
|
|
|
3712
3757
|
}
|
|
3713
3758
|
};
|
|
3714
3759
|
|
|
3715
|
-
// eslint/rules/
|
|
3760
|
+
// eslint/rules/documentation/no-cross-document-link.ts
|
|
3716
3761
|
function linkedKind(filename) {
|
|
3717
3762
|
if (filename.endsWith("-rule.md")) return "rule";
|
|
3718
3763
|
if (filename.endsWith("-reference.md")) return "reference";
|
|
@@ -3744,7 +3789,7 @@ var noCrossDocumentLinkRule = {
|
|
|
3744
3789
|
}
|
|
3745
3790
|
};
|
|
3746
3791
|
|
|
3747
|
-
// eslint/rules/
|
|
3792
|
+
// eslint/rules/documentation/reference-no-rfc-vocabulary.ts
|
|
3748
3793
|
var referenceNoRfcVocabularyRule = {
|
|
3749
3794
|
meta: {
|
|
3750
3795
|
type: "problem",
|
|
@@ -3770,7 +3815,7 @@ var referenceNoRfcVocabularyRule = {
|
|
|
3770
3815
|
}
|
|
3771
3816
|
};
|
|
3772
3817
|
|
|
3773
|
-
// eslint/rules/
|
|
3818
|
+
// eslint/rules/documentation/reference-block-headings.ts
|
|
3774
3819
|
var referenceBlockHeadingsRule = {
|
|
3775
3820
|
meta: {
|
|
3776
3821
|
type: "problem",
|
|
@@ -3801,7 +3846,7 @@ var referenceBlockHeadingsRule = {
|
|
|
3801
3846
|
}
|
|
3802
3847
|
};
|
|
3803
3848
|
|
|
3804
|
-
// eslint/rules/
|
|
3849
|
+
// eslint/rules/documentation/support-document-placement.ts
|
|
3805
3850
|
import path35 from "path";
|
|
3806
3851
|
var supportDocumentPlacementRule = {
|
|
3807
3852
|
meta: {
|
|
@@ -3834,7 +3879,7 @@ var supportDocumentPlacementRule = {
|
|
|
3834
3879
|
}
|
|
3835
3880
|
};
|
|
3836
3881
|
|
|
3837
|
-
// eslint/rules/
|
|
3882
|
+
// eslint/rules/documentation/no-template-prompt.ts
|
|
3838
3883
|
var TEMPLATE_PROMPT = /^\s*\[[A-Z0-9].*\]\s*$/;
|
|
3839
3884
|
var noTemplatePromptRule = {
|
|
3840
3885
|
meta: {
|
|
@@ -3858,10 +3903,10 @@ var noTemplatePromptRule = {
|
|
|
3858
3903
|
}
|
|
3859
3904
|
};
|
|
3860
3905
|
|
|
3861
|
-
// eslint/rules/
|
|
3906
|
+
// eslint/rules/documentation/guide-folder-entry-point.ts
|
|
3862
3907
|
import path37 from "path";
|
|
3863
3908
|
|
|
3864
|
-
// eslint/rules/
|
|
3909
|
+
// eslint/rules/documentation/project-index.ts
|
|
3865
3910
|
import { readdirSync as readdirSync2, readFileSync as readFileSync4, statSync as statSync3 } from "fs";
|
|
3866
3911
|
import path36 from "path";
|
|
3867
3912
|
var KIND_BY_SUFFIX = [
|
|
@@ -3915,7 +3960,7 @@ function findDocsRoot(filePath) {
|
|
|
3915
3960
|
}
|
|
3916
3961
|
}
|
|
3917
3962
|
|
|
3918
|
-
// eslint/rules/
|
|
3963
|
+
// eslint/rules/documentation/guide-folder-entry-point.ts
|
|
3919
3964
|
var guideFolderEntryPointRule = {
|
|
3920
3965
|
meta: {
|
|
3921
3966
|
type: "problem",
|
|
@@ -3953,7 +3998,7 @@ var guideFolderEntryPointRule = {
|
|
|
3953
3998
|
}
|
|
3954
3999
|
};
|
|
3955
4000
|
|
|
3956
|
-
// eslint/rules/
|
|
4001
|
+
// eslint/rules/documentation/rfc-only-in-bullets.ts
|
|
3957
4002
|
function checkOutsideBullets(node, context, insideBullet) {
|
|
3958
4003
|
if (node.type === "listItem") {
|
|
3959
4004
|
for (const child of node.children) {
|
|
@@ -3996,7 +4041,7 @@ var rfcOnlyInBulletsRule = {
|
|
|
3996
4041
|
}
|
|
3997
4042
|
};
|
|
3998
4043
|
|
|
3999
|
-
// eslint/rules/
|
|
4044
|
+
// eslint/rules/documentation/rfc-keyword-in-every-bullet.ts
|
|
4000
4045
|
function checkBullets(node, context) {
|
|
4001
4046
|
if (node.type === "listItem" && !containsRfcKeyword(getTextContent(node))) {
|
|
4002
4047
|
context.report({
|
|
@@ -4029,7 +4074,7 @@ var rfcKeywordInEveryBulletRule = {
|
|
|
4029
4074
|
}
|
|
4030
4075
|
};
|
|
4031
4076
|
|
|
4032
|
-
// eslint/rules/
|
|
4077
|
+
// eslint/rules/documentation/policy-subject-headings.ts
|
|
4033
4078
|
var policySubjectHeadingsRule = {
|
|
4034
4079
|
meta: {
|
|
4035
4080
|
type: "problem",
|
|
@@ -4082,7 +4127,7 @@ var policySubjectHeadingsRule = {
|
|
|
4082
4127
|
}
|
|
4083
4128
|
};
|
|
4084
4129
|
|
|
4085
|
-
// eslint/rules/
|
|
4130
|
+
// eslint/rules/documentation/guide-link-anchors.ts
|
|
4086
4131
|
function visitSteps2(node, check) {
|
|
4087
4132
|
if (node.type === "list" && node.ordered) {
|
|
4088
4133
|
for (const child of node.children) check(child);
|
|
@@ -4126,7 +4171,7 @@ var guideLinkAnchorsRule = {
|
|
|
4126
4171
|
}
|
|
4127
4172
|
};
|
|
4128
4173
|
|
|
4129
|
-
// eslint/rules/
|
|
4174
|
+
// eslint/rules/documentation/no-nested-how-to.ts
|
|
4130
4175
|
var noNestedHowToRule = {
|
|
4131
4176
|
meta: {
|
|
4132
4177
|
type: "problem",
|
|
@@ -4162,7 +4207,7 @@ var noNestedHowToRule = {
|
|
|
4162
4207
|
}
|
|
4163
4208
|
};
|
|
4164
4209
|
|
|
4165
|
-
// eslint/rules/
|
|
4210
|
+
// eslint/rules/documentation/glossary-term-linking.ts
|
|
4166
4211
|
import { readFileSync as readFileSync5 } from "fs";
|
|
4167
4212
|
import path38 from "path";
|
|
4168
4213
|
function extractGlossaryTerms(filePath) {
|
|
@@ -4243,8 +4288,8 @@ var glossaryTermLinkingRule = {
|
|
|
4243
4288
|
}
|
|
4244
4289
|
};
|
|
4245
4290
|
|
|
4246
|
-
// eslint/rules/
|
|
4247
|
-
var
|
|
4291
|
+
// eslint/rules/documentation/index.ts
|
|
4292
|
+
var documentationRules = {
|
|
4248
4293
|
"doc-kind-suffix": docKindSuffixRule,
|
|
4249
4294
|
"title-matches-file-name": titleMatchesFileNameRule,
|
|
4250
4295
|
"overview-present": overviewPresentRule,
|
|
@@ -4271,7 +4316,7 @@ var mdRules = {
|
|
|
4271
4316
|
"glossary-term-linking": glossaryTermLinkingRule
|
|
4272
4317
|
};
|
|
4273
4318
|
|
|
4274
|
-
// eslint/rules/
|
|
4319
|
+
// eslint/rules/tailwind/helpers.ts
|
|
4275
4320
|
function walkNodes(node, visit) {
|
|
4276
4321
|
visit(node);
|
|
4277
4322
|
if ("children" in node && node.children) {
|
|
@@ -4328,7 +4373,7 @@ function selectorNames(node) {
|
|
|
4328
4373
|
return names;
|
|
4329
4374
|
}
|
|
4330
4375
|
|
|
4331
|
-
// eslint/rules/
|
|
4376
|
+
// eslint/rules/tailwind/theme-reset.ts
|
|
4332
4377
|
var themeResetRule = {
|
|
4333
4378
|
meta: {
|
|
4334
4379
|
schema: [],
|
|
@@ -4358,7 +4403,7 @@ var themeResetRule = {
|
|
|
4358
4403
|
}
|
|
4359
4404
|
};
|
|
4360
4405
|
|
|
4361
|
-
// eslint/rules/
|
|
4406
|
+
// eslint/rules/tailwind/root-variables.ts
|
|
4362
4407
|
var rootVariablesRule = {
|
|
4363
4408
|
meta: {
|
|
4364
4409
|
schema: [],
|
|
@@ -4401,7 +4446,7 @@ var rootVariablesRule = {
|
|
|
4401
4446
|
}
|
|
4402
4447
|
};
|
|
4403
4448
|
|
|
4404
|
-
// eslint/rules/
|
|
4449
|
+
// eslint/rules/tailwind/apply-usage.ts
|
|
4405
4450
|
var applyUsageRule = {
|
|
4406
4451
|
meta: {
|
|
4407
4452
|
schema: [],
|
|
@@ -4431,7 +4476,7 @@ var applyUsageRule = {
|
|
|
4431
4476
|
}
|
|
4432
4477
|
};
|
|
4433
4478
|
|
|
4434
|
-
// eslint/rules/
|
|
4479
|
+
// eslint/rules/tailwind/base-layer-pair.ts
|
|
4435
4480
|
var baseLayerPairRule = {
|
|
4436
4481
|
meta: {
|
|
4437
4482
|
schema: [],
|
|
@@ -4469,7 +4514,7 @@ var baseLayerPairRule = {
|
|
|
4469
4514
|
}
|
|
4470
4515
|
};
|
|
4471
4516
|
|
|
4472
|
-
// eslint/rules/
|
|
4517
|
+
// eslint/rules/tailwind/stylesheet-ordering.ts
|
|
4473
4518
|
var SECTION_ORDER = ["imports", "custom-variant", "root", "theme", "utility", "base styles", "keyframes"];
|
|
4474
4519
|
var stylesheetOrderingRule = {
|
|
4475
4520
|
meta: {
|
|
@@ -4526,7 +4571,7 @@ var stylesheetOrderingRule = {
|
|
|
4526
4571
|
}
|
|
4527
4572
|
};
|
|
4528
4573
|
|
|
4529
|
-
// eslint/rules/
|
|
4574
|
+
// eslint/rules/tailwind/css-variable-naming.ts
|
|
4530
4575
|
var cssVariableNamingRule = {
|
|
4531
4576
|
meta: {
|
|
4532
4577
|
schema: [],
|
|
@@ -4558,7 +4603,7 @@ var cssVariableNamingRule = {
|
|
|
4558
4603
|
}
|
|
4559
4604
|
};
|
|
4560
4605
|
|
|
4561
|
-
// eslint/rules/
|
|
4606
|
+
// eslint/rules/tailwind/custom-utility-apply.ts
|
|
4562
4607
|
function rawProperty(raw) {
|
|
4563
4608
|
const match = /^\s*(?<property>[a-z][a-z-]*)\s*:/.exec(raw);
|
|
4564
4609
|
return match?.groups?.property;
|
|
@@ -4600,7 +4645,7 @@ var customUtilityApplyRule = {
|
|
|
4600
4645
|
}
|
|
4601
4646
|
};
|
|
4602
4647
|
|
|
4603
|
-
// eslint/rules/
|
|
4648
|
+
// eslint/rules/tailwind/surface-utility.ts
|
|
4604
4649
|
var surfaceUtilityRule = {
|
|
4605
4650
|
meta: {
|
|
4606
4651
|
schema: [],
|
|
@@ -4633,7 +4678,7 @@ var surfaceUtilityRule = {
|
|
|
4633
4678
|
}
|
|
4634
4679
|
};
|
|
4635
4680
|
|
|
4636
|
-
// eslint/rules/
|
|
4681
|
+
// eslint/rules/tailwind/theme-variable-namespace.ts
|
|
4637
4682
|
var themeVariableNamespaceRule = {
|
|
4638
4683
|
meta: {
|
|
4639
4684
|
schema: [],
|
|
@@ -4672,7 +4717,7 @@ var themeVariableNamespaceRule = {
|
|
|
4672
4717
|
}
|
|
4673
4718
|
};
|
|
4674
4719
|
|
|
4675
|
-
// eslint/rules/
|
|
4720
|
+
// eslint/rules/tailwind/global-css-location.ts
|
|
4676
4721
|
var globalCssLocationRule = {
|
|
4677
4722
|
meta: {
|
|
4678
4723
|
schema: [],
|
|
@@ -4703,7 +4748,7 @@ var globalCssLocationRule = {
|
|
|
4703
4748
|
}
|
|
4704
4749
|
};
|
|
4705
4750
|
|
|
4706
|
-
// eslint/rules/
|
|
4751
|
+
// eslint/rules/tailwind/global-stylesheet.ts
|
|
4707
4752
|
var globalStylesheetRule = {
|
|
4708
4753
|
meta: {
|
|
4709
4754
|
schema: [],
|
|
@@ -4736,8 +4781,8 @@ var globalStylesheetRule = {
|
|
|
4736
4781
|
}
|
|
4737
4782
|
};
|
|
4738
4783
|
|
|
4739
|
-
// eslint/rules/
|
|
4740
|
-
var
|
|
4784
|
+
// eslint/rules/tailwind/index.ts
|
|
4785
|
+
var tailwindRules = {
|
|
4741
4786
|
"theme-reset": themeResetRule,
|
|
4742
4787
|
"root-variables": rootVariablesRule,
|
|
4743
4788
|
"apply-usage": applyUsageRule,
|
|
@@ -4751,10 +4796,50 @@ var cssRules = {
|
|
|
4751
4796
|
"global-stylesheet": globalStylesheetRule
|
|
4752
4797
|
};
|
|
4753
4798
|
|
|
4754
|
-
// eslint/rules/json/
|
|
4799
|
+
// eslint/rules/package-json/exact-version.ts
|
|
4755
4800
|
function memberName(member) {
|
|
4756
4801
|
return member.name.type === "String" ? member.name.value : member.name.name;
|
|
4757
4802
|
}
|
|
4803
|
+
var EXACT_VERSION_PATTERN = /^\d+\.\d+\.\d+$/;
|
|
4804
|
+
function memberValue(member) {
|
|
4805
|
+
return member.value.type === "String" ? member.value.value : null;
|
|
4806
|
+
}
|
|
4807
|
+
var exactVersionRule = {
|
|
4808
|
+
meta: {
|
|
4809
|
+
schema: [],
|
|
4810
|
+
type: "problem",
|
|
4811
|
+
docs: {
|
|
4812
|
+
description: "Require dependency and devDependency versions to be pinned exactly."
|
|
4813
|
+
}
|
|
4814
|
+
},
|
|
4815
|
+
create(context) {
|
|
4816
|
+
return {
|
|
4817
|
+
Document(node) {
|
|
4818
|
+
const root = node.body;
|
|
4819
|
+
if (root.type !== "Object") return;
|
|
4820
|
+
for (const key of ["dependencies", "devDependencies"]) {
|
|
4821
|
+
const section = root.members.find((member) => memberName(member) === key);
|
|
4822
|
+
if (section?.value.type !== "Object") continue;
|
|
4823
|
+
for (const member of section.value.members) {
|
|
4824
|
+
const version = memberValue(member);
|
|
4825
|
+
if (version === null) continue;
|
|
4826
|
+
if (!EXACT_VERSION_PATTERN.test(version)) {
|
|
4827
|
+
context.report({
|
|
4828
|
+
node: member,
|
|
4829
|
+
message: `${memberName(member)} must pin an exact version (e.g. "1.2.3"), not a range or cap such as "${version}".`
|
|
4830
|
+
});
|
|
4831
|
+
}
|
|
4832
|
+
}
|
|
4833
|
+
}
|
|
4834
|
+
}
|
|
4835
|
+
};
|
|
4836
|
+
}
|
|
4837
|
+
};
|
|
4838
|
+
|
|
4839
|
+
// eslint/rules/package-json/no-vulyk-dependency.ts
|
|
4840
|
+
function memberName2(member) {
|
|
4841
|
+
return member.name.type === "String" ? member.name.value : member.name.name;
|
|
4842
|
+
}
|
|
4758
4843
|
var noVulykDependencyRule = {
|
|
4759
4844
|
meta: {
|
|
4760
4845
|
schema: [],
|
|
@@ -4769,9 +4854,9 @@ var noVulykDependencyRule = {
|
|
|
4769
4854
|
const root = node.body;
|
|
4770
4855
|
if (root.type !== "Object") return;
|
|
4771
4856
|
for (const key of ["dependencies", "devDependencies"]) {
|
|
4772
|
-
const section = root.members.find((member) =>
|
|
4857
|
+
const section = root.members.find((member) => memberName2(member) === key);
|
|
4773
4858
|
if (section?.value.type !== "Object") continue;
|
|
4774
|
-
const vulyk = section.value.members.find((member) =>
|
|
4859
|
+
const vulyk = section.value.members.find((member) => memberName2(member) === "vulyk");
|
|
4775
4860
|
if (vulyk) {
|
|
4776
4861
|
context.report({
|
|
4777
4862
|
node: vulyk,
|
|
@@ -4784,16 +4869,39 @@ var noVulykDependencyRule = {
|
|
|
4784
4869
|
}
|
|
4785
4870
|
};
|
|
4786
4871
|
|
|
4787
|
-
// eslint/rules/json/
|
|
4788
|
-
|
|
4872
|
+
// eslint/rules/package-json/nextjs-stack.ts
|
|
4873
|
+
var NEXTJS_STACK_DEPENDENCIES = [
|
|
4874
|
+
"next",
|
|
4875
|
+
"react",
|
|
4876
|
+
"react-dom",
|
|
4877
|
+
"zod",
|
|
4878
|
+
"class-variance-authority",
|
|
4879
|
+
"clsx",
|
|
4880
|
+
"tailwind-merge"
|
|
4881
|
+
];
|
|
4882
|
+
var NEXTJS_STACK_DEV_DEPENDENCIES = [
|
|
4883
|
+
"typescript",
|
|
4884
|
+
"tailwindcss",
|
|
4885
|
+
"eslint",
|
|
4886
|
+
"prettier",
|
|
4887
|
+
"husky",
|
|
4888
|
+
"lint-staged",
|
|
4889
|
+
"zirka"
|
|
4890
|
+
];
|
|
4891
|
+
function memberName3(member) {
|
|
4789
4892
|
return member.name.type === "String" ? member.name.value : member.name.name;
|
|
4790
4893
|
}
|
|
4791
|
-
|
|
4894
|
+
function sectionPackages(root, section) {
|
|
4895
|
+
const member = root.type === "Object" ? root.members.find((entry) => memberName3(entry) === section) : void 0;
|
|
4896
|
+
if (member?.value.type !== "Object") return /* @__PURE__ */ new Set();
|
|
4897
|
+
return new Set(member.value.members.map(memberName3));
|
|
4898
|
+
}
|
|
4899
|
+
var nextjsStackRule = {
|
|
4792
4900
|
meta: {
|
|
4793
4901
|
schema: [],
|
|
4794
4902
|
type: "problem",
|
|
4795
4903
|
docs: {
|
|
4796
|
-
description: "Require
|
|
4904
|
+
description: "Require the framework's runtime packages in dependencies and toolchain packages in devDependencies."
|
|
4797
4905
|
}
|
|
4798
4906
|
},
|
|
4799
4907
|
create(context) {
|
|
@@ -4801,18 +4909,20 @@ var zirkaInstalledRule = {
|
|
|
4801
4909
|
Document(node) {
|
|
4802
4910
|
const root = node.body;
|
|
4803
4911
|
if (root.type !== "Object") return;
|
|
4804
|
-
const
|
|
4805
|
-
|
|
4806
|
-
|
|
4807
|
-
if (
|
|
4808
|
-
|
|
4809
|
-
|
|
4810
|
-
|
|
4912
|
+
const dependencies = sectionPackages(root, "dependencies");
|
|
4913
|
+
const devDependencies = sectionPackages(root, "devDependencies");
|
|
4914
|
+
for (const pkg of NEXTJS_STACK_DEPENDENCIES) {
|
|
4915
|
+
if (dependencies.has(pkg)) continue;
|
|
4916
|
+
context.report({
|
|
4917
|
+
node,
|
|
4918
|
+
message: `${pkg} must be listed in package.json as a dependency.`
|
|
4919
|
+
});
|
|
4811
4920
|
}
|
|
4812
|
-
|
|
4921
|
+
for (const pkg of NEXTJS_STACK_DEV_DEPENDENCIES) {
|
|
4922
|
+
if (devDependencies.has(pkg)) continue;
|
|
4813
4923
|
context.report({
|
|
4814
4924
|
node,
|
|
4815
|
-
message:
|
|
4925
|
+
message: `${pkg} must be listed in package.json as a devDependency.`
|
|
4816
4926
|
});
|
|
4817
4927
|
}
|
|
4818
4928
|
}
|
|
@@ -4820,76 +4930,201 @@ var zirkaInstalledRule = {
|
|
|
4820
4930
|
}
|
|
4821
4931
|
};
|
|
4822
4932
|
|
|
4823
|
-
// eslint/rules/json/index.ts
|
|
4824
|
-
var
|
|
4933
|
+
// eslint/rules/package-json/index.ts
|
|
4934
|
+
var repoPackageJsonRules = {
|
|
4825
4935
|
"no-vulyk-dependency": noVulykDependencyRule,
|
|
4826
|
-
"
|
|
4936
|
+
"exact-version": exactVersionRule
|
|
4937
|
+
};
|
|
4938
|
+
var nextPackageJsonRules = {
|
|
4939
|
+
"nextjs-stack": nextjsStackRule
|
|
4940
|
+
};
|
|
4941
|
+
|
|
4942
|
+
// eslint/rules/husky/husky-hook.ts
|
|
4943
|
+
import { existsSync, readFileSync as readFileSync6 } from "fs";
|
|
4944
|
+
import path39 from "path";
|
|
4945
|
+
function memberName4(member) {
|
|
4946
|
+
return member.name.type === "String" ? member.name.value : member.name.name;
|
|
4947
|
+
}
|
|
4948
|
+
var huskyHookRule = {
|
|
4949
|
+
meta: {
|
|
4950
|
+
schema: [],
|
|
4951
|
+
type: "problem",
|
|
4952
|
+
docs: {
|
|
4953
|
+
description: "Require a pre-commit hook that runs lint-staged, typecheck, and the libyear drift check."
|
|
4954
|
+
}
|
|
4955
|
+
},
|
|
4956
|
+
create(context) {
|
|
4957
|
+
return {
|
|
4958
|
+
Document(node) {
|
|
4959
|
+
const root = node.body;
|
|
4960
|
+
if (root.type !== "Object") return;
|
|
4961
|
+
const scriptName = context.filename;
|
|
4962
|
+
if (!scriptName.endsWith("package.json")) return;
|
|
4963
|
+
const hookPath = path39.join(process.cwd(), ".husky", "pre-commit");
|
|
4964
|
+
if (!existsSync(hookPath)) {
|
|
4965
|
+
context.report({
|
|
4966
|
+
node,
|
|
4967
|
+
message: "No .husky/pre-commit hook found. Configure husky to run checks before commits."
|
|
4968
|
+
});
|
|
4969
|
+
return;
|
|
4970
|
+
}
|
|
4971
|
+
const content = readFileSync6(hookPath, "utf8");
|
|
4972
|
+
if (!content.includes("lint-staged")) {
|
|
4973
|
+
context.report({ node, message: ".husky/pre-commit must run lint-staged." });
|
|
4974
|
+
}
|
|
4975
|
+
if (!content.includes("typecheck")) {
|
|
4976
|
+
context.report({ node, message: ".husky/pre-commit must run npm run typecheck." });
|
|
4977
|
+
}
|
|
4978
|
+
if (!content.includes("libyear --limit-major-individual=1")) {
|
|
4979
|
+
context.report({ node, message: ".husky/pre-commit must run npx libyear --limit-major-individual=1." });
|
|
4980
|
+
}
|
|
4981
|
+
const scripts = root.members.find((member) => memberName4(member) === "scripts");
|
|
4982
|
+
if (scripts?.value.type === "Object") {
|
|
4983
|
+
const prepare = scripts.value.members.find((member) => memberName4(member) === "prepare");
|
|
4984
|
+
if (prepare?.value.type === "String" && !prepare.value.value.includes("husky")) {
|
|
4985
|
+
context.report({
|
|
4986
|
+
node: prepare,
|
|
4987
|
+
message: 'package.json "prepare" script must run husky (e.g. "prepare": "husky").'
|
|
4988
|
+
});
|
|
4989
|
+
}
|
|
4990
|
+
}
|
|
4991
|
+
}
|
|
4992
|
+
};
|
|
4993
|
+
}
|
|
4994
|
+
};
|
|
4995
|
+
|
|
4996
|
+
// eslint/rules/husky/index.ts
|
|
4997
|
+
var huskyRules = {
|
|
4998
|
+
"husky-hook": huskyHookRule
|
|
4827
4999
|
};
|
|
4828
5000
|
|
|
4829
5001
|
// eslint/index.ts
|
|
4830
|
-
var
|
|
4831
|
-
"
|
|
4832
|
-
"
|
|
4833
|
-
"application-structure": applicationStructureRule,
|
|
5002
|
+
var repoSourceRules = {
|
|
5003
|
+
"filename-case": filenameCaseRule,
|
|
5004
|
+
"import-boundaries": importBoundariesRule,
|
|
4834
5005
|
"named-exports": namedExportsRule,
|
|
4835
|
-
"
|
|
5006
|
+
"support-file-placement": supportFilePlacementRule,
|
|
4836
5007
|
"support-folder-shape": supportFolderShapeRule,
|
|
4837
5008
|
"import-through-index": importThroughIndexRule,
|
|
4838
5009
|
"util-file-name": utilFileNameRule,
|
|
4839
5010
|
"no-util-barrel": noUtilBarrelRule,
|
|
5011
|
+
"enforce-barrel-exports": enforceBarrelExportsRule,
|
|
5012
|
+
"config-extraction": configExtractionRule,
|
|
5013
|
+
"value-extraction": valueExtractionRule,
|
|
5014
|
+
"type-extraction": typeExtractionRule,
|
|
5015
|
+
"zod-schema-validation": zodSchemaValidationRule,
|
|
5016
|
+
"source-under-src": sourceUnderSrcRule,
|
|
5017
|
+
"config-baseline": configBaselineRule
|
|
5018
|
+
};
|
|
5019
|
+
var nextSourceRules = {
|
|
5020
|
+
"component-placement": componentPlacementRule,
|
|
5021
|
+
"application-structure": applicationStructureRule,
|
|
5022
|
+
"data-testid-case": dataTestIdCaseRule,
|
|
4840
5023
|
"jsx-hygiene": jsxHygieneRule,
|
|
4841
5024
|
"interactive-component": interactiveComponentRule,
|
|
4842
5025
|
"ui-state": uiStateRule,
|
|
4843
|
-
"filename-case": filenameCaseRule,
|
|
4844
|
-
"import-boundaries": importBoundariesRule,
|
|
4845
5026
|
"no-mixed-concerns": noMixedConcernsRule,
|
|
4846
5027
|
"no-arbitrary-tailwind": noArbitraryTailwindRule,
|
|
4847
5028
|
"enforce-cn-merge": enforceCnMergeRule,
|
|
5029
|
+
"cn-helper": cnHelperRule,
|
|
4848
5030
|
"enforce-cva-variant-props": enforceCvaVariantPropsRule,
|
|
4849
5031
|
"cva-appearance-props": cvaAppearancePropsRule,
|
|
4850
5032
|
"cva-boolean-variants": cvaBooleanVariantsRule,
|
|
4851
|
-
"enforce-barrel-exports": enforceBarrelExportsRule,
|
|
4852
5033
|
"cross-feature-import": crossFeatureImportRule,
|
|
4853
5034
|
"pure-function-extract": pureFunctionExtractRule,
|
|
4854
5035
|
"hook-complexity": hookComplexityRule,
|
|
4855
5036
|
"locale-dotted-path": localeDottedPathRule,
|
|
4856
5037
|
"locales-location": localesLocationRule,
|
|
4857
5038
|
"hook-extraction": hookExtractionRule,
|
|
4858
|
-
"value-extraction": valueExtractionRule,
|
|
4859
|
-
"config-extraction": configExtractionRule,
|
|
4860
5039
|
"component-nesting": componentNestingRule,
|
|
4861
5040
|
"stay-flat": stayFlatRule,
|
|
4862
|
-
"type-extraction": typeExtractionRule,
|
|
4863
5041
|
"locale-placement": localePlacementRule,
|
|
4864
5042
|
"sole-state-owner": soleStateOwnerRule,
|
|
4865
5043
|
"locale-key-shape": localeKeyShapeRule,
|
|
4866
5044
|
"shared-style-dedup": sharedStyleDedupRule,
|
|
4867
|
-
"repeated-structure": repeatedStructureRule
|
|
4868
|
-
|
|
4869
|
-
|
|
4870
|
-
|
|
5045
|
+
"repeated-structure": repeatedStructureRule
|
|
5046
|
+
};
|
|
5047
|
+
var pasikaRules = {
|
|
5048
|
+
...repoSourceRules,
|
|
5049
|
+
...nextSourceRules
|
|
4871
5050
|
};
|
|
4872
|
-
|
|
4873
|
-
|
|
4874
|
-
|
|
4875
|
-
var
|
|
4876
|
-
var
|
|
4877
|
-
var
|
|
5051
|
+
function ruleIds(rules2) {
|
|
5052
|
+
return Object.keys(rules2).map((name) => `pasika/${name}`);
|
|
5053
|
+
}
|
|
5054
|
+
var pasikaRuleIds = ruleIds(pasikaRules);
|
|
5055
|
+
var documentationRuleIds = ruleIds(documentationRules);
|
|
5056
|
+
var tailwindRuleIds = ruleIds(tailwindRules);
|
|
5057
|
+
var repoPackageJsonRuleIds = ruleIds(repoPackageJsonRules);
|
|
5058
|
+
var nextPackageJsonRuleIds = ruleIds(nextPackageJsonRules);
|
|
5059
|
+
var huskyRuleIds = ruleIds(huskyRules);
|
|
5060
|
+
var allPasikaRuleIds = [
|
|
5061
|
+
...pasikaRuleIds,
|
|
5062
|
+
...documentationRuleIds,
|
|
5063
|
+
...tailwindRuleIds,
|
|
5064
|
+
...repoPackageJsonRuleIds,
|
|
5065
|
+
...nextPackageJsonRuleIds,
|
|
5066
|
+
...huskyRuleIds
|
|
5067
|
+
];
|
|
5068
|
+
var nextAppBlock = {
|
|
4878
5069
|
files: ["src/**/*.{cjs,cts,js,jsx,mjs,mts,ts,tsx}"],
|
|
4879
5070
|
plugins: {
|
|
4880
5071
|
pasika: { rules: pasikaRules }
|
|
4881
5072
|
},
|
|
4882
5073
|
rules: Object.fromEntries(pasikaRuleIds.map((id) => [id, "error"]))
|
|
4883
5074
|
};
|
|
5075
|
+
var tailwindGlobalsBlock = {
|
|
5076
|
+
files: ["src/**/globals.css"],
|
|
5077
|
+
plugins: {
|
|
5078
|
+
css,
|
|
5079
|
+
pasika: { rules: tailwindRules }
|
|
5080
|
+
},
|
|
5081
|
+
language: "css/css",
|
|
5082
|
+
languageOptions: { tolerant: true },
|
|
5083
|
+
rules: Object.fromEntries(
|
|
5084
|
+
tailwindRuleIds.filter((id) => id !== "pasika/global-css-location").map((id) => [id, "error"])
|
|
5085
|
+
)
|
|
5086
|
+
};
|
|
5087
|
+
var tailwindAnyCssBlock = {
|
|
5088
|
+
files: ["src/**/*.css"],
|
|
5089
|
+
plugins: {
|
|
5090
|
+
css,
|
|
5091
|
+
pasika: { rules: tailwindRules }
|
|
5092
|
+
},
|
|
5093
|
+
language: "css/css",
|
|
5094
|
+
languageOptions: { tolerant: true },
|
|
5095
|
+
rules: { "pasika/global-css-location": "error" }
|
|
5096
|
+
};
|
|
5097
|
+
var manifestBlock = {
|
|
5098
|
+
files: ["package.json"],
|
|
5099
|
+
plugins: {
|
|
5100
|
+
json: { languages: { json: jsonPlugin.languages.json } },
|
|
5101
|
+
pasika: { rules: { ...repoPackageJsonRules, ...nextPackageJsonRules, ...huskyRules } }
|
|
5102
|
+
},
|
|
5103
|
+
language: "json/json",
|
|
5104
|
+
rules: Object.fromEntries(
|
|
5105
|
+
[...repoPackageJsonRuleIds, ...nextPackageJsonRuleIds, ...huskyRuleIds].map((id) => [id, "error"])
|
|
5106
|
+
)
|
|
5107
|
+
};
|
|
5108
|
+
var docsBlock = {
|
|
5109
|
+
files: ["docs/**/*.md"],
|
|
5110
|
+
ignores: ["**/_*/**"],
|
|
5111
|
+
plugins: {
|
|
5112
|
+
markdown,
|
|
5113
|
+
pasika: { rules: documentationRules }
|
|
5114
|
+
},
|
|
5115
|
+
language: "markdown/gfm",
|
|
5116
|
+
rules: Object.fromEntries(documentationRuleIds.map((id) => [id, "error"]))
|
|
5117
|
+
};
|
|
5118
|
+
var pasikaRepo = [manifestBlock, docsBlock];
|
|
5119
|
+
var pasikaNext = [...pasikaRepo, nextAppBlock, tailwindGlobalsBlock, tailwindAnyCssBlock];
|
|
4884
5120
|
export {
|
|
4885
5121
|
allPasikaRuleIds,
|
|
4886
|
-
|
|
4887
|
-
|
|
4888
|
-
|
|
4889
|
-
|
|
4890
|
-
|
|
4891
|
-
|
|
4892
|
-
|
|
4893
|
-
|
|
4894
|
-
pasikaRules
|
|
5122
|
+
documentationRules,
|
|
5123
|
+
huskyRules,
|
|
5124
|
+
nextPackageJsonRules,
|
|
5125
|
+
pasikaNext,
|
|
5126
|
+
pasikaRepo,
|
|
5127
|
+
pasikaRules,
|
|
5128
|
+
repoPackageJsonRules,
|
|
5129
|
+
tailwindRules
|
|
4895
5130
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pasika",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.9",
|
|
4
4
|
"description": "Reusable agent setup package",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -31,28 +31,33 @@
|
|
|
31
31
|
"!(*.ts|*.mts|*.cts|*.tsx|*.js|*.cjs|*.mjs|*.jsx)": "prettier --write --ignore-unknown",
|
|
32
32
|
"*.ts|*.mts|*.cts|*.tsx|*.js|*.cjs|*.mjs|*.jsx": "npx eslint --fix"
|
|
33
33
|
},
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"typescript": "6.0.3"
|
|
36
|
+
},
|
|
34
37
|
"devDependencies": {
|
|
35
|
-
"@eslint/css": "
|
|
36
|
-
"@eslint/css-tree": "
|
|
37
|
-
"@eslint/json": "
|
|
38
|
-
"@eslint/markdown": "
|
|
39
|
-
"@humanwhocodes/momoa": "
|
|
40
|
-
"@types/estree": "
|
|
41
|
-
"@types/mdast": "
|
|
42
|
-
"@types/node": "
|
|
43
|
-
"@typescript-eslint/parser": "
|
|
44
|
-
"eslint": "
|
|
45
|
-
"husky": "
|
|
46
|
-
"lint-staged": "
|
|
47
|
-
"prettier": "
|
|
48
|
-
"tsup": "
|
|
49
|
-
"tsx": "
|
|
50
|
-
"typescript": "
|
|
51
|
-
"zirka": "
|
|
52
|
-
"zod": "
|
|
38
|
+
"@eslint/css": "1.4.0",
|
|
39
|
+
"@eslint/css-tree": "4.0.5",
|
|
40
|
+
"@eslint/json": "2.0.1",
|
|
41
|
+
"@eslint/markdown": "8.0.3",
|
|
42
|
+
"@humanwhocodes/momoa": "3.3.12",
|
|
43
|
+
"@types/estree": "1.0.9",
|
|
44
|
+
"@types/mdast": "4.0.4",
|
|
45
|
+
"@types/node": "26.4.0",
|
|
46
|
+
"@typescript-eslint/parser": "8.68.0",
|
|
47
|
+
"eslint": "10.9.1",
|
|
48
|
+
"husky": "9.1.7",
|
|
49
|
+
"lint-staged": "17.4.1",
|
|
50
|
+
"prettier": "3.8.1",
|
|
51
|
+
"tsup": "8.5.1",
|
|
52
|
+
"tsx": "4.23.12",
|
|
53
|
+
"typescript": "6.0.3",
|
|
54
|
+
"zirka": "0.0.45",
|
|
55
|
+
"zod": "4.4.3"
|
|
53
56
|
},
|
|
54
57
|
"peerDependencies": {
|
|
55
|
-
"
|
|
58
|
+
"@eslint/css": ">=1.4.0",
|
|
59
|
+
"@eslint/json": ">=2.0.1",
|
|
60
|
+
"@eslint/markdown": ">=8.0.3"
|
|
56
61
|
},
|
|
57
62
|
"engines": {
|
|
58
63
|
"node": ">=22"
|