@drskillissue/ganko 0.1.19 → 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-LGHIMW4P.js → chunk-PX2XCAZW.js} +170 -19
- package/dist/{chunk-LGHIMW4P.js.map → chunk-PX2XCAZW.js.map} +1 -1
- package/dist/eslint-plugin.cjs +173 -21
- 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 +171 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +23 -1
- package/dist/index.d.ts +23 -1
- package/dist/index.js +1 -1
- package/package.json +1 -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
|
@@ -30800,6 +30800,7 @@ function readStatefulBaseValueIndex(graph) {
|
|
|
30800
30800
|
}
|
|
30801
30801
|
|
|
30802
30802
|
// src/cross-file/layout/context-classification.ts
|
|
30803
|
+
var WHITESPACE_RE3 = /\s+/;
|
|
30803
30804
|
var TABLE_SEMANTIC_TAGS = /* @__PURE__ */ new Set(["table", "thead", "tbody", "tfoot", "tr", "td", "th"]);
|
|
30804
30805
|
var TABLE_DISPLAY_VALUES = /* @__PURE__ */ new Set([
|
|
30805
30806
|
"table",
|
|
@@ -30838,6 +30839,7 @@ function createAlignmentContextForParent(parent, snapshot) {
|
|
|
30838
30839
|
const classified = classifyKind(evidence);
|
|
30839
30840
|
const contextCertainty = combineCertainty(classified.certainty, axis.certainty);
|
|
30840
30841
|
const certainty = combineCertainty(contextCertainty, inlineDirection.certainty);
|
|
30842
|
+
const baselineRelevance = computeBaselineRelevance(classified.kind, parentAlignItems, parentPlaceItems);
|
|
30841
30843
|
const out = {
|
|
30842
30844
|
kind: classified.kind,
|
|
30843
30845
|
certainty,
|
|
@@ -30853,6 +30855,7 @@ function createAlignmentContextForParent(parent, snapshot) {
|
|
|
30853
30855
|
parentAlignItems,
|
|
30854
30856
|
parentPlaceItems,
|
|
30855
30857
|
hasPositionedOffset: positionedOffset.hasPositionedOffset,
|
|
30858
|
+
baselineRelevance,
|
|
30856
30859
|
evidence
|
|
30857
30860
|
};
|
|
30858
30861
|
return out;
|
|
@@ -31073,6 +31076,63 @@ function combineCertainty(left, right) {
|
|
|
31073
31076
|
if (left === "conditional" || right === "conditional") return "conditional";
|
|
31074
31077
|
return "resolved";
|
|
31075
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
|
+
}
|
|
31076
31136
|
|
|
31077
31137
|
// src/cross-file/layout/diagnostics.ts
|
|
31078
31138
|
var FINDING_WEIGHT_BY_KIND = /* @__PURE__ */ new Map([
|
|
@@ -33719,7 +33779,7 @@ var UNCONDITIONAL_GUARD = {
|
|
|
33719
33779
|
conditions: [],
|
|
33720
33780
|
key: "always"
|
|
33721
33781
|
};
|
|
33722
|
-
var
|
|
33782
|
+
var WHITESPACE_RE4 = /\s+/g;
|
|
33723
33783
|
function resolveRuleGuard(rule) {
|
|
33724
33784
|
const conditions = collectRuleConditions(rule);
|
|
33725
33785
|
if (conditions.length === 0) return UNCONDITIONAL_GUARD;
|
|
@@ -33778,7 +33838,7 @@ function buildCondition(kind, query) {
|
|
|
33778
33838
|
}
|
|
33779
33839
|
function normalizeQuery(query) {
|
|
33780
33840
|
if (query === null) return null;
|
|
33781
|
-
const normalized = query.trim().toLowerCase().replace(
|
|
33841
|
+
const normalized = query.trim().toLowerCase().replace(WHITESPACE_RE4, " ");
|
|
33782
33842
|
if (normalized.length === 0) return null;
|
|
33783
33843
|
return normalized;
|
|
33784
33844
|
}
|
|
@@ -34400,12 +34460,7 @@ function resolveInlineReplacedKindDivergence(subjectFingerprint, allFingerprints
|
|
|
34400
34460
|
return alignmentStrengthCalibration.compositionMixedOutlierAmongReplacedStrength;
|
|
34401
34461
|
}
|
|
34402
34462
|
function hasSharedBaselineAlignment(context) {
|
|
34403
|
-
|
|
34404
|
-
if (context.kind === "flex-cross-axis" || context.kind === "grid-cross-axis") {
|
|
34405
|
-
const alignItems = context.parentAlignItems;
|
|
34406
|
-
return alignItems === null || alignItems === "baseline";
|
|
34407
|
-
}
|
|
34408
|
-
return false;
|
|
34463
|
+
return context.baselineRelevance === "relevant";
|
|
34409
34464
|
}
|
|
34410
34465
|
function resolveMajorityClassification(allFingerprints) {
|
|
34411
34466
|
const countByClassification = /* @__PURE__ */ new Map();
|
|
@@ -34559,6 +34614,7 @@ function estimateBlockOffsetWithDeclaredFromSources(axis, position, readNumeric)
|
|
|
34559
34614
|
// src/cross-file/layout/cohort-index.ts
|
|
34560
34615
|
function buildCohortIndex(input) {
|
|
34561
34616
|
const statsByParentNode = /* @__PURE__ */ new Map();
|
|
34617
|
+
const verticalAlignConsensusByParent = /* @__PURE__ */ new Map();
|
|
34562
34618
|
const profileBuffers = createCohortProfileBuffers();
|
|
34563
34619
|
let conditionalSignals = 0;
|
|
34564
34620
|
let totalSignals = 0;
|
|
@@ -34633,12 +34689,14 @@ function buildCohortIndex(input) {
|
|
|
34633
34689
|
subjectsByElementKey,
|
|
34634
34690
|
excludedElementKeys: cohortMetricsResult.excludedElementKeys
|
|
34635
34691
|
});
|
|
34692
|
+
verticalAlignConsensusByParent.set(parent, resolveVerticalAlignConsensus(signalIndex.verticalAlign));
|
|
34636
34693
|
conditionalSignals += counts.conditional;
|
|
34637
34694
|
totalSignals += counts.total;
|
|
34638
34695
|
if (!profile.unimodal) unimodalFalseCount++;
|
|
34639
34696
|
}
|
|
34640
34697
|
return {
|
|
34641
34698
|
statsByParentNode,
|
|
34699
|
+
verticalAlignConsensusByParent,
|
|
34642
34700
|
conditionalSignals,
|
|
34643
34701
|
totalSignals,
|
|
34644
34702
|
unimodalFalseCount,
|
|
@@ -35461,6 +35519,13 @@ function swap(values, left, right) {
|
|
|
35461
35519
|
values[left] = rightValue;
|
|
35462
35520
|
values[right] = leftValue;
|
|
35463
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
|
+
}
|
|
35464
35529
|
|
|
35465
35530
|
// src/cross-file/layout/measurement-node.ts
|
|
35466
35531
|
var EMPTY_NODE_LIST = [];
|
|
@@ -37063,6 +37128,7 @@ function buildLayoutGraph(solids, css, logger = noopLogger) {
|
|
|
37063
37128
|
snapshotByElementNode,
|
|
37064
37129
|
snapshotHotSignalsByElementKey: factIndex.snapshotHotSignalsByElementKey
|
|
37065
37130
|
});
|
|
37131
|
+
finalizeTableCellBaselineRelevance(contextByParentNode, cohortIndex.verticalAlignConsensusByParent);
|
|
37066
37132
|
perf.conditionalSignals = cohortIndex.conditionalSignals;
|
|
37067
37133
|
perf.totalSignals = cohortIndex.totalSignals;
|
|
37068
37134
|
perf.cohortUnimodalFalse = cohortIndex.unimodalFalseCount;
|
|
@@ -37403,6 +37469,12 @@ function collectAlignmentCases(context) {
|
|
|
37403
37469
|
if (!subjectStats) {
|
|
37404
37470
|
throw new Error(`missing subject cohort stats for ${measurementNode.key}`);
|
|
37405
37471
|
}
|
|
37472
|
+
const effectiveAlignmentContext = resolveEffectiveAlignmentContext(
|
|
37473
|
+
alignmentContext,
|
|
37474
|
+
child,
|
|
37475
|
+
measurementNode,
|
|
37476
|
+
context.layout.contextByParentNode
|
|
37477
|
+
);
|
|
37406
37478
|
const subjectDeclaredOffsetDeviation = computeDeviation(
|
|
37407
37479
|
subjectStats.declaredOffset,
|
|
37408
37480
|
subjectStats.baselineProfile.medianDeclaredOffsetPx
|
|
@@ -37418,7 +37490,7 @@ function collectAlignmentCases(context) {
|
|
|
37418
37490
|
out.push(
|
|
37419
37491
|
buildAlignmentCase(
|
|
37420
37492
|
parent,
|
|
37421
|
-
|
|
37493
|
+
effectiveAlignmentContext,
|
|
37422
37494
|
cohortStats.profile,
|
|
37423
37495
|
subjectStats.signals,
|
|
37424
37496
|
subjectStats.identifiability,
|
|
@@ -37567,6 +37639,31 @@ function collectCohortContentCompositions(cohortStats, children, measurementNode
|
|
|
37567
37639
|
}
|
|
37568
37640
|
return out;
|
|
37569
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
|
+
}
|
|
37570
37667
|
function compareAlignmentCaseOrder(left, right) {
|
|
37571
37668
|
if (left.subject.solidFile < right.subject.solidFile) return -1;
|
|
37572
37669
|
if (left.subject.solidFile > right.subject.solidFile) return 1;
|
|
@@ -37599,10 +37696,11 @@ function buildConsistencyEvidence(input) {
|
|
|
37599
37696
|
input.cohortProfile.lineHeightDispersionPx,
|
|
37600
37697
|
input.cohortProfile.medianLineHeightPx
|
|
37601
37698
|
);
|
|
37602
|
-
const
|
|
37603
|
-
const
|
|
37604
|
-
const
|
|
37605
|
-
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);
|
|
37606
37704
|
const contextCertaintyPenalty = resolveContextCertaintyPenalty(input);
|
|
37607
37705
|
const provenance = input.cohortProvenance;
|
|
37608
37706
|
const atoms = buildEvidenceAtoms(
|
|
@@ -37898,6 +37996,7 @@ function toNegativeContribution(strength, maxPenalty, valueKind) {
|
|
|
37898
37996
|
max: 0
|
|
37899
37997
|
};
|
|
37900
37998
|
}
|
|
37999
|
+
var ZERO_STRENGTH = { strength: 0, kind: "exact" };
|
|
37901
38000
|
|
|
37902
38001
|
// src/cross-file/layout/consistency-policy.ts
|
|
37903
38002
|
function applyConsistencyPolicy(input) {
|
|
@@ -38117,6 +38216,7 @@ function runLayoutDetector(context, detector) {
|
|
|
38117
38216
|
const cases = detector.collect(context);
|
|
38118
38217
|
const startedAt = performance.now();
|
|
38119
38218
|
const out = [];
|
|
38219
|
+
const log = context.logger;
|
|
38120
38220
|
for (let i = 0; i < cases.length; i++) {
|
|
38121
38221
|
const current = cases[i];
|
|
38122
38222
|
if (!current) continue;
|
|
@@ -38129,10 +38229,20 @@ function runLayoutDetector(context, detector) {
|
|
|
38129
38229
|
result.evidence.posteriorLower,
|
|
38130
38230
|
result.evidence.posteriorUpper
|
|
38131
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
|
+
}
|
|
38132
38237
|
out.push({ caseData: current, evidence: result.evidence });
|
|
38133
38238
|
continue;
|
|
38134
38239
|
}
|
|
38135
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
|
+
}
|
|
38136
38246
|
if (result.reason === "low-evidence") {
|
|
38137
38247
|
context.layout.perf.casesRejectedLowEvidence++;
|
|
38138
38248
|
continue;
|
|
@@ -38819,33 +38929,73 @@ var cssLayoutSiblingAlignmentOutlier = defineCrossRule({
|
|
|
38819
38929
|
category: "css-layout"
|
|
38820
38930
|
},
|
|
38821
38931
|
check(context, emit) {
|
|
38932
|
+
const log = context.logger;
|
|
38822
38933
|
const detections = runLayoutDetector(context, siblingAlignmentDetector);
|
|
38823
38934
|
const uniqueDetections = dedupeDetectionsBySubject(detections);
|
|
38935
|
+
if (log.enabled) {
|
|
38936
|
+
log.debug(
|
|
38937
|
+
`[sibling-alignment] raw=${detections.length} deduped=${uniqueDetections.length}`
|
|
38938
|
+
);
|
|
38939
|
+
}
|
|
38824
38940
|
for (let i = 0; i < uniqueDetections.length; i++) {
|
|
38825
38941
|
const detection = uniqueDetections[i];
|
|
38826
38942
|
if (!detection) continue;
|
|
38827
|
-
|
|
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
|
+
}
|
|
38828
38956
|
const estimatedOffset = detection.evidence.estimatedOffsetPx;
|
|
38829
|
-
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
|
+
}
|
|
38830
38965
|
if (isInsideOutOfFlowAncestor(
|
|
38831
38966
|
context.layout,
|
|
38832
38967
|
detection.caseData.cohort.parentElementKey,
|
|
38833
38968
|
detection.caseData.subject.solidFile
|
|
38834
|
-
))
|
|
38969
|
+
)) {
|
|
38970
|
+
if (log.enabled) {
|
|
38971
|
+
log.debug(`${logPrefix} SKIP: out-of-flow ancestor`);
|
|
38972
|
+
}
|
|
38973
|
+
continue;
|
|
38974
|
+
}
|
|
38835
38975
|
const subjectRef = readNodeRefById(
|
|
38836
38976
|
context.layout,
|
|
38837
38977
|
detection.caseData.subject.solidFile,
|
|
38838
38978
|
detection.caseData.subject.elementId
|
|
38839
38979
|
);
|
|
38840
|
-
if (!subjectRef)
|
|
38841
|
-
|
|
38842
|
-
|
|
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;
|
|
38843
38988
|
const severity = formatFixed(detection.evidence.severity);
|
|
38844
38989
|
const confidence = formatFixed(detection.evidence.confidence);
|
|
38845
38990
|
const offset = detection.evidence.estimatedOffsetPx;
|
|
38846
38991
|
const hasOffset = offset !== null && Math.abs(offset) > 0.25;
|
|
38847
38992
|
const offsetClause = hasOffset ? `, estimated offset ${formatFixed(offset)}px` : "";
|
|
38848
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
|
+
}
|
|
38849
38999
|
emit(
|
|
38850
39000
|
createDiagnostic(
|
|
38851
39001
|
subjectRef.solid.file,
|
|
@@ -40254,7 +40404,8 @@ var CrossFilePlugin = {
|
|
|
40254
40404
|
const context = {
|
|
40255
40405
|
solids: solidGraphs,
|
|
40256
40406
|
css: cssGraph,
|
|
40257
|
-
layout: buildLayoutGraph(solidGraphs, cssGraph)
|
|
40407
|
+
layout: buildLayoutGraph(solidGraphs, cssGraph),
|
|
40408
|
+
logger: noopLogger
|
|
40258
40409
|
};
|
|
40259
40410
|
runCrossFileRules(context, emit);
|
|
40260
40411
|
}
|