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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # pasika
2
2
 
3
- Documentation, the lint rules derived from it, and the CLI that applies and diagnoses both.
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
- enforcement/
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
- pasika/rules/ # the lint rules, with fixture tests beside them
22
- pasika/rules/md/ # the documentation-guide rules, linting docs/ itself
23
- cli/
24
- index.ts # the `pasika` command
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 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.
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
- `pasika 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 `pasika coverage --accept`.
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
- npx pasika coverage # check that every requirement has recorded enforcement
57
- npx pasika coverage --accept # record reworded and removed requirements
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 `coverage` reports as `new` is classified with the hash it prints:
75
+ A requirement the report shows as `new` is classified with the hash it prints:
63
76
 
64
77
  ```bash
65
- npx pasika coverage --classify d311a1457a --ref pasika/import-boundaries --note "reports imports that cross a feature boundary"
66
- npx pasika coverage --classify 041b665bd7 --note "no check can compare against the previous state"
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 command refuses a hash no requirement has, a `ref` naming a rule or doctor check that does not exist, and an entry without a note — so a mismatch cannot reach the registry by hand. Re-running it on an already-recorded requirement replaces the earlier entry.
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
- pasika: RuleSeverity.Error,
96
+ pasikaNextjsApp: RuleSeverity.Error,
84
97
  });
85
98
 
86
99
  export default eslintConfig;
87
100
  ```
88
101
 
89
- `zirka` composes the full 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.
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 { pasikaConfig } from "pasika/eslint";
107
+ // eslint.config.ts — plain TypeScript repository
108
+ import { typescriptApp } from "pasika/eslint";
96
109
 
97
- export default [pasikaConfig];
110
+ export default typescriptApp;
98
111
  ```
99
112
 
100
- `pasikaConfig` applies the TS/TSX rules to `src/**` only, so a repository without a `src/` tree passes it trivially. The CSS, JSON, and markdown language configs are composed by `zirka`'s `styleguide()`; the individual rule objects (`cssRules`, `jsonRules`, `mdRules`) are exported for manual wiring.
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/no-eslint-disable` | No `eslint-disable` directives |
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
- ### CSS rules
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
- ### JSON rules
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-cache-flag` | Lint scripts don't pass `--cache` |
171
- | `pasika/no-vulyk-dependency` | `vulyk` is not in `dependencies` |
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` (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`; `pasika coverage` verifies each has a test and a registry entry. Pasika's own `docs/` are linted by them in CI (`npm run lint`).
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 `pasika coverage --json` for the exact requirement each rule covers.
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 mdRules: {
77
+ declare const documentationRules: {
78
78
  "doc-kind-suffix": _eslint_markdown.MarkdownRuleDefinition;
79
79
  "title-matches-file-name": _eslint_markdown.MarkdownRuleDefinition;
80
- "overview-present": _eslint_markdown.MarkdownRuleDefinition;
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 cssRules: {
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
- declare const jsonRules: {
117
+ /** Framework-agnostic package.json rules any repository should follow. */
118
+ declare const repoPackageJsonRules: {
119
119
  "no-vulyk-dependency": _eslint_json.JSONRuleDefinition;
120
- "zirka-installed": _eslint_json.JSONRuleDefinition;
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
- "config-baseline": eslint.Rule.RuleModule;
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
- declare const pasikaConfig: Linter.Config;
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, cssRules, jsonRules, mdRules, pasikaConfig, pasikaCssRuleIds, pasikaJsonRuleIds, pasikaMdRuleIds, pasikaRuleIds, pasikaRules };
208
+ export { allPasikaRuleIds, documentationRules, huskyRules, nextPackageJsonRules, nextjsApp, pasikaRules, repoPackageJsonRules, tailwindRules, typescriptApp, vulykRules };