@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.
@@ -0,0 +1,40 @@
1
+ import { TSESLint } from '@typescript-eslint/utils';
2
+
3
+ /**
4
+ * Shared ESLint Adapter Utilities
5
+ *
6
+ * Common infrastructure for bridging ganko's rule engine into
7
+ * ESLint's plugin format. Used by each plugin's eslint-plugin.ts.
8
+ */
9
+
10
+ type RuleModule = TSESLint.RuleModule<string>;
11
+
12
+ /**
13
+ * ESLint Plugin
14
+ *
15
+ * Aggregates all ganko rule engines (Solid, CSS, cross-file) into
16
+ * a single ESLint plugin. Each plugin directory owns its own ESLint
17
+ * adapter; this module merges their rules and builds configs.
18
+ *
19
+ * @example
20
+ * ```js
21
+ * // eslint.config.mjs
22
+ * import solid from "@drskillissue/ganko/eslint-plugin"
23
+ *
24
+ * export default [
25
+ * ...solid.configs.recommended,
26
+ * ]
27
+ * ```
28
+ */
29
+
30
+ interface SolidLintPlugin {
31
+ readonly meta: {
32
+ readonly name: string;
33
+ readonly version: string;
34
+ };
35
+ readonly rules: Record<string, RuleModule>;
36
+ readonly configs: Record<string, TSESLint.FlatConfig.ConfigArray>;
37
+ }
38
+ declare const plugin: SolidLintPlugin;
39
+
40
+ export { plugin as default };
@@ -0,0 +1,40 @@
1
+ import { TSESLint } from '@typescript-eslint/utils';
2
+
3
+ /**
4
+ * Shared ESLint Adapter Utilities
5
+ *
6
+ * Common infrastructure for bridging ganko's rule engine into
7
+ * ESLint's plugin format. Used by each plugin's eslint-plugin.ts.
8
+ */
9
+
10
+ type RuleModule = TSESLint.RuleModule<string>;
11
+
12
+ /**
13
+ * ESLint Plugin
14
+ *
15
+ * Aggregates all ganko rule engines (Solid, CSS, cross-file) into
16
+ * a single ESLint plugin. Each plugin directory owns its own ESLint
17
+ * adapter; this module merges their rules and builds configs.
18
+ *
19
+ * @example
20
+ * ```js
21
+ * // eslint.config.mjs
22
+ * import solid from "@drskillissue/ganko/eslint-plugin"
23
+ *
24
+ * export default [
25
+ * ...solid.configs.recommended,
26
+ * ]
27
+ * ```
28
+ */
29
+
30
+ interface SolidLintPlugin {
31
+ readonly meta: {
32
+ readonly name: string;
33
+ readonly version: string;
34
+ };
35
+ readonly rules: Record<string, RuleModule>;
36
+ readonly configs: Record<string, TSESLint.FlatConfig.ConfigArray>;
37
+ }
38
+ declare const plugin: SolidLintPlugin;
39
+
40
+ export { plugin as default };
@@ -0,0 +1,301 @@
1
+ import {
2
+ SolidGraph,
3
+ buildCSSGraph,
4
+ buildLayoutGraph,
5
+ resolveTailwindValidatorSync,
6
+ rules,
7
+ rules2,
8
+ rules3,
9
+ runCrossFileRules,
10
+ runPhases
11
+ } from "./chunk-RB7SZIJX.js";
12
+
13
+ // src/eslint-adapter.ts
14
+ function buildSolidInputFromContext(context) {
15
+ const sourceCode = context.sourceCode;
16
+ return {
17
+ file: context.filename,
18
+ sourceCode,
19
+ parserServices: sourceCode.parserServices ?? null,
20
+ checker: null
21
+ };
22
+ }
23
+ var MSG_ID = "_msg";
24
+ var MSG_TEMPLATE = { [MSG_ID]: "{{msg}}" };
25
+ function applyFix(fixer, op) {
26
+ return fixer.replaceTextRange([op.range[0], op.range[1]], op.text);
27
+ }
28
+ function toESLintFix(fix) {
29
+ return (fixer) => {
30
+ const first = fix[0];
31
+ if (fix.length === 1 && first) return applyFix(fixer, first);
32
+ const fixes = [];
33
+ for (let i = 0; i < fix.length; i++) {
34
+ const op = fix[i];
35
+ if (!op) continue;
36
+ fixes.push(applyFix(fixer, op));
37
+ }
38
+ return fixes;
39
+ };
40
+ }
41
+ function toESLintSuggestions(suggestions) {
42
+ const result = [];
43
+ for (let i = 0; i < suggestions.length; i++) {
44
+ const s = suggestions[i];
45
+ if (!s) continue;
46
+ result.push({
47
+ messageId: MSG_ID,
48
+ data: { msg: s.message },
49
+ fix: toESLintFix(s.fix)
50
+ });
51
+ }
52
+ return result;
53
+ }
54
+ function createRuleModule(rule, getGraph) {
55
+ const meta = {
56
+ type: "problem",
57
+ docs: {
58
+ description: rule.meta.description
59
+ },
60
+ messages: MSG_TEMPLATE,
61
+ schema: []
62
+ };
63
+ if (rule.meta.fixable) meta.fixable = "code";
64
+ return {
65
+ meta,
66
+ defaultOptions: [],
67
+ create(context) {
68
+ return {
69
+ Program() {
70
+ const graph = getGraph(context);
71
+ const diagnostics = [];
72
+ const emit = (d) => diagnostics.push(d);
73
+ rule.check(graph, emit);
74
+ for (let i = 0; i < diagnostics.length; i++) {
75
+ const diag = diagnostics[i];
76
+ if (!diag) continue;
77
+ reportDiagnostic(context, diag);
78
+ }
79
+ }
80
+ };
81
+ }
82
+ };
83
+ }
84
+ function createCachedPluginAdapter(rules4, buildGraph) {
85
+ const cache = /* @__PURE__ */ new WeakMap();
86
+ function getGraph(context) {
87
+ const sourceCode = context.sourceCode;
88
+ const cached = cache.get(sourceCode);
89
+ if (cached) return cached;
90
+ const graph = buildGraph(context);
91
+ cache.set(sourceCode, graph);
92
+ return graph;
93
+ }
94
+ const eslintRules4 = {};
95
+ for (let i = 0; i < rules4.length; i++) {
96
+ const r = rules4[i];
97
+ if (!r) continue;
98
+ eslintRules4[r.id] = createRuleModule(r, getGraph);
99
+ }
100
+ return { eslintRules: eslintRules4 };
101
+ }
102
+ function createBatchPluginAdapter(rules4, buildContext, runAll) {
103
+ const cache = /* @__PURE__ */ new WeakMap();
104
+ function getResults(context) {
105
+ const sourceCode = context.sourceCode;
106
+ const cached = cache.get(sourceCode);
107
+ if (cached) return cached;
108
+ const graph = buildContext(context);
109
+ const byRule = /* @__PURE__ */ new Map();
110
+ const emit = (d) => {
111
+ const list = byRule.get(d.rule);
112
+ if (list) {
113
+ list.push(d);
114
+ } else {
115
+ byRule.set(d.rule, [d]);
116
+ }
117
+ };
118
+ runAll(graph, emit);
119
+ cache.set(sourceCode, byRule);
120
+ return byRule;
121
+ }
122
+ function createBatchRuleModule(rule, getResults2) {
123
+ const meta = {
124
+ type: "problem",
125
+ docs: { description: rule.meta.description },
126
+ messages: MSG_TEMPLATE,
127
+ schema: []
128
+ };
129
+ if (rule.meta.fixable) meta.fixable = "code";
130
+ return {
131
+ meta,
132
+ defaultOptions: [],
133
+ create(context) {
134
+ return {
135
+ Program() {
136
+ const results = getResults2(context);
137
+ const diagnostics = results.get(rule.id) ?? [];
138
+ for (let j = 0; j < diagnostics.length; j++) {
139
+ const diag = diagnostics[j];
140
+ if (!diag) continue;
141
+ reportDiagnostic(context, diag);
142
+ }
143
+ }
144
+ };
145
+ }
146
+ };
147
+ }
148
+ const eslintRules4 = {};
149
+ for (let i = 0; i < rules4.length; i++) {
150
+ const rule = rules4[i];
151
+ if (!rule) continue;
152
+ eslintRules4[rule.id] = createBatchRuleModule(rule, getResults);
153
+ }
154
+ return { eslintRules: eslintRules4 };
155
+ }
156
+ function reportDiagnostic(context, d) {
157
+ const data = { msg: d.message };
158
+ if (d.fix) {
159
+ if (d.suggest && d.suggest.length > 0) {
160
+ context.report({
161
+ messageId: MSG_ID,
162
+ data,
163
+ loc: d.loc,
164
+ fix: toESLintFix(d.fix),
165
+ suggest: toESLintSuggestions(d.suggest)
166
+ });
167
+ } else {
168
+ context.report({
169
+ messageId: MSG_ID,
170
+ data,
171
+ loc: d.loc,
172
+ fix: toESLintFix(d.fix)
173
+ });
174
+ }
175
+ } else if (d.suggest && d.suggest.length > 0) {
176
+ context.report({
177
+ messageId: MSG_ID,
178
+ data,
179
+ loc: d.loc,
180
+ suggest: toESLintSuggestions(d.suggest)
181
+ });
182
+ } else {
183
+ context.report({
184
+ messageId: MSG_ID,
185
+ data,
186
+ loc: d.loc
187
+ });
188
+ }
189
+ }
190
+
191
+ // src/solid/eslint-plugin.ts
192
+ var { eslintRules } = createCachedPluginAdapter(rules, (context) => {
193
+ const input = buildSolidInputFromContext(context);
194
+ const graph = new SolidGraph(input);
195
+ runPhases(graph, input);
196
+ return graph;
197
+ });
198
+
199
+ // src/css/eslint-plugin.ts
200
+ var { eslintRules: eslintRules2 } = createCachedPluginAdapter(rules2, (context) => {
201
+ const input = {
202
+ files: [{ path: context.filename, content: context.sourceCode.getText() }]
203
+ };
204
+ return buildCSSGraph(input);
205
+ });
206
+
207
+ // src/cross-file/eslint-plugin.ts
208
+ import { CSS_EXTENSIONS, canonicalPath, matchesExtension } from "@drskillissue/ganko-shared";
209
+ import { existsSync, readFileSync } from "fs";
210
+ import { dirname, resolve } from "path";
211
+ function findImportedCSS(graph) {
212
+ const out = [];
213
+ const seen = /* @__PURE__ */ new Set();
214
+ const baseDir = dirname(graph.file);
215
+ for (let i = 0; i < graph.imports.length; i++) {
216
+ const imp = graph.imports[i];
217
+ if (!imp) continue;
218
+ const source = imp.source;
219
+ if (!matchesExtension(source, CSS_EXTENSIONS)) continue;
220
+ const filePath = canonicalPath(resolve(baseDir, source));
221
+ if (!existsSync(filePath)) continue;
222
+ if (seen.has(filePath)) continue;
223
+ seen.add(filePath);
224
+ out.push({ path: filePath, content: readFileSync(filePath, "utf-8") });
225
+ }
226
+ return out;
227
+ }
228
+ function buildCrossContext(context) {
229
+ const input = buildSolidInputFromContext(context);
230
+ const solidGraph = new SolidGraph(input);
231
+ runPhases(solidGraph, input);
232
+ const cssFiles2 = findImportedCSS(solidGraph);
233
+ const tailwind = cssFiles2.length > 0 ? resolveTailwindValidatorSync(cssFiles2) : null;
234
+ const resolved = tailwind ?? void 0;
235
+ const cssInput = { files: cssFiles2 };
236
+ if (resolved !== void 0) cssInput.tailwind = resolved;
237
+ const cssGraph = buildCSSGraph(cssInput);
238
+ return {
239
+ solids: [solidGraph],
240
+ css: cssGraph,
241
+ layout: buildLayoutGraph([solidGraph], cssGraph)
242
+ };
243
+ }
244
+ var { eslintRules: eslintRules3 } = createBatchPluginAdapter(
245
+ rules3,
246
+ buildCrossContext,
247
+ runCrossFileRules
248
+ );
249
+
250
+ // src/eslint-plugin.ts
251
+ import { SOLID_EXTENSIONS, CSS_EXTENSIONS as CSS_EXTENSIONS2, extensionsToGlobs } from "@drskillissue/ganko-shared";
252
+ var allRules = {
253
+ ...eslintRules,
254
+ ...eslintRules2,
255
+ ...eslintRules3
256
+ };
257
+ var configs = {};
258
+ var plugin = {
259
+ meta: {
260
+ name: "eslint-plugin-ganko",
261
+ version: "0.1.0"
262
+ },
263
+ rules: allRules,
264
+ configs
265
+ };
266
+ function buildRuleConfig(ruleList) {
267
+ const out = {};
268
+ for (let i = 0; i < ruleList.length; i++) {
269
+ const r = ruleList[i];
270
+ if (!r) continue;
271
+ out[`solid/${r.id}`] = r.severity === "off" ? "off" : r.severity === "warn" ? "warn" : "error";
272
+ }
273
+ return out;
274
+ }
275
+ var solidOnlyRules = buildRuleConfig(rules);
276
+ var cssOnlyRules = buildRuleConfig(rules2);
277
+ var crossFileOnlyRules = buildRuleConfig(rules3);
278
+ var tsFiles = extensionsToGlobs(SOLID_EXTENSIONS);
279
+ var cssFiles = extensionsToGlobs(CSS_EXTENSIONS2);
280
+ plugin.configs["recommended"] = [
281
+ {
282
+ plugins: { solid: plugin },
283
+ files: tsFiles,
284
+ rules: solidOnlyRules
285
+ },
286
+ {
287
+ plugins: { solid: plugin },
288
+ files: cssFiles,
289
+ rules: cssOnlyRules
290
+ },
291
+ {
292
+ plugins: { solid: plugin },
293
+ files: [...tsFiles, ...cssFiles],
294
+ rules: crossFileOnlyRules
295
+ }
296
+ ];
297
+ var eslint_plugin_default = plugin;
298
+ export {
299
+ eslint_plugin_default as default
300
+ };
301
+ //# sourceMappingURL=eslint-plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/eslint-adapter.ts","../src/solid/eslint-plugin.ts","../src/css/eslint-plugin.ts","../src/cross-file/eslint-plugin.ts","../src/eslint-plugin.ts"],"sourcesContent":["/**\n * Shared ESLint Adapter Utilities\n *\n * Common infrastructure for bridging ganko's rule engine into\n * ESLint's plugin format. Used by each plugin's eslint-plugin.ts.\n */\nimport type { TSESLint } from \"@typescript-eslint/utils\"\nimport type { Diagnostic, Fix, FixOperation, Suggestion } from \"./diagnostic\"\nimport type { BaseRule, Emit } from \"./graph\"\nimport type { SolidInput } from \"./solid/input\"\n\nexport type RuleModule = TSESLint.RuleModule<string>\nexport type RuleContext = TSESLint.RuleContext<string, readonly unknown[]>\n\n/**\n * Build a SolidInput from an ESLint rule context.\n */\nexport function buildSolidInputFromContext(context: RuleContext): SolidInput {\n const sourceCode = context.sourceCode\n return {\n file: context.filename,\n sourceCode,\n parserServices: sourceCode.parserServices ?? null,\n checker: null,\n }\n}\n\n/**\n * Passthrough message ID used by all rules.\n *\n * ganko resolves message templates at emit time, so the ESLint\n * adapter uses a single passthrough template that receives the\n * pre-resolved message via data.\n */\nexport const MSG_ID = \"_msg\" as const\nexport const MSG_TEMPLATE = { [MSG_ID]: \"{{msg}}\" }\n\n/**\n * Convert a ganko FixOperation to an ESLint RuleFix.\n */\nfunction applyFix(fixer: TSESLint.RuleFixer, op: FixOperation): TSESLint.RuleFix {\n return fixer.replaceTextRange([op.range[0], op.range[1]], op.text)\n}\n\n/**\n * Convert a ganko Fix to an ESLint fix function.\n */\nexport function toESLintFix(fix: Fix): (fixer: TSESLint.RuleFixer) => TSESLint.RuleFix | TSESLint.RuleFix[] {\n return (fixer) => {\n const first = fix[0]\n if (fix.length === 1 && first) return applyFix(fixer, first)\n const fixes: TSESLint.RuleFix[] = []\n for (let i = 0; i < fix.length; i++) {\n const op = fix[i]\n if (!op) continue\n fixes.push(applyFix(fixer, op))\n }\n return fixes\n }\n}\n\n/**\n * Convert ganko suggestions to ESLint suggestion descriptors.\n */\nexport function toESLintSuggestions(\n suggestions: readonly Suggestion[],\n): TSESLint.SuggestionReportDescriptor<string>[] {\n const result: TSESLint.SuggestionReportDescriptor<string>[] = []\n for (let i = 0; i < suggestions.length; i++) {\n const s = suggestions[i]\n if (!s) continue\n result.push({\n messageId: MSG_ID,\n data: { msg: s.message },\n fix: toESLintFix(s.fix),\n })\n }\n return result\n}\n\n/**\n * Create an ESLint RuleModule from a ganko rule.\n *\n * Works for any rule+graph pair where the graph is obtained from a\n * context-keyed getter (SolidRule+SolidGraph, CSSRule+CSSGraph).\n */\nexport function createRuleModule<G>(\n rule: BaseRule<G>,\n getGraph: (context: RuleContext) => G,\n): RuleModule {\n const meta: TSESLint.RuleMetaData<string> = {\n type: \"problem\",\n docs: {\n description: rule.meta.description,\n },\n messages: MSG_TEMPLATE,\n schema: [],\n }\n if (rule.meta.fixable) meta.fixable = \"code\" as const\n return {\n meta,\n defaultOptions: [],\n create(context) {\n return {\n Program() {\n const graph = getGraph(context)\n const diagnostics: Diagnostic[] = []\n const emit: Emit = (d) => diagnostics.push(d)\n\n rule.check(graph, emit)\n\n for (let i = 0; i < diagnostics.length; i++) {\n const diag = diagnostics[i]\n if (!diag) continue\n reportDiagnostic(context, diag)\n }\n },\n }\n },\n }\n}\n\n/**\n * Create a cached ESLint plugin adapter from rules and a graph builder.\n *\n * Handles the SourceCode-keyed WeakMap cache and the rules-to-modules\n * loop that is identical across Solid and CSS eslint-plugin files.\n */\nexport function createCachedPluginAdapter<G>(\n rules: readonly BaseRule<G>[],\n buildGraph: (context: RuleContext) => G,\n): { eslintRules: Record<string, RuleModule> } {\n const cache = new WeakMap<TSESLint.SourceCode, G>()\n\n function getGraph(context: RuleContext): G {\n const sourceCode = context.sourceCode\n const cached = cache.get(sourceCode)\n if (cached) return cached\n const graph = buildGraph(context)\n cache.set(sourceCode, graph)\n return graph\n }\n\n const eslintRules: Record<string, RuleModule> = {}\n for (let i = 0; i < rules.length; i++) {\n const r = rules[i]\n if (!r) continue\n eslintRules[r.id] = createRuleModule(r, getGraph)\n }\n\n return { eslintRules }\n}\n\n/**\n * Create an ESLint plugin adapter for rules that run in batch (all rules share\n * one analysis pass). The runAll function receives the context built from a\n * single ESLint RuleContext and an emit callback, runs analysis once, and\n * emits diagnostics keyed by rule ID.\n *\n * Used by cross-file rules where graph construction is expensive and shared.\n */\nexport function createBatchPluginAdapter<G>(\n rules: readonly BaseRule<G>[],\n buildContext: (context: RuleContext) => G,\n runAll: (graph: G, emit: Emit) => void,\n): { eslintRules: Record<string, RuleModule> } {\n const cache = new WeakMap<TSESLint.SourceCode, ReadonlyMap<string, readonly Diagnostic[]>>()\n\n function getResults(context: RuleContext): ReadonlyMap<string, readonly Diagnostic[]> {\n const sourceCode = context.sourceCode\n const cached = cache.get(sourceCode)\n if (cached) return cached\n\n const graph = buildContext(context)\n const byRule = new Map<string, Diagnostic[]>()\n const emit: Emit = (d) => {\n const list = byRule.get(d.rule)\n if (list) { list.push(d) }\n else { byRule.set(d.rule, [d]) }\n }\n runAll(graph, emit)\n cache.set(sourceCode, byRule)\n return byRule\n }\n\n function createBatchRuleModule(\n rule: BaseRule<G>,\n getResults: (context: RuleContext) => ReadonlyMap<string, readonly Diagnostic[]>,\n ): RuleModule {\n const meta: TSESLint.RuleMetaData<string> = {\n type: \"problem\",\n docs: { description: rule.meta.description },\n messages: MSG_TEMPLATE,\n schema: [],\n }\n if (rule.meta.fixable) meta.fixable = \"code\" as const\n return {\n meta,\n defaultOptions: [],\n create(context) {\n return {\n Program() {\n const results = getResults(context)\n const diagnostics = results.get(rule.id) ?? []\n for (let j = 0; j < diagnostics.length; j++) {\n const diag = diagnostics[j]\n if (!diag) continue\n reportDiagnostic(context, diag)\n }\n },\n }\n },\n }\n }\n\n const eslintRules: Record<string, RuleModule> = {}\n for (let i = 0; i < rules.length; i++) {\n const rule = rules[i]\n if (!rule) continue\n eslintRules[rule.id] = createBatchRuleModule(rule, getResults)\n }\n return { eslintRules }\n}\n\n/**\n * Report a ganko Diagnostic through ESLint's context.report().\n */\nexport function reportDiagnostic(context: RuleContext, d: Diagnostic): void {\n const data = { msg: d.message }\n\n if (d.fix) {\n if (d.suggest && d.suggest.length > 0) {\n context.report({\n messageId: MSG_ID,\n data,\n loc: d.loc,\n fix: toESLintFix(d.fix),\n suggest: toESLintSuggestions(d.suggest),\n })\n } else {\n context.report({\n messageId: MSG_ID,\n data,\n loc: d.loc,\n fix: toESLintFix(d.fix),\n })\n }\n } else if (d.suggest && d.suggest.length > 0) {\n context.report({\n messageId: MSG_ID,\n data,\n loc: d.loc,\n suggest: toESLintSuggestions(d.suggest),\n })\n } else {\n context.report({\n messageId: MSG_ID,\n data,\n loc: d.loc,\n })\n }\n}\n","/**\n * Solid ESLint Plugin Adapter\n *\n * Bridges ganko's Solid rules into ESLint's plugin format.\n * The SolidGraph is built once per file and cached via WeakMap on\n * SourceCode (unique per file per lint run).\n */\nimport { SolidGraph } from \"./impl\"\nimport { runPhases } from \"./phases\"\nimport { rules } from \"./rules\"\nimport { createCachedPluginAdapter, buildSolidInputFromContext } from \"../eslint-adapter\"\n\n/** All Solid rules as ESLint RuleModules, keyed by rule ID. */\nexport const { eslintRules } = createCachedPluginAdapter(rules, (context) => {\n const input = buildSolidInputFromContext(context)\n const graph = new SolidGraph(input)\n runPhases(graph, input)\n return graph\n})\n\n/** Solid rules array for config generation. */\nexport { rules }\n","/**\n * CSS ESLint Plugin Adapter\n *\n * Bridges ganko's CSS rules into ESLint's plugin format.\n * The CSSGraph is built once per file and cached via WeakMap on SourceCode.\n */\nimport type { CSSInput } from \"./input\"\nimport { buildCSSGraph } from \"./plugin\"\nimport { rules } from \"./rules\"\nimport { createCachedPluginAdapter } from \"../eslint-adapter\"\n\n/** All CSS rules as ESLint RuleModules, keyed by rule ID. */\nexport const { eslintRules } = createCachedPluginAdapter(rules, (context) => {\n const input: CSSInput = {\n files: [{ path: context.filename, content: context.sourceCode.getText() }],\n }\n return buildCSSGraph(input)\n})\n\n/** CSS rules array for config generation. */\nexport { rules }\n","/**\n * Cross-File ESLint Plugin Adapter\n *\n * Bridges ganko's cross-file rules into ESLint's plugin format.\n *\n * Cross-file rules require both SolidGraph and CSSGraph. In ESLint's\n * per-file model, these rules run on Solid files (.tsx/.jsx/.ts) and\n * resolve CSS files from static import declarations.\n *\n * Uses createBatchPluginAdapter: all cross-file rules share one analysis\n * pass per SourceCode instance, avoiding redundant graph construction.\n */\nimport { CSS_EXTENSIONS, canonicalPath, matchesExtension } from \"@drskillissue/ganko-shared\"\nimport { createBatchPluginAdapter, buildSolidInputFromContext } from \"../eslint-adapter\"\nimport type { RuleContext } from \"../eslint-adapter\"\nimport type { CrossRuleContext } from \"./rule\"\nimport { SolidGraph } from \"../solid/impl\"\nimport { runPhases as runSolidPhases } from \"../solid/phases\"\nimport type { CSSInput } from \"../css/input\"\nimport { buildCSSGraph } from \"../css/plugin\"\nimport { buildLayoutGraph } from \"./layout\"\nimport { runCrossFileRules } from \"./plugin\"\nimport { resolveTailwindValidatorSync } from \"../css/tailwind\"\nimport { rules } from \"./rules\"\nimport { existsSync, readFileSync } from \"node:fs\"\nimport { dirname, resolve } from \"node:path\"\n\nfunction findImportedCSS(graph: SolidGraph): readonly { path: string; content: string }[] {\n const out: { path: string; content: string }[] = []\n const seen = new Set<string>()\n const baseDir = dirname(graph.file)\n\n for (let i = 0; i < graph.imports.length; i++) {\n const imp = graph.imports[i]\n if (!imp) continue\n const source = imp.source\n if (!matchesExtension(source, CSS_EXTENSIONS)) continue\n const filePath = canonicalPath(resolve(baseDir, source))\n if (!existsSync(filePath)) continue\n if (seen.has(filePath)) continue\n seen.add(filePath)\n out.push({ path: filePath, content: readFileSync(filePath, \"utf-8\") })\n }\n\n return out\n}\n\nfunction buildCrossContext(context: RuleContext): CrossRuleContext {\n const input = buildSolidInputFromContext(context)\n const solidGraph = new SolidGraph(input)\n runSolidPhases(solidGraph, input)\n\n const cssFiles = findImportedCSS(solidGraph)\n const tailwind = cssFiles.length > 0 ? resolveTailwindValidatorSync(cssFiles) : null\n const resolved = tailwind ?? undefined\n const cssInput: { -readonly [K in keyof CSSInput]: CSSInput[K] } = { files: cssFiles }\n if (resolved !== undefined) cssInput.tailwind = resolved\n const cssGraph = buildCSSGraph(cssInput)\n return {\n solids: [solidGraph],\n css: cssGraph,\n layout: buildLayoutGraph([solidGraph], cssGraph),\n }\n}\n\nexport const { eslintRules } = createBatchPluginAdapter(\n rules,\n buildCrossContext,\n runCrossFileRules,\n)\n\nexport { rules }\n","/**\n * ESLint Plugin\n *\n * Aggregates all ganko rule engines (Solid, CSS, cross-file) into\n * a single ESLint plugin. Each plugin directory owns its own ESLint\n * adapter; this module merges their rules and builds configs.\n *\n * @example\n * ```js\n * // eslint.config.mjs\n * import solid from \"@drskillissue/ganko/eslint-plugin\"\n *\n * export default [\n * ...solid.configs.recommended,\n * ]\n * ```\n */\nimport type { TSESLint } from \"@typescript-eslint/utils\"\nimport type { RuleModule } from \"./eslint-adapter\"\nimport { eslintRules as solidRules, rules as solidRuleList } from \"./solid/eslint-plugin\"\nimport { eslintRules as cssRules, rules as cssRuleList } from \"./css/eslint-plugin\"\nimport { eslintRules as crossFileRules, rules as crossFileRuleList } from \"./cross-file/eslint-plugin\"\nimport { SOLID_EXTENSIONS, CSS_EXTENSIONS, extensionsToGlobs } from \"@drskillissue/ganko-shared\"\n\n/** Merge all rule modules into a single record. */\nconst allRules: Record<string, RuleModule> = {\n ...solidRules,\n ...cssRules,\n ...crossFileRules,\n}\n\ninterface SolidLintPlugin {\n readonly meta: { readonly name: string; readonly version: string }\n readonly rules: Record<string, RuleModule>\n readonly configs: Record<string, TSESLint.FlatConfig.ConfigArray>\n}\n\nconst configs: Record<string, TSESLint.FlatConfig.ConfigArray> = {}\n\nconst plugin: SolidLintPlugin = {\n meta: {\n name: \"eslint-plugin-ganko\",\n version: \"0.1.0\",\n },\n rules: allRules,\n configs,\n}\n\nfunction buildRuleConfig(\n ruleList: readonly { readonly id: string; readonly severity: string }[],\n): Partial<Record<string, TSESLint.SharedConfig.RuleEntry>> {\n const out: Partial<Record<string, TSESLint.SharedConfig.RuleEntry>> = {}\n for (let i = 0; i < ruleList.length; i++) {\n const r = ruleList[i]\n if (!r) continue\n out[`solid/${r.id}`] = r.severity === \"off\" ? \"off\" : r.severity === \"warn\" ? \"warn\" : \"error\"\n }\n return out\n}\n\nconst solidOnlyRules = buildRuleConfig(solidRuleList)\nconst cssOnlyRules = buildRuleConfig(cssRuleList)\nconst crossFileOnlyRules = buildRuleConfig(crossFileRuleList)\n\nconst tsFiles = extensionsToGlobs(SOLID_EXTENSIONS)\nconst cssFiles = extensionsToGlobs(CSS_EXTENSIONS)\n\nplugin.configs[\"recommended\"] = [\n {\n plugins: { solid: plugin },\n files: tsFiles,\n rules: solidOnlyRules,\n },\n {\n plugins: { solid: plugin },\n files: cssFiles,\n rules: cssOnlyRules,\n },\n {\n plugins: { solid: plugin },\n files: [...tsFiles, ...cssFiles],\n rules: crossFileOnlyRules,\n },\n]\n\nexport default plugin\n"],"mappings":"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","names":["rules","eslintRules","getResults","eslintRules","rules","cssFiles","eslintRules","rules","CSS_EXTENSIONS","eslintRules","rules"]}