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
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
|
|
@@ -44,60 +48,71 @@ Requirements are identified by a hash of their canonical text, not by a hand-wri
|
|
|
44
48
|
|
|
45
49
|
The `text` field is the bullet as written in the document (markdown links and code spans intact), so it is greppable in the doc it came from; the `hash` is computed from the same text with links collapsed to their text and code spans unwrapped, so editing a URL or adding backticks does not read as a change.
|
|
46
50
|
|
|
47
|
-
Every requirement carries a `note` explaining how it is met: what the ref'd rule
|
|
51
|
+
Every requirement carries a `note` explaining how it is met: what the ref'd rule 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 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:
|
|
68
|
+
|
|
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
|
+
```
|
|
61
74
|
|
|
62
|
-
A requirement
|
|
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 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
|
|
|
73
86
|
### With Zirka (recommended)
|
|
74
87
|
|
|
75
88
|
```ts
|
|
76
|
-
// eslint.config.ts
|
|
89
|
+
// eslint.config.ts — Next.js application
|
|
77
90
|
import { RuleSeverity, styleguide } from "zirka";
|
|
78
91
|
|
|
79
92
|
const { eslintConfig } = styleguide({
|
|
80
93
|
next: RuleSeverity.Error,
|
|
81
94
|
node: RuleSeverity.Error,
|
|
82
95
|
typescript: RuleSeverity.Error,
|
|
83
|
-
|
|
96
|
+
pasikaNextjsApp: RuleSeverity.Error,
|
|
84
97
|
});
|
|
85
98
|
|
|
86
99
|
export default eslintConfig;
|
|
87
100
|
```
|
|
88
101
|
|
|
89
|
-
`zirka` composes the
|
|
102
|
+
For a plain TypeScript repository, enable `pasikaTypescriptApp` instead of `pasikaNextjsApp`. `zirka` composes the pasika ruleset over four file scopes: TS/TSX under `src/**`, `globals.css` and other stylesheets, `package.json`, and markdown — each with its own ESLint language.
|
|
90
103
|
|
|
91
104
|
### Without Zirka
|
|
92
105
|
|
|
93
106
|
```ts
|
|
94
|
-
// eslint.config.ts
|
|
95
|
-
import {
|
|
107
|
+
// eslint.config.ts — plain TypeScript repository
|
|
108
|
+
import { typescriptApp } from "pasika/eslint";
|
|
96
109
|
|
|
97
|
-
export default
|
|
110
|
+
export default typescriptApp;
|
|
98
111
|
```
|
|
99
112
|
|
|
100
|
-
`
|
|
113
|
+
`typescriptApp` is the plain-TypeScript-repository preset — the package.json manifest, the zirka configuration contract, the `src/**` TypeScript app source, and the docs. `nextjsApp` is the full framework preset: everything in `typescriptApp` plus the Next.js-stack manifest requirement, the Next.js app source rules, and the Tailwind stylesheet blocks. The granular rule objects (`tailwindRules`, `repoPackageJsonRules`, `documentationRules`) stay exported for manual wiring.
|
|
114
|
+
|
|
115
|
+
Because the preset blocks wire ESLint's language plugins, using them 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
116
|
|
|
102
117
|
### TS/TSX rules
|
|
103
118
|
|
|
@@ -140,11 +155,11 @@ export default [pasikaConfig];
|
|
|
140
155
|
| `pasika/shared-style-dedup` † | A className combo used by two or more components becomes a named utility |
|
|
141
156
|
| `pasika/repeated-structure` | A block of elements repeated two or more times is extracted as a named component |
|
|
142
157
|
| `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/
|
|
158
|
+
| `pasika/zirka-baseline` | eslint, prettier, and TypeScript configuration come from zirka instead of being restated locally |
|
|
144
159
|
| `pasika/zod-schema-validation` | Runtime validation through Zod schemas, not hand-written type guards |
|
|
145
160
|
| `pasika/source-under-src` | Application source lives under `src/`, not in root-level folders |
|
|
146
161
|
|
|
147
|
-
###
|
|
162
|
+
### Tailwind rules
|
|
148
163
|
|
|
149
164
|
Applied to `src/**/globals.css` (and other stylesheets) through `@eslint/css` with tolerant Tailwind v4 parsing.
|
|
150
165
|
|
|
@@ -161,20 +176,22 @@ Applied to `src/**/globals.css` (and other stylesheets) through `@eslint/css` wi
|
|
|
161
176
|
| `pasika/theme-variable-namespace` | Utility class groups share a namespace prefix |
|
|
162
177
|
| `pasika/global-css-location` | Global CSS lives in the correct entry point |
|
|
163
178
|
|
|
164
|
-
###
|
|
179
|
+
### Package.json rules
|
|
165
180
|
|
|
166
|
-
Applied to `package.json` through `@eslint/json`.
|
|
181
|
+
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, and `vulyk-docs` to a repository adopting the framework.
|
|
167
182
|
|
|
168
|
-
| Rule | Enforces
|
|
169
|
-
| ---------------------------- |
|
|
170
|
-
| `pasika/no-
|
|
171
|
-
| `pasika/
|
|
183
|
+
| Rule | Enforces |
|
|
184
|
+
| ---------------------------- | ----------------------------------------------------------------------------------- |
|
|
185
|
+
| `pasika/no-vulyk-dependency` | `vulyk` is not in `dependencies` |
|
|
186
|
+
| `pasika/exact-version` | Dependency and devDependency versions are pinned exactly, never ranges |
|
|
187
|
+
| `pasika/nextjs-stack` | All Tech Stack Reference packages are listed in `package.json` (Next.js/React apps) |
|
|
188
|
+
| `pasika/vulyk-docs` | `vulyk.config.ts` tracks the framework's docs from pasika and `AGENTS.md` exists |
|
|
172
189
|
|
|
173
190
|
### Documentation rules
|
|
174
191
|
|
|
175
|
-
The `pasika/*` markdown rules enforce the documentation guide over `docs/**/*.md` (
|
|
192
|
+
The `pasika/*` markdown rules enforce the documentation guide over `docs/**/*.md` (22 rules): file-name suffixes and titles, overview shape (presence, sentence count, links), 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
193
|
|
|
177
|
-
Run `
|
|
194
|
+
Run `npx tsx scripts/coverage.ts --json` for the exact requirement each rule covers.
|
|
178
195
|
|
|
179
196
|
### † Cross-file rules
|
|
180
197
|
|
|
@@ -185,6 +202,10 @@ Where a component, hook, value, type, or style belongs depends on which files us
|
|
|
185
202
|
|
|
186
203
|
All are inert in a repository with no `src/` tree.
|
|
187
204
|
|
|
205
|
+
## Runtime dependency on typescript
|
|
206
|
+
|
|
207
|
+
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`.
|
|
208
|
+
|
|
188
209
|
## Development
|
|
189
210
|
|
|
190
211
|
```bash
|
|
@@ -74,12 +74,10 @@ 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
|
-
|
|
81
|
-
"overview-length": _eslint_markdown.MarkdownRuleDefinition;
|
|
82
|
-
"guide-overview-no-links": _eslint_markdown.MarkdownRuleDefinition;
|
|
80
|
+
overview: _eslint_markdown.MarkdownRuleDefinition;
|
|
83
81
|
"guide-step-single-sentence": _eslint_markdown.MarkdownRuleDefinition;
|
|
84
82
|
"guide-step-single-link": _eslint_markdown.MarkdownRuleDefinition;
|
|
85
83
|
"guide-states-no-requirement": _eslint_markdown.MarkdownRuleDefinition;
|
|
@@ -99,9 +97,10 @@ declare const mdRules: {
|
|
|
99
97
|
"guide-link-anchors": _eslint_markdown.MarkdownRuleDefinition;
|
|
100
98
|
"no-nested-how-to": _eslint_markdown.MarkdownRuleDefinition;
|
|
101
99
|
"glossary-term-linking": _eslint_markdown.MarkdownRuleDefinition;
|
|
100
|
+
"guide-mentions-documents": _eslint_markdown.MarkdownRuleDefinition;
|
|
102
101
|
};
|
|
103
102
|
|
|
104
|
-
declare const
|
|
103
|
+
declare const tailwindRules: {
|
|
105
104
|
"theme-reset": _eslint_css.CSSRuleDefinition;
|
|
106
105
|
"root-variables": _eslint_css.CSSRuleDefinition;
|
|
107
106
|
"apply-usage": _eslint_css.CSSRuleDefinition;
|
|
@@ -115,26 +114,32 @@ declare const cssRules: {
|
|
|
115
114
|
"global-stylesheet": _eslint_css.CSSRuleDefinition;
|
|
116
115
|
};
|
|
117
116
|
|
|
118
|
-
|
|
117
|
+
/** Framework-agnostic package.json rules any repository should follow. */
|
|
118
|
+
declare const repoPackageJsonRules: {
|
|
119
119
|
"no-vulyk-dependency": _eslint_json.JSONRuleDefinition;
|
|
120
|
-
"
|
|
120
|
+
"exact-version": _eslint_json.JSONRuleDefinition;
|
|
121
|
+
};
|
|
122
|
+
/** Package.json rules specific to a Next.js (or React) application. */
|
|
123
|
+
declare const nextPackageJsonRules: {
|
|
124
|
+
"nextjs-stack": _eslint_json.JSONRuleDefinition;
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
declare const huskyRules: {
|
|
128
|
+
"husky-hook": _eslint_json.JSONRuleDefinition;
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
declare const vulykRules: {
|
|
132
|
+
"vulyk-docs": _eslint_json.JSONRuleDefinition;
|
|
121
133
|
};
|
|
122
134
|
|
|
135
|
+
/** Every source rule, merged so the Next.js preset applies them all. */
|
|
123
136
|
declare const pasikaRules: {
|
|
124
137
|
"component-placement": eslint.Rule.RuleModule;
|
|
125
|
-
"support-file-placement": eslint.Rule.RuleModule;
|
|
126
138
|
"application-structure": eslint.Rule.RuleModule;
|
|
127
|
-
"named-exports": eslint.Rule.RuleModule;
|
|
128
139
|
"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
140
|
"jsx-hygiene": eslint.Rule.RuleModule;
|
|
134
141
|
"interactive-component": eslint.Rule.RuleModule;
|
|
135
142
|
"ui-state": eslint.Rule.RuleModule;
|
|
136
|
-
"filename-case": eslint.Rule.RuleModule;
|
|
137
|
-
"import-boundaries": eslint.Rule.RuleModule;
|
|
138
143
|
"no-mixed-concerns": eslint.Rule.RuleModule;
|
|
139
144
|
"no-arbitrary-tailwind": eslint.Rule.RuleModule;
|
|
140
145
|
"enforce-cn-merge": {
|
|
@@ -149,38 +154,55 @@ declare const pasikaRules: {
|
|
|
149
154
|
JSXAttribute(node: JsxAttributeNode): void;
|
|
150
155
|
};
|
|
151
156
|
};
|
|
157
|
+
"cn-helper": eslint.Rule.RuleModule;
|
|
152
158
|
"enforce-cva-variant-props": eslint.Rule.RuleModule;
|
|
153
159
|
"cva-appearance-props": eslint.Rule.RuleModule;
|
|
154
160
|
"cva-boolean-variants": eslint.Rule.RuleModule;
|
|
155
|
-
"enforce-barrel-exports": eslint.Rule.RuleModule;
|
|
156
161
|
"cross-feature-import": eslint.Rule.RuleModule;
|
|
157
162
|
"pure-function-extract": eslint.Rule.RuleModule;
|
|
158
163
|
"hook-complexity": eslint.Rule.RuleModule;
|
|
159
164
|
"locale-dotted-path": eslint.Rule.RuleModule;
|
|
160
165
|
"locales-location": eslint.Rule.RuleModule;
|
|
161
166
|
"hook-extraction": eslint.Rule.RuleModule;
|
|
162
|
-
"value-extraction": eslint.Rule.RuleModule;
|
|
163
|
-
"config-extraction": eslint.Rule.RuleModule;
|
|
164
167
|
"component-nesting": eslint.Rule.RuleModule;
|
|
165
168
|
"stay-flat": eslint.Rule.RuleModule;
|
|
166
|
-
"type-extraction": eslint.Rule.RuleModule;
|
|
167
169
|
"locale-placement": eslint.Rule.RuleModule;
|
|
168
170
|
"sole-state-owner": eslint.Rule.RuleModule;
|
|
169
171
|
"locale-key-shape": eslint.Rule.RuleModule;
|
|
170
172
|
"shared-style-dedup": eslint.Rule.RuleModule;
|
|
171
173
|
"repeated-structure": eslint.Rule.RuleModule;
|
|
174
|
+
"filename-case": eslint.Rule.RuleModule;
|
|
175
|
+
"import-boundaries": eslint.Rule.RuleModule;
|
|
176
|
+
"named-exports": eslint.Rule.RuleModule;
|
|
177
|
+
"support-file-placement": eslint.Rule.RuleModule;
|
|
178
|
+
"support-folder-shape": eslint.Rule.RuleModule;
|
|
179
|
+
"import-through-index": eslint.Rule.RuleModule;
|
|
180
|
+
"util-file-name": eslint.Rule.RuleModule;
|
|
181
|
+
"no-util-barrel": eslint.Rule.RuleModule;
|
|
182
|
+
"enforce-barrel-exports": eslint.Rule.RuleModule;
|
|
183
|
+
"config-extraction": eslint.Rule.RuleModule;
|
|
184
|
+
"value-extraction": eslint.Rule.RuleModule;
|
|
185
|
+
"type-extraction": eslint.Rule.RuleModule;
|
|
172
186
|
"zod-schema-validation": eslint.Rule.RuleModule;
|
|
173
187
|
"source-under-src": eslint.Rule.RuleModule;
|
|
174
|
-
"
|
|
188
|
+
"zirka-baseline": eslint.Rule.RuleModule;
|
|
175
189
|
};
|
|
176
190
|
|
|
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
191
|
/** Every rule id, as they appear in configuration and in lint output. */
|
|
183
192
|
declare const allPasikaRuleIds: string[];
|
|
184
|
-
|
|
193
|
+
/**
|
|
194
|
+
* TypeScript app preset: the framework-agnostic baseline — the package.json
|
|
195
|
+
* manifest (incl. husky hook and vulyk requirements), the zirka configuration
|
|
196
|
+
* contract, the `src/**` TS/TSX source, and the documentation markdown rules.
|
|
197
|
+
* Use this for a plain TypeScript repository.
|
|
198
|
+
*/
|
|
199
|
+
declare const typescriptApp: Linter.Config[];
|
|
200
|
+
/**
|
|
201
|
+
* Next.js app preset: the full adopted-to-the-framework stack. Anything in
|
|
202
|
+
* `typescriptApp` plus the framework-only blocks — the Next.js-stack manifest
|
|
203
|
+
* requirement, the Next.js app source rules, and the Tailwind stylesheet
|
|
204
|
+
* rules. `typescriptApp` is a strict subset of `nextjsApp`.
|
|
205
|
+
*/
|
|
206
|
+
declare const nextjsApp: Linter.Config[];
|
|
185
207
|
|
|
186
|
-
export { allPasikaRuleIds,
|
|
208
|
+
export { allPasikaRuleIds, documentationRules, huskyRules, nextPackageJsonRules, nextjsApp, pasikaRules, repoPackageJsonRules, tailwindRules, typescriptApp, vulykRules };
|