@drskillissue/ganko 0.1.18 → 0.1.20
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/dist/{chunk-OYGFWDEL.js → chunk-PX2XCAZW.js} +189 -21
- package/dist/chunk-PX2XCAZW.js.map +1 -0
- package/dist/eslint-plugin.cjs +192 -23
- package/dist/eslint-plugin.cjs.map +1 -1
- package/dist/eslint-plugin.js +4 -2
- package/dist/eslint-plugin.js.map +1 -1
- package/dist/index.cjs +210 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +34 -1
- package/dist/index.d.ts +34 -1
- package/dist/index.js +21 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-OYGFWDEL.js.map +0 -1
package/dist/eslint-plugin.js
CHANGED
|
@@ -7,13 +7,14 @@ import {
|
|
|
7
7
|
canonicalPath,
|
|
8
8
|
extensionsToGlobs,
|
|
9
9
|
matchesExtension,
|
|
10
|
+
noopLogger,
|
|
10
11
|
resolveTailwindValidatorSync,
|
|
11
12
|
rules,
|
|
12
13
|
rules2,
|
|
13
14
|
rules3,
|
|
14
15
|
runCrossFileRules,
|
|
15
16
|
runPhases
|
|
16
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-PX2XCAZW.js";
|
|
17
18
|
import "./chunk-EGRHWZRV.js";
|
|
18
19
|
|
|
19
20
|
// src/eslint-adapter.ts
|
|
@@ -243,7 +244,8 @@ function buildCrossContext(context) {
|
|
|
243
244
|
return {
|
|
244
245
|
solids: [solidGraph],
|
|
245
246
|
css: cssGraph,
|
|
246
|
-
layout: buildLayoutGraph([solidGraph], cssGraph)
|
|
247
|
+
layout: buildLayoutGraph([solidGraph], cssGraph),
|
|
248
|
+
logger: noopLogger
|
|
247
249
|
};
|
|
248
250
|
}
|
|
249
251
|
var { eslintRules: eslintRules3 } = createBatchPluginAdapter(
|
|
@@ -1 +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","eslintRules","rules"]}
|
|
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, noopLogger } 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 logger: noopLogger,\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","eslintRules","rules"]}
|
package/dist/index.cjs
CHANGED
|
@@ -2805,6 +2805,26 @@ var GraphCache = class {
|
|
|
2805
2805
|
this.solidGeneration++;
|
|
2806
2806
|
if (this.log.enabled) this.log.debug(`setSolidGraph: ${key} v=${version} (${this.solids.size} total) solidGen=${this.solidGeneration}`);
|
|
2807
2807
|
}
|
|
2808
|
+
/**
|
|
2809
|
+
* Get a cached SolidGraph without building on miss.
|
|
2810
|
+
*
|
|
2811
|
+
* Returns the cached graph if the version matches, null otherwise.
|
|
2812
|
+
* Use when the caller has already confirmed the entry exists via
|
|
2813
|
+
* `hasSolidGraph` and wants to avoid allocating a builder closure.
|
|
2814
|
+
*
|
|
2815
|
+
* @param path Absolute file path
|
|
2816
|
+
* @param version Script version string from the TS project service
|
|
2817
|
+
*/
|
|
2818
|
+
getCachedSolidGraph(path, version) {
|
|
2819
|
+
const key = canonicalPath(path);
|
|
2820
|
+
const cached = this.solids.get(key);
|
|
2821
|
+
if (cached !== void 0 && cached.version === version) {
|
|
2822
|
+
if (this.log.enabled) this.log.debug(`getCachedSolidGraph HIT: ${key} v=${version}`);
|
|
2823
|
+
return cached.graph;
|
|
2824
|
+
}
|
|
2825
|
+
if (this.log.enabled) this.log.debug(`getCachedSolidGraph MISS: ${key} v=${version}`);
|
|
2826
|
+
return null;
|
|
2827
|
+
}
|
|
2808
2828
|
/**
|
|
2809
2829
|
* Get or build a SolidGraph for a file path.
|
|
2810
2830
|
*
|
|
@@ -29273,7 +29293,8 @@ var cssRequireReducedMotionOverride = defineCSSRule({
|
|
|
29273
29293
|
for (let j = 0; j < resolved.length; j++) {
|
|
29274
29294
|
const sel = resolved[j];
|
|
29275
29295
|
if (!sel) continue;
|
|
29276
|
-
|
|
29296
|
+
const key = `${normalizeSelector2(sel)}|${group}`;
|
|
29297
|
+
reduced.add(key);
|
|
29277
29298
|
}
|
|
29278
29299
|
}
|
|
29279
29300
|
for (let i = 0; i < motionDecls.length; i++) {
|
|
@@ -29292,7 +29313,8 @@ var cssRequireReducedMotionOverride = defineCSSRule({
|
|
|
29292
29313
|
for (let j = 0; j < resolved.length; j++) {
|
|
29293
29314
|
const sel = resolved[j];
|
|
29294
29315
|
if (!sel) continue;
|
|
29295
|
-
|
|
29316
|
+
const key = `${normalizeSelector2(sel)}|${group}`;
|
|
29317
|
+
if (reduced.has(key)) {
|
|
29296
29318
|
covered = true;
|
|
29297
29319
|
break;
|
|
29298
29320
|
}
|
|
@@ -30700,6 +30722,16 @@ function readKnownNormalizedWithGuard(snapshot, name) {
|
|
|
30700
30722
|
if (!value2) return null;
|
|
30701
30723
|
return value2.normalized;
|
|
30702
30724
|
}
|
|
30725
|
+
function isLayoutHidden(node, snapshotByElementNode) {
|
|
30726
|
+
if (node.attributes.has("hidden")) return true;
|
|
30727
|
+
if (node.classTokenSet.has("hidden")) return true;
|
|
30728
|
+
const snapshot = snapshotByElementNode.get(node);
|
|
30729
|
+
if (snapshot) {
|
|
30730
|
+
const display = readKnownNormalized(snapshot, "display");
|
|
30731
|
+
if (display === "none") return true;
|
|
30732
|
+
}
|
|
30733
|
+
return false;
|
|
30734
|
+
}
|
|
30703
30735
|
function hasEffectivePosition(snapshot) {
|
|
30704
30736
|
const position = readKnownNormalized(snapshot, "position");
|
|
30705
30737
|
if (position === null) return false;
|
|
@@ -30768,6 +30800,7 @@ function readStatefulBaseValueIndex(graph) {
|
|
|
30768
30800
|
}
|
|
30769
30801
|
|
|
30770
30802
|
// src/cross-file/layout/context-classification.ts
|
|
30803
|
+
var WHITESPACE_RE3 = /\s+/;
|
|
30771
30804
|
var TABLE_SEMANTIC_TAGS = /* @__PURE__ */ new Set(["table", "thead", "tbody", "tfoot", "tr", "td", "th"]);
|
|
30772
30805
|
var TABLE_DISPLAY_VALUES = /* @__PURE__ */ new Set([
|
|
30773
30806
|
"table",
|
|
@@ -30806,6 +30839,7 @@ function createAlignmentContextForParent(parent, snapshot) {
|
|
|
30806
30839
|
const classified = classifyKind(evidence);
|
|
30807
30840
|
const contextCertainty = combineCertainty(classified.certainty, axis.certainty);
|
|
30808
30841
|
const certainty = combineCertainty(contextCertainty, inlineDirection.certainty);
|
|
30842
|
+
const baselineRelevance = computeBaselineRelevance(classified.kind, parentAlignItems, parentPlaceItems);
|
|
30809
30843
|
const out = {
|
|
30810
30844
|
kind: classified.kind,
|
|
30811
30845
|
certainty,
|
|
@@ -30821,6 +30855,7 @@ function createAlignmentContextForParent(parent, snapshot) {
|
|
|
30821
30855
|
parentAlignItems,
|
|
30822
30856
|
parentPlaceItems,
|
|
30823
30857
|
hasPositionedOffset: positionedOffset.hasPositionedOffset,
|
|
30858
|
+
baselineRelevance,
|
|
30824
30859
|
evidence
|
|
30825
30860
|
};
|
|
30826
30861
|
return out;
|
|
@@ -31041,6 +31076,63 @@ function combineCertainty(left, right) {
|
|
|
31041
31076
|
if (left === "conditional" || right === "conditional") return "conditional";
|
|
31042
31077
|
return "resolved";
|
|
31043
31078
|
}
|
|
31079
|
+
var FLEX_GRID_GEOMETRIC_ALIGN_ITEMS = /* @__PURE__ */ new Set([
|
|
31080
|
+
"center",
|
|
31081
|
+
"flex-start",
|
|
31082
|
+
"flex-end",
|
|
31083
|
+
"start",
|
|
31084
|
+
"end",
|
|
31085
|
+
"stretch",
|
|
31086
|
+
"self-start",
|
|
31087
|
+
"self-end",
|
|
31088
|
+
"normal"
|
|
31089
|
+
]);
|
|
31090
|
+
function computeBaselineRelevance(kind, parentAlignItems, parentPlaceItems) {
|
|
31091
|
+
if (kind === "flex-cross-axis" || kind === "grid-cross-axis") {
|
|
31092
|
+
const effective = resolveEffectiveAlignItems(parentAlignItems, parentPlaceItems);
|
|
31093
|
+
if (effective === null) return "relevant";
|
|
31094
|
+
return FLEX_GRID_GEOMETRIC_ALIGN_ITEMS.has(effective) ? "irrelevant" : "relevant";
|
|
31095
|
+
}
|
|
31096
|
+
return "relevant";
|
|
31097
|
+
}
|
|
31098
|
+
function resolveEffectiveAlignItems(alignItems, placeItems) {
|
|
31099
|
+
if (alignItems !== null) return alignItems;
|
|
31100
|
+
if (placeItems === null) return null;
|
|
31101
|
+
const firstToken2 = placeItems.split(WHITESPACE_RE3)[0];
|
|
31102
|
+
return firstToken2 ?? null;
|
|
31103
|
+
}
|
|
31104
|
+
var TABLE_CELL_GEOMETRIC_VERTICAL_ALIGN = /* @__PURE__ */ new Set([
|
|
31105
|
+
"middle",
|
|
31106
|
+
"top",
|
|
31107
|
+
"bottom"
|
|
31108
|
+
]);
|
|
31109
|
+
function finalizeTableCellBaselineRelevance(contextByParentNode, cohortVerticalAlignConsensus) {
|
|
31110
|
+
for (const [parent, consensusValue] of cohortVerticalAlignConsensus) {
|
|
31111
|
+
const context = contextByParentNode.get(parent);
|
|
31112
|
+
if (!context) continue;
|
|
31113
|
+
if (context.kind !== "table-cell") continue;
|
|
31114
|
+
if (consensusValue === null) continue;
|
|
31115
|
+
if (!TABLE_CELL_GEOMETRIC_VERTICAL_ALIGN.has(consensusValue)) continue;
|
|
31116
|
+
contextByParentNode.set(parent, {
|
|
31117
|
+
kind: context.kind,
|
|
31118
|
+
certainty: context.certainty,
|
|
31119
|
+
parentSolidFile: context.parentSolidFile,
|
|
31120
|
+
parentElementId: context.parentElementId,
|
|
31121
|
+
parentElementKey: context.parentElementKey,
|
|
31122
|
+
parentTag: context.parentTag,
|
|
31123
|
+
axis: context.axis,
|
|
31124
|
+
axisCertainty: context.axisCertainty,
|
|
31125
|
+
inlineDirection: context.inlineDirection,
|
|
31126
|
+
inlineDirectionCertainty: context.inlineDirectionCertainty,
|
|
31127
|
+
parentDisplay: context.parentDisplay,
|
|
31128
|
+
parentAlignItems: context.parentAlignItems,
|
|
31129
|
+
parentPlaceItems: context.parentPlaceItems,
|
|
31130
|
+
hasPositionedOffset: context.hasPositionedOffset,
|
|
31131
|
+
baselineRelevance: "irrelevant",
|
|
31132
|
+
evidence: context.evidence
|
|
31133
|
+
});
|
|
31134
|
+
}
|
|
31135
|
+
}
|
|
31044
31136
|
|
|
31045
31137
|
// src/cross-file/layout/diagnostics.ts
|
|
31046
31138
|
var FINDING_WEIGHT_BY_KIND = /* @__PURE__ */ new Map([
|
|
@@ -33687,7 +33779,7 @@ var UNCONDITIONAL_GUARD = {
|
|
|
33687
33779
|
conditions: [],
|
|
33688
33780
|
key: "always"
|
|
33689
33781
|
};
|
|
33690
|
-
var
|
|
33782
|
+
var WHITESPACE_RE4 = /\s+/g;
|
|
33691
33783
|
function resolveRuleGuard(rule) {
|
|
33692
33784
|
const conditions = collectRuleConditions(rule);
|
|
33693
33785
|
if (conditions.length === 0) return UNCONDITIONAL_GUARD;
|
|
@@ -33746,7 +33838,7 @@ function buildCondition(kind, query) {
|
|
|
33746
33838
|
}
|
|
33747
33839
|
function normalizeQuery(query) {
|
|
33748
33840
|
if (query === null) return null;
|
|
33749
|
-
const normalized = query.trim().toLowerCase().replace(
|
|
33841
|
+
const normalized = query.trim().toLowerCase().replace(WHITESPACE_RE4, " ");
|
|
33750
33842
|
if (normalized.length === 0) return null;
|
|
33751
33843
|
return normalized;
|
|
33752
33844
|
}
|
|
@@ -34368,12 +34460,7 @@ function resolveInlineReplacedKindDivergence(subjectFingerprint, allFingerprints
|
|
|
34368
34460
|
return alignmentStrengthCalibration.compositionMixedOutlierAmongReplacedStrength;
|
|
34369
34461
|
}
|
|
34370
34462
|
function hasSharedBaselineAlignment(context) {
|
|
34371
|
-
|
|
34372
|
-
if (context.kind === "flex-cross-axis" || context.kind === "grid-cross-axis") {
|
|
34373
|
-
const alignItems = context.parentAlignItems;
|
|
34374
|
-
return alignItems === null || alignItems === "baseline";
|
|
34375
|
-
}
|
|
34376
|
-
return false;
|
|
34463
|
+
return context.baselineRelevance === "relevant";
|
|
34377
34464
|
}
|
|
34378
34465
|
function resolveMajorityClassification(allFingerprints) {
|
|
34379
34466
|
const countByClassification = /* @__PURE__ */ new Map();
|
|
@@ -34527,6 +34614,7 @@ function estimateBlockOffsetWithDeclaredFromSources(axis, position, readNumeric)
|
|
|
34527
34614
|
// src/cross-file/layout/cohort-index.ts
|
|
34528
34615
|
function buildCohortIndex(input) {
|
|
34529
34616
|
const statsByParentNode = /* @__PURE__ */ new Map();
|
|
34617
|
+
const verticalAlignConsensusByParent = /* @__PURE__ */ new Map();
|
|
34530
34618
|
const profileBuffers = createCohortProfileBuffers();
|
|
34531
34619
|
let conditionalSignals = 0;
|
|
34532
34620
|
let totalSignals = 0;
|
|
@@ -34601,12 +34689,14 @@ function buildCohortIndex(input) {
|
|
|
34601
34689
|
subjectsByElementKey,
|
|
34602
34690
|
excludedElementKeys: cohortMetricsResult.excludedElementKeys
|
|
34603
34691
|
});
|
|
34692
|
+
verticalAlignConsensusByParent.set(parent, resolveVerticalAlignConsensus(signalIndex.verticalAlign));
|
|
34604
34693
|
conditionalSignals += counts.conditional;
|
|
34605
34694
|
totalSignals += counts.total;
|
|
34606
34695
|
if (!profile.unimodal) unimodalFalseCount++;
|
|
34607
34696
|
}
|
|
34608
34697
|
return {
|
|
34609
34698
|
statsByParentNode,
|
|
34699
|
+
verticalAlignConsensusByParent,
|
|
34610
34700
|
conditionalSignals,
|
|
34611
34701
|
totalSignals,
|
|
34612
34702
|
unimodalFalseCount,
|
|
@@ -34626,6 +34716,10 @@ function collectCohortMetrics(input) {
|
|
|
34626
34716
|
const node = input.children[i];
|
|
34627
34717
|
if (!node) continue;
|
|
34628
34718
|
const childSnapshot = input.snapshotByElementNode.get(node);
|
|
34719
|
+
if (isLayoutHidden(node, input.snapshotByElementNode)) {
|
|
34720
|
+
excluded.add(node.key);
|
|
34721
|
+
continue;
|
|
34722
|
+
}
|
|
34629
34723
|
if (childSnapshot && isUnconditionallyOutOfFlow(childSnapshot)) {
|
|
34630
34724
|
excluded.add(node.key);
|
|
34631
34725
|
continue;
|
|
@@ -35425,6 +35519,13 @@ function swap(values, left, right) {
|
|
|
35425
35519
|
values[left] = rightValue;
|
|
35426
35520
|
values[right] = leftValue;
|
|
35427
35521
|
}
|
|
35522
|
+
function resolveVerticalAlignConsensus(aggregate) {
|
|
35523
|
+
if (aggregate.comparableCount === 0) return null;
|
|
35524
|
+
if (aggregate.countsByValue.size !== 1) return null;
|
|
35525
|
+
const firstEntry = aggregate.countsByValue.entries().next();
|
|
35526
|
+
if (firstEntry.done) return null;
|
|
35527
|
+
return firstEntry.value[0];
|
|
35528
|
+
}
|
|
35428
35529
|
|
|
35429
35530
|
// src/cross-file/layout/measurement-node.ts
|
|
35430
35531
|
var EMPTY_NODE_LIST = [];
|
|
@@ -35512,6 +35613,7 @@ function resolveMeasurementCandidates(root, childrenByParentNode, snapshotByElem
|
|
|
35512
35613
|
for (let i = 0; i < children.length; i++) {
|
|
35513
35614
|
const child = children[i];
|
|
35514
35615
|
if (!child) continue;
|
|
35616
|
+
if (isLayoutHidden(child, snapshotByElementNode)) continue;
|
|
35515
35617
|
if (firstControlOrReplacedDescendant === null && (child.isControl || child.isReplaced)) {
|
|
35516
35618
|
firstControlOrReplacedDescendant = child;
|
|
35517
35619
|
}
|
|
@@ -37026,6 +37128,7 @@ function buildLayoutGraph(solids, css, logger = noopLogger) {
|
|
|
37026
37128
|
snapshotByElementNode,
|
|
37027
37129
|
snapshotHotSignalsByElementKey: factIndex.snapshotHotSignalsByElementKey
|
|
37028
37130
|
});
|
|
37131
|
+
finalizeTableCellBaselineRelevance(contextByParentNode, cohortIndex.verticalAlignConsensusByParent);
|
|
37029
37132
|
perf.conditionalSignals = cohortIndex.conditionalSignals;
|
|
37030
37133
|
perf.totalSignals = cohortIndex.totalSignals;
|
|
37031
37134
|
perf.cohortUnimodalFalse = cohortIndex.unimodalFalseCount;
|
|
@@ -37366,6 +37469,12 @@ function collectAlignmentCases(context) {
|
|
|
37366
37469
|
if (!subjectStats) {
|
|
37367
37470
|
throw new Error(`missing subject cohort stats for ${measurementNode.key}`);
|
|
37368
37471
|
}
|
|
37472
|
+
const effectiveAlignmentContext = resolveEffectiveAlignmentContext(
|
|
37473
|
+
alignmentContext,
|
|
37474
|
+
child,
|
|
37475
|
+
measurementNode,
|
|
37476
|
+
context.layout.contextByParentNode
|
|
37477
|
+
);
|
|
37369
37478
|
const subjectDeclaredOffsetDeviation = computeDeviation(
|
|
37370
37479
|
subjectStats.declaredOffset,
|
|
37371
37480
|
subjectStats.baselineProfile.medianDeclaredOffsetPx
|
|
@@ -37381,7 +37490,7 @@ function collectAlignmentCases(context) {
|
|
|
37381
37490
|
out.push(
|
|
37382
37491
|
buildAlignmentCase(
|
|
37383
37492
|
parent,
|
|
37384
|
-
|
|
37493
|
+
effectiveAlignmentContext,
|
|
37385
37494
|
cohortStats.profile,
|
|
37386
37495
|
subjectStats.signals,
|
|
37387
37496
|
subjectStats.identifiability,
|
|
@@ -37530,6 +37639,31 @@ function collectCohortContentCompositions(cohortStats, children, measurementNode
|
|
|
37530
37639
|
}
|
|
37531
37640
|
return out;
|
|
37532
37641
|
}
|
|
37642
|
+
function resolveEffectiveAlignmentContext(parentContext, child, measurementNode, contextByParentNode) {
|
|
37643
|
+
if (child === measurementNode) return parentContext;
|
|
37644
|
+
if (parentContext.baselineRelevance === "irrelevant") return parentContext;
|
|
37645
|
+
const childContext = contextByParentNode.get(child);
|
|
37646
|
+
if (!childContext) return parentContext;
|
|
37647
|
+
if (childContext.baselineRelevance !== "irrelevant") return parentContext;
|
|
37648
|
+
return {
|
|
37649
|
+
kind: parentContext.kind,
|
|
37650
|
+
certainty: parentContext.certainty,
|
|
37651
|
+
parentSolidFile: parentContext.parentSolidFile,
|
|
37652
|
+
parentElementId: parentContext.parentElementId,
|
|
37653
|
+
parentElementKey: parentContext.parentElementKey,
|
|
37654
|
+
parentTag: parentContext.parentTag,
|
|
37655
|
+
axis: parentContext.axis,
|
|
37656
|
+
axisCertainty: parentContext.axisCertainty,
|
|
37657
|
+
inlineDirection: parentContext.inlineDirection,
|
|
37658
|
+
inlineDirectionCertainty: parentContext.inlineDirectionCertainty,
|
|
37659
|
+
parentDisplay: parentContext.parentDisplay,
|
|
37660
|
+
parentAlignItems: parentContext.parentAlignItems,
|
|
37661
|
+
parentPlaceItems: parentContext.parentPlaceItems,
|
|
37662
|
+
hasPositionedOffset: parentContext.hasPositionedOffset,
|
|
37663
|
+
baselineRelevance: "irrelevant",
|
|
37664
|
+
evidence: parentContext.evidence
|
|
37665
|
+
};
|
|
37666
|
+
}
|
|
37533
37667
|
function compareAlignmentCaseOrder(left, right) {
|
|
37534
37668
|
if (left.subject.solidFile < right.subject.solidFile) return -1;
|
|
37535
37669
|
if (left.subject.solidFile > right.subject.solidFile) return 1;
|
|
@@ -37562,10 +37696,11 @@ function buildConsistencyEvidence(input) {
|
|
|
37562
37696
|
input.cohortProfile.lineHeightDispersionPx,
|
|
37563
37697
|
input.cohortProfile.medianLineHeightPx
|
|
37564
37698
|
);
|
|
37565
|
-
const
|
|
37566
|
-
const
|
|
37567
|
-
const
|
|
37568
|
-
const
|
|
37699
|
+
const baselinesIrrelevant = input.context.baselineRelevance === "irrelevant";
|
|
37700
|
+
const baselineStrength = baselinesIrrelevant ? ZERO_STRENGTH : resolveBaselineStrength(input, lineHeight);
|
|
37701
|
+
const contextStrength = baselinesIrrelevant ? ZERO_STRENGTH : resolveContextStrength(input, lineHeight);
|
|
37702
|
+
const replacedStrength = baselinesIrrelevant ? ZERO_STRENGTH : resolveReplacedControlStrength(input, lineHeight);
|
|
37703
|
+
const compositionStrength = baselinesIrrelevant ? ZERO_STRENGTH : resolveContentCompositionStrength(input);
|
|
37569
37704
|
const contextCertaintyPenalty = resolveContextCertaintyPenalty(input);
|
|
37570
37705
|
const provenance = input.cohortProvenance;
|
|
37571
37706
|
const atoms = buildEvidenceAtoms(
|
|
@@ -37861,6 +37996,7 @@ function toNegativeContribution(strength, maxPenalty, valueKind) {
|
|
|
37861
37996
|
max: 0
|
|
37862
37997
|
};
|
|
37863
37998
|
}
|
|
37999
|
+
var ZERO_STRENGTH = { strength: 0, kind: "exact" };
|
|
37864
38000
|
|
|
37865
38001
|
// src/cross-file/layout/consistency-policy.ts
|
|
37866
38002
|
function applyConsistencyPolicy(input) {
|
|
@@ -38080,6 +38216,7 @@ function runLayoutDetector(context, detector) {
|
|
|
38080
38216
|
const cases = detector.collect(context);
|
|
38081
38217
|
const startedAt = performance.now();
|
|
38082
38218
|
const out = [];
|
|
38219
|
+
const log = context.logger;
|
|
38083
38220
|
for (let i = 0; i < cases.length; i++) {
|
|
38084
38221
|
const current = cases[i];
|
|
38085
38222
|
if (!current) continue;
|
|
@@ -38092,10 +38229,20 @@ function runLayoutDetector(context, detector) {
|
|
|
38092
38229
|
result.evidence.posteriorLower,
|
|
38093
38230
|
result.evidence.posteriorUpper
|
|
38094
38231
|
);
|
|
38232
|
+
if (log.enabled) {
|
|
38233
|
+
log.debug(
|
|
38234
|
+
`[${detector.id}] accept case=${i} severity=${result.evidence.severity.toFixed(2)} confidence=${result.evidence.confidence.toFixed(2)} posterior=[${result.evidence.posteriorLower.toFixed(3)},${result.evidence.posteriorUpper.toFixed(3)}] evidenceMass=${result.evidence.evidenceMass.toFixed(3)} context=${result.evidence.contextKind} offset=${result.evidence.estimatedOffsetPx?.toFixed(2) ?? "null"} topFactors=[${result.evidence.topFactors.join(",")}] causes=[${result.evidence.causes.join("; ")}]`
|
|
38235
|
+
);
|
|
38236
|
+
}
|
|
38095
38237
|
out.push({ caseData: current, evidence: result.evidence });
|
|
38096
38238
|
continue;
|
|
38097
38239
|
}
|
|
38098
38240
|
recordPolicyMetrics(context, result.evidenceMass, result.posteriorLower, result.posteriorUpper);
|
|
38241
|
+
if (log.enabled) {
|
|
38242
|
+
log.debug(
|
|
38243
|
+
`[${detector.id}] reject case=${i} reason=${result.reason} detail=${result.detail ?? "none"} posterior=[${result.posteriorLower.toFixed(3)},${result.posteriorUpper.toFixed(3)}] evidenceMass=${result.evidenceMass.toFixed(3)}`
|
|
38244
|
+
);
|
|
38245
|
+
}
|
|
38099
38246
|
if (result.reason === "low-evidence") {
|
|
38100
38247
|
context.layout.perf.casesRejectedLowEvidence++;
|
|
38101
38248
|
continue;
|
|
@@ -38782,33 +38929,73 @@ var cssLayoutSiblingAlignmentOutlier = defineCrossRule({
|
|
|
38782
38929
|
category: "css-layout"
|
|
38783
38930
|
},
|
|
38784
38931
|
check(context, emit) {
|
|
38932
|
+
const log = context.logger;
|
|
38785
38933
|
const detections = runLayoutDetector(context, siblingAlignmentDetector);
|
|
38786
38934
|
const uniqueDetections = dedupeDetectionsBySubject(detections);
|
|
38935
|
+
if (log.enabled) {
|
|
38936
|
+
log.debug(
|
|
38937
|
+
`[sibling-alignment] raw=${detections.length} deduped=${uniqueDetections.length}`
|
|
38938
|
+
);
|
|
38939
|
+
}
|
|
38787
38940
|
for (let i = 0; i < uniqueDetections.length; i++) {
|
|
38788
38941
|
const detection = uniqueDetections[i];
|
|
38789
38942
|
if (!detection) continue;
|
|
38790
|
-
|
|
38943
|
+
const subjectTag = detection.caseData.subject.tag ?? "element";
|
|
38944
|
+
const parentTag = detection.caseData.cohort.parentTag ?? "container";
|
|
38945
|
+
const subjectFile = detection.caseData.subject.solidFile;
|
|
38946
|
+
const subjectId = detection.caseData.subject.elementId;
|
|
38947
|
+
const logPrefix = `[sibling-alignment] <${subjectTag}> in <${parentTag}> (${subjectFile}#${subjectId})`;
|
|
38948
|
+
if (detection.evidence.confidence < MIN_CONFIDENCE_THRESHOLD) {
|
|
38949
|
+
if (log.enabled) {
|
|
38950
|
+
log.debug(
|
|
38951
|
+
`${logPrefix} SKIP: confidence=${detection.evidence.confidence.toFixed(2)} < threshold=${MIN_CONFIDENCE_THRESHOLD}`
|
|
38952
|
+
);
|
|
38953
|
+
}
|
|
38954
|
+
continue;
|
|
38955
|
+
}
|
|
38791
38956
|
const estimatedOffset = detection.evidence.estimatedOffsetPx;
|
|
38792
|
-
if (estimatedOffset !== null && Math.abs(estimatedOffset) < MIN_OFFSET_PX_THRESHOLD && !hasNonOffsetPrimaryEvidence(detection.evidence.topFactors))
|
|
38957
|
+
if (estimatedOffset !== null && Math.abs(estimatedOffset) < MIN_OFFSET_PX_THRESHOLD && !hasNonOffsetPrimaryEvidence(detection.evidence.topFactors)) {
|
|
38958
|
+
if (log.enabled) {
|
|
38959
|
+
log.debug(
|
|
38960
|
+
`${logPrefix} SKIP: offset=${estimatedOffset.toFixed(2)}px < ${MIN_OFFSET_PX_THRESHOLD}px (no non-offset primary evidence, topFactors=[${detection.evidence.topFactors.join(",")}])`
|
|
38961
|
+
);
|
|
38962
|
+
}
|
|
38963
|
+
continue;
|
|
38964
|
+
}
|
|
38793
38965
|
if (isInsideOutOfFlowAncestor(
|
|
38794
38966
|
context.layout,
|
|
38795
38967
|
detection.caseData.cohort.parentElementKey,
|
|
38796
38968
|
detection.caseData.subject.solidFile
|
|
38797
|
-
))
|
|
38969
|
+
)) {
|
|
38970
|
+
if (log.enabled) {
|
|
38971
|
+
log.debug(`${logPrefix} SKIP: out-of-flow ancestor`);
|
|
38972
|
+
}
|
|
38973
|
+
continue;
|
|
38974
|
+
}
|
|
38798
38975
|
const subjectRef = readNodeRefById(
|
|
38799
38976
|
context.layout,
|
|
38800
38977
|
detection.caseData.subject.solidFile,
|
|
38801
38978
|
detection.caseData.subject.elementId
|
|
38802
38979
|
);
|
|
38803
|
-
if (!subjectRef)
|
|
38804
|
-
|
|
38805
|
-
|
|
38980
|
+
if (!subjectRef) {
|
|
38981
|
+
if (log.enabled) {
|
|
38982
|
+
log.debug(`${logPrefix} SKIP: no node ref`);
|
|
38983
|
+
}
|
|
38984
|
+
continue;
|
|
38985
|
+
}
|
|
38986
|
+
const subject = subjectTag;
|
|
38987
|
+
const parent = parentTag;
|
|
38806
38988
|
const severity = formatFixed(detection.evidence.severity);
|
|
38807
38989
|
const confidence = formatFixed(detection.evidence.confidence);
|
|
38808
38990
|
const offset = detection.evidence.estimatedOffsetPx;
|
|
38809
38991
|
const hasOffset = offset !== null && Math.abs(offset) > 0.25;
|
|
38810
38992
|
const offsetClause = hasOffset ? `, estimated offset ${formatFixed(offset)}px` : "";
|
|
38811
38993
|
const causes = detection.evidence.causes.length === 0 ? "alignment signals indicate an outlier" : detection.evidence.causes.join("; ");
|
|
38994
|
+
if (log.enabled) {
|
|
38995
|
+
log.debug(
|
|
38996
|
+
`${logPrefix} EMIT: severity=${severity} confidence=${confidence} offset=${offset?.toFixed(2) ?? "null"} posterior=[${detection.evidence.posteriorLower.toFixed(3)},${detection.evidence.posteriorUpper.toFixed(3)}] evidenceMass=${detection.evidence.evidenceMass.toFixed(3)} topFactors=[${detection.evidence.topFactors.join(",")}] causes=[${causes}]`
|
|
38997
|
+
);
|
|
38998
|
+
}
|
|
38812
38999
|
emit(
|
|
38813
39000
|
createDiagnostic(
|
|
38814
39001
|
subjectRef.solid.file,
|
|
@@ -40217,7 +40404,8 @@ var CrossFilePlugin = {
|
|
|
40217
40404
|
const context = {
|
|
40218
40405
|
solids: solidGraphs,
|
|
40219
40406
|
css: cssGraph,
|
|
40220
|
-
layout: buildLayoutGraph(solidGraphs, cssGraph)
|
|
40407
|
+
layout: buildLayoutGraph(solidGraphs, cssGraph),
|
|
40408
|
+
logger: noopLogger
|
|
40221
40409
|
};
|
|
40222
40410
|
runCrossFileRules(context, emit);
|
|
40223
40411
|
}
|