@drskillissue/ganko 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 DrSkillIssue
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,430 @@
1
+ # Ganko
2
+
3
+ `Ganko` is a graph-first linting SDK for Solid.js and CSS.
4
+
5
+ It provides:
6
+
7
+ - Typed program graphs for Solid and CSS
8
+ - A plugin-agnostic runner (`SolidPlugin`, `CSSPlugin`, `CrossFilePlugin`)
9
+ - Cross-file analysis (Solid <-> CSS) with layout inference
10
+ - ESLint plugin adapters
11
+ - A generated rule metadata manifest for tooling (`ganko/rules-manifest`)
12
+
13
+ ## Package Entry Points
14
+
15
+ | Entry | Purpose |
16
+ |-------|---------|
17
+ | `ganko` | Full SDK (runner, plugins, graph builders, diagnostics, cache, policy, helpers) |
18
+ | `ganko/eslint-plugin` | Flat-config ESLint plugin with `configs.recommended` |
19
+ | `ganko/rules-manifest` | Lightweight metadata-only rule manifest (`RULES`, `RULES_BY_CATEGORY`, `RULE_CATEGORIES`, `getRule`) |
20
+
21
+ ## Requirements
22
+
23
+ - Node.js `>=22.0.0`
24
+ - TypeScript `^5.9.3` (peer dependency)
25
+ - Bun for local development workflows in this monorepo
26
+
27
+ ## Quick Start
28
+
29
+ ```ts
30
+ import { createRunner, SolidPlugin, CSSPlugin } from "@drskillissue/ganko";
31
+
32
+ const runner = createRunner({
33
+ plugins: [SolidPlugin, CSSPlugin],
34
+ rules: {
35
+ "signal-call": "error",
36
+ "jsx-uses-vars": "off",
37
+ "no-transition-all": "warn",
38
+ },
39
+ });
40
+
41
+ const diagnostics = runner.run([
42
+ "src/App.tsx",
43
+ "src/styles/app.css",
44
+ ]);
45
+ ```
46
+
47
+ `rules` is a map of `rule-id -> "error" | "warn" | "off"`.
48
+
49
+ ## Core Concepts
50
+
51
+ - **Plugin**: owns file filtering, graph construction, and rule execution (`SolidPlugin`, `CSSPlugin`).
52
+ - **Graph**: typed model of a source domain (`SolidGraph`, `CSSGraph`).
53
+ - **Rule**: consumes a typed graph and emits diagnostics via callback.
54
+ - **Runner**: executes plugins across a file list and merges diagnostics.
55
+ - **Emit wrapper**: can rewrite/suppress diagnostics (rule overrides, suppressions).
56
+
57
+ ## Runner API
58
+
59
+ ```ts
60
+ import { createRunner } from "@drskillissue/ganko";
61
+ import type { Runner, RunnerConfig } from "@drskillissue/ganko";
62
+
63
+ const config: RunnerConfig = {
64
+ plugins: [],
65
+ rules: {},
66
+ };
67
+
68
+ const runner: Runner = createRunner(config);
69
+ runner.setRuleOverrides({ "signal-call": "warn" });
70
+ const diagnostics = runner.run(["src/App.tsx"]);
71
+ ```
72
+
73
+ Diagnostic severities are `"error" | "warn"`, matching ESLint convention.
74
+
75
+ ## Parsing And In-Memory Analysis
76
+
77
+ Use these APIs when content is already in memory (ESLint, LSP, tests).
78
+
79
+ ### Solid Input
80
+
81
+ ```ts
82
+ import {
83
+ parseContent,
84
+ parseContentWithProgram,
85
+ analyzeInput,
86
+ buildSolidGraph,
87
+ } from "@drskillissue/ganko";
88
+
89
+ const input = parseContent("src/App.tsx", "export const App = () => <div />");
90
+
91
+ const diagnostics = [];
92
+ analyzeInput(input, (d) => diagnostics.push(d));
93
+
94
+ const graph = buildSolidGraph(input);
95
+ ```
96
+
97
+ `parseContentWithProgram(path, content, program)` is available for type-aware parsing when you already have a `ts.Program`.
98
+
99
+ ### CSS Graph
100
+
101
+ ```ts
102
+ import { buildCSSGraph } from "@drskillissue/ganko";
103
+ import type { CSSInput } from "@drskillissue/ganko";
104
+
105
+ const cssInput: CSSInput = {
106
+ files: [{ path: "src/styles/app.css", content: ".btn { color: red; }" }],
107
+ };
108
+
109
+ const cssGraph = buildCSSGraph(cssInput);
110
+ ```
111
+
112
+ ### Cross-File Analysis
113
+
114
+ ```ts
115
+ import {
116
+ parseContent,
117
+ buildSolidGraph,
118
+ buildCSSGraph,
119
+ buildLayoutGraph,
120
+ runCrossFileRules,
121
+ } from "@drskillissue/ganko";
122
+
123
+ const solidInput = parseContent("src/App.tsx", "export const App = () => <div class=\"btn\" />;");
124
+ const cssInput = { files: [{ path: "src/app.css", content: ".btn { color: red; }" }] };
125
+
126
+ const solids = [buildSolidGraph(solidInput)];
127
+ const css = buildCSSGraph(cssInput);
128
+ const layout = buildLayoutGraph(solids, css);
129
+ runCrossFileRules({ solids, css, layout }, (d) => {
130
+ // handle diagnostic
131
+ });
132
+ ```
133
+
134
+ ## Suppression Directives
135
+
136
+ Inline suppression comments are supported in Solid source files:
137
+
138
+ - `ganko-disable-next-line`
139
+ - `ganko-disable-line`
140
+ - `ganko-disable` (file-wide)
141
+
142
+ Rules may be listed after the directive; if omitted, all rules are suppressed for that scope.
143
+
144
+ ```ts
145
+ // ganko-disable-next-line signal-call
146
+ const view = <div>{count}</div>;
147
+ ```
148
+
149
+ ## Plugins
150
+
151
+ ### `SolidPlugin`
152
+
153
+ - Extensions: `.tsx`, `.jsx`, `.ts`, `.js`, `.mts`, `.cts`, `.mjs`, `.cjs`
154
+ - Parses with `@typescript-eslint/parser`
155
+ - Builds `SolidGraph`
156
+ - Runs Solid rules (reactivity, JSX, correctness, performance, Solid style/import conventions)
157
+
158
+ ### `CSSPlugin`
159
+
160
+ - Extensions: `.css`, `.scss`, `.sass`, `.less`
161
+ - Builds `CSSGraph` from one or many files
162
+ - Runs CSS rules across a11y, animation, cascade, property, selector, and structure categories
163
+
164
+ ### Cross-File Analysis
165
+
166
+ - Uses `buildLayoutGraph` and `runCrossFileRules` for cross-domain analysis
167
+ - Builds `LayoutGraph` on top of Solid + CSS graphs
168
+ - Runs cross-file rules (class name usage, `classList` consistency, JSX inline style policy, layout outlier detection)
169
+
170
+ ## Graph APIs
171
+
172
+ ### `SolidGraph`
173
+
174
+ `SolidGraph` stores typed entities and indexes for:
175
+
176
+ - scopes, variables, functions, calls
177
+ - JSX elements/attributes and static class/classList/style indexes
178
+ - imports/exports
179
+ - reactive computations, dependency edges, ownership edges
180
+
181
+ ### `CSSGraph`
182
+
183
+ `CSSGraph` stores:
184
+
185
+ - files, rules, selectors, declarations
186
+ - CSS custom properties and references
187
+ - at-rules (media, keyframes, layers, containers)
188
+ - selector and property indexes
189
+ - parse errors and unresolved references
190
+ - optional Tailwind validator integration
191
+
192
+ ### `GraphCache`
193
+
194
+ `GraphCache` is exported for LSP-style incremental workflows:
195
+
196
+ ```ts
197
+ import { GraphCache } from "@drskillissue/ganko";
198
+
199
+ const cache = new GraphCache();
200
+
201
+ // per-file/version Solid graph (lazy build on cache miss)
202
+ const solidGraph = cache.getSolidGraph(path, version, () => buildSolidGraph(input));
203
+
204
+ // pre-populate cache with an already-built graph (CLI uses this)
205
+ cache.setSolidGraph(path, version, graph);
206
+
207
+ // check if a graph is cached without building
208
+ cache.hasSolidGraph(path, version); // boolean
209
+
210
+ // workspace CSS graph
211
+ const cssGraph = cache.getCSSGraph(() => buildCSSGraph(cssInput));
212
+
213
+ // derived layout graph
214
+ const layoutGraph = cache.getLayoutGraph(() => buildLayoutGraph([solidGraph], cssGraph));
215
+
216
+ // read-only access to cached graphs (returns null if not cached)
217
+ cache.getCachedCSSGraph();
218
+ cache.getCachedLayoutGraph();
219
+
220
+ // all cached SolidGraphs (for cross-file analysis)
221
+ cache.getAllSolidGraphs(); // readonly SolidGraph[]
222
+
223
+ // cross-file diagnostics cache (avoids re-running cross-file rules during typing)
224
+ cache.getCachedCrossFileDiagnostics(path);
225
+ cache.setCachedCrossFileDiagnostics(path, diagnostics);
226
+ cache.getCachedCrossFileResults(); // null when stale
227
+ cache.setCachedCrossFileResults(allDiagnostics);
228
+
229
+ // invalidation
230
+ cache.invalidate(path); // evict by file kind (solid or css)
231
+ cache.invalidateAll(); // full eviction
232
+
233
+ // introspection
234
+ cache.solidCount; // number of cached SolidGraphs
235
+ ```
236
+
237
+ ## Tailwind And Policy Configuration
238
+
239
+ ### Tailwind class validation
240
+
241
+ `resolveTailwindValidator` is exported for resolving Tailwind CSS class validators. Cross-file undefined-class checks use Tailwind validation when available.
242
+
243
+ ### Accessibility policy
244
+
245
+ `setActivePolicy(name)` sets the active accessibility policy template. Supported names:
246
+
247
+ - `wcag-aa`
248
+ - `wcag-aaa`
249
+ - `mobile-first`
250
+ - `dense-ui`
251
+ - `large-text`
252
+
253
+ Policy-aware rules include CSS and JSX style threshold checks (contrast, spacing, touch target, typography).
254
+
255
+ ## ESLint Integration
256
+
257
+ Use the dedicated subpath export:
258
+
259
+ ```js
260
+ // eslint.config.mjs
261
+ import solid from "@drskillissue/ganko/eslint-plugin";
262
+
263
+ export default [
264
+ ...solid.configs.recommended,
265
+ {
266
+ rules: {
267
+ "solid/signal-call": "error",
268
+ "solid/no-transition-all": "off",
269
+ },
270
+ },
271
+ ];
272
+ ```
273
+
274
+ Notes:
275
+
276
+ - Rule names are `solid/<rule-id>`.
277
+ - `configs.recommended` scopes Solid, CSS, and cross-file rules to matching file globs.
278
+
279
+ ## Rule Manifest (Metadata-Only)
280
+
281
+ For docs/UI/config tools, import metadata without loading full analysis code:
282
+
283
+ ```ts
284
+ import { RULES, RULES_BY_CATEGORY, getRule } from "@drskillissue/ganko/rules-manifest";
285
+
286
+ const allRules = RULES;
287
+ const reactivityRules = RULES_BY_CATEGORY["reactivity"];
288
+ const signalCall = getRule("signal-call");
289
+ ```
290
+
291
+ Manifest generation command:
292
+
293
+ ```bash
294
+ bun run --cwd packages/ganko generate
295
+ ```
296
+
297
+ ## Rule Catalog (Current Manifest)
298
+
299
+ <!-- BEGIN AUTO-GENERATED:rule-catalog -->
300
+ Totals:
301
+
302
+ - 163 rules total
303
+ - 100 Solid rules, 33 CSS rules, 30 cross-file rules
304
+ - 23 fixable rules
305
+
306
+ Category breakdown:
307
+
308
+ | Category | Count |
309
+ |----------|:-----:|
310
+ | `correctness` | 14 |
311
+ | `css-a11y` | 6 |
312
+ | `css-animation` | 6 |
313
+ | `css-cascade` | 5 |
314
+ | `css-jsx` | 15 |
315
+ | `css-layout` | 15 |
316
+ | `css-property` | 7 |
317
+ | `css-selector` | 5 |
318
+ | `css-structure` | 4 |
319
+ | `jsx` | 10 |
320
+ | `performance` | 51 |
321
+ | `reactivity` | 15 |
322
+ | `solid` | 10 |
323
+
324
+ For full, up-to-date rule IDs and descriptions, read the generated manifest via API:
325
+
326
+ ```ts
327
+ import { RULES, RULES_BY_CATEGORY } from "@drskillissue/ganko/rules-manifest"
328
+
329
+ const allRules = RULES
330
+ const cssLayoutRules = RULES_BY_CATEGORY["css-layout"]
331
+
332
+ for (const rule of cssLayoutRules) {
333
+ console.log(`${rule.id} [${rule.plugin}/${rule.severity}] - ${rule.description}`)
334
+ }
335
+ ```
336
+ <!-- END AUTO-GENERATED:rule-catalog -->
337
+
338
+ ## Architecture
339
+
340
+ ```text
341
+ src/
342
+ index.ts Public SDK exports
343
+ graph.ts Graph/plugin contracts and rule metadata shape
344
+ diagnostic.ts Diagnostic and fix models
345
+ runner.ts Plugin runner + rule override emit wrapper
346
+ suppression.ts Inline suppression parser and emit filter
347
+ cache.ts Versioned graph cache for incremental workflows
348
+ eslint-adapter.ts Shared diagnostic -> ESLint adapter utilities
349
+ eslint-plugin.ts Aggregated ESLint plugin entry
350
+ rules-manifest.ts Metadata-only manifest re-export
351
+ generated/
352
+ rules-manifest.ts Auto-generated manifest
353
+
354
+ solid/
355
+ index.ts Solid barrel exports
356
+ plugin.ts SolidPlugin, analyzeInput, buildSolidGraph
357
+ parse.ts parseFile/parseContent/parseContentWithProgram
358
+ impl.ts SolidGraph implementation
359
+ input.ts SolidInput
360
+ rule.ts Solid rule contract
361
+ phases/ Graph build phases
362
+ entities/ Solid entity models
363
+ queries/ Solid query helpers
364
+ rules/ Solid rule implementations
365
+ typescript/ Type resolver integration
366
+ util/ Solid helpers
367
+ eslint-plugin.ts Solid-rule ESLint adapter
368
+
369
+ css/
370
+ index.ts CSS barrel exports
371
+ plugin.ts CSSPlugin, analyzeCSSInput, buildCSSGraph
372
+ impl.ts CSSGraph implementation
373
+ input.ts CSSInput/CSSOptions
374
+ rule.ts CSS rule contract
375
+ intern.ts String interning for CSS identifiers
376
+ layout-taxonomy.ts Layout-affecting property classification
377
+ library-analysis.ts Dependency custom property scanning
378
+ parser/ CSS value/parser helpers
379
+ phases/ CSS graph build phases
380
+ entities/ CSS entity models
381
+ queries/ CSS query helpers
382
+ rules/ CSS rule implementations
383
+ tailwind.ts Tailwind validator integration
384
+ policy.ts Accessibility policy templates and active policy
385
+ analysis/ Additional CSS analysis modules
386
+ eslint-plugin.ts CSS-rule ESLint adapter
387
+
388
+ cross-file/
389
+ index.ts Cross-file barrel exports
390
+ plugin.ts CrossFilePlugin, analyzeCrossFileInput, runCrossFileRules
391
+ rule.ts Cross-rule contract
392
+ queries.ts Cross-file utility queries
393
+ rules/ Cross-file rule implementations
394
+ layout/ Layout graph + scoring/detection pipeline
395
+ eslint-plugin.ts Cross-file ESLint adapter
396
+
397
+ util/
398
+ query-ops.ts Shared query operation helpers
399
+
400
+ scripts/
401
+ generate-rules-manifest.ts
402
+ generate-rule-readmes.ts
403
+ ```
404
+
405
+ ## Development
406
+
407
+ From monorepo root:
408
+
409
+ ```bash
410
+ bun run --cwd packages/ganko generate
411
+ bun run --cwd packages/ganko build
412
+ bun run --cwd packages/ganko test
413
+ bun run --cwd packages/ganko lint
414
+ bun run --cwd packages/ganko tsc
415
+ ```
416
+
417
+ From `packages/ganko` directly:
418
+
419
+ ```bash
420
+ bun run generate
421
+ bun run build
422
+ bun run test
423
+ bun run test:watch
424
+ bun run lint
425
+ bun run tsc
426
+ ```
427
+
428
+ ## License
429
+
430
+ MIT