@nfq/eslint-config 4.0.0-beta.22 → 4.0.0-beta.23
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/esm/rules/custom/styled-components-order.js +21 -3
- package/dist/esm/rules/custom/styled-components-order.js.map +1 -1
- package/dist/esm/rules/custom/utils/styled-components-order-utils.js +26 -1
- package/dist/esm/rules/custom/utils/styled-components-order-utils.js.map +1 -1
- package/dist/index.js +45 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/types/rules/custom/utils/styled-components-order-utils.d.ts +18 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ESLintUtils } from '@typescript-eslint/utils';
|
|
2
|
-
import { compareBy, unwrapExpression, isStyledBase, getDependencyNames, unwrapTypeStatement } from './utils/styled-components-order-utils.js';
|
|
2
|
+
import { compareBy, unwrapExpression, isStyledBase, getTagDependencies, getDependencyNames, unwrapTypeStatement } from './utils/styled-components-order-utils.js';
|
|
3
3
|
|
|
4
4
|
const createRule = ESLintUtils.RuleCreator(name => `https://github.com/nfqde/eslint-config-nfq/blob/master/docs/rules/${name}.md`);
|
|
5
5
|
const styledComponentsOrder = createRule({
|
|
@@ -136,7 +136,7 @@ const styledComponentsOrder = createRule({
|
|
|
136
136
|
}
|
|
137
137
|
definitions.set(name, {
|
|
138
138
|
canFix: statementInfo.canFix,
|
|
139
|
-
dependencies: getDependencyNames(node.init.quasi),
|
|
139
|
+
dependencies: [...getTagDependencies(node.init.tag), ...getDependencyNames(node.init.quasi)],
|
|
140
140
|
groupFirst: statementInfo.groupFirst,
|
|
141
141
|
groupLast: statementInfo.groupLast,
|
|
142
142
|
id: node.id,
|
|
@@ -232,6 +232,24 @@ const styledComponentsOrder = createRule({
|
|
|
232
232
|
}
|
|
233
233
|
});
|
|
234
234
|
});
|
|
235
|
+
const transitiveDeps = new Map();
|
|
236
|
+
const getTransitiveDeps = name => {
|
|
237
|
+
if (transitiveDeps.has(name)) {
|
|
238
|
+
return transitiveDeps.get(name);
|
|
239
|
+
}
|
|
240
|
+
const result = new Set();
|
|
241
|
+
transitiveDeps.set(name, result);
|
|
242
|
+
const direct = dependencyMap.get(name);
|
|
243
|
+
if (direct) {
|
|
244
|
+
for (const dep of direct) {
|
|
245
|
+
result.add(dep);
|
|
246
|
+
for (const transitive of getTransitiveDeps(dep)) {
|
|
247
|
+
result.add(transitive);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
return result;
|
|
252
|
+
};
|
|
235
253
|
const earlierRendered = [];
|
|
236
254
|
let maxDefIndex = -1;
|
|
237
255
|
let maxDefName = '';
|
|
@@ -241,7 +259,7 @@ const styledComponentsOrder = createRule({
|
|
|
241
259
|
return;
|
|
242
260
|
}
|
|
243
261
|
if (currentIndex < maxDefIndex) {
|
|
244
|
-
const isDependencyForEarlier = earlierRendered.some(earlier =>
|
|
262
|
+
const isDependencyForEarlier = earlierRendered.some(earlier => getTransitiveDeps(earlier).has(name));
|
|
245
263
|
if (!isDependencyForEarlier) {
|
|
246
264
|
const definition = definitions.get(name);
|
|
247
265
|
if (definition) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"styled-components-order.js","sources":["../../../../src/rules/custom/styled-components-order.ts"],"sourcesContent":["import {ESLintUtils} from '@typescript-eslint/utils';\n\nimport {\n compareBy,\n getDependencyNames,\n isStyledBase,\n unwrapExpression,\n unwrapTypeStatement\n} from './utils/styled-components-order-utils';\n\nimport type {TSESLint, TSESTree} from '@typescript-eslint/utils';\n\nconst createRule = ESLintUtils.RuleCreator(\n name => `https://github.com/nfqde/eslint-config-nfq/blob/master/docs/rules/${name}.md`\n);\n\ntype MessageIds = 'dependencyOrder' | 'renderOrder';\n\ntype DefinitionInfo = {\n canFix: boolean;\n dependencies: {name: string; node: TSESTree.Identifier}[];\n groupFirst: TSESTree.Node;\n groupLast: TSESTree.Node;\n id: TSESTree.Identifier;\n index: number;\n name: string;\n};\n\nexport const styledComponentsOrder = createRule<[], MessageIds>({\n defaultOptions: [],\n meta: {\n docs: {description: 'Ensure styled component definitions follow their JSX render order.'},\n fixable: 'code',\n messages: {\n dependencyOrder: 'Define {{dependency}} before {{component}} because it is used in its styles.',\n renderOrder: 'Define {{name}} after {{previous}} to match JSX render order.'\n },\n schema: [],\n type: 'suggestion'\n },\n name: 'styled-components-order',\n /**\n * Creates the rule visitor set and initializes all tracking state.\n * This function wires together definition collection and render-order analysis.\n * It returns the listener map that ESLint uses to walk the AST.\n *\n * @param context The rule context provided by ESLint.\n * @returns The rule listener map for this rule.\n *\n * @example\n * ```tsx\n * const listeners = create(context);\n * ```\n */\n // eslint-disable-next-line max-lines-per-function\n create(context) {\n const {sourceCode} = context;\n const definitions = new Map<string, DefinitionInfo>();\n const renderOrder: string[] = [];\n const renderSet = new Set<string>();\n /**\n * Computes statement grouping and placement information for a variable declarator.\n * This helps keep related statements together when producing fixes.\n * It returns null when the node cannot be safely handled.\n *\n * @param node The variable declarator to analyze.\n * @returns The statement info or null if unavailable.\n *\n * @example\n * ```tsx\n * const info = getStatementInfo(node);\n * ```\n */\n const getStatementInfo = (node: TSESTree.VariableDeclarator) => {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (node.parent?.type !== 'VariableDeclaration') {\n return null;\n }\n\n const declaration = node.parent;\n const statement = declaration.parent.type === 'ExportNamedDeclaration'\n ? declaration.parent\n : declaration;\n\n const parentNode = statement.parent;\n const body = 'body' in parentNode && Array.isArray(parentNode.body)\n ? parentNode.body\n : null;\n\n if (!body) {\n return null;\n }\n\n // @ts-expect-error\n const statementIndex = body.indexOf(statement);\n\n if (statementIndex === -1) {\n return null;\n }\n\n let groupFirst: TSESTree.Node = statement as TSESTree.Node;\n\n for (let i = statementIndex - 1; i >= 0; i -= 1) {\n const candidate = unwrapTypeStatement(body[i] as TSESTree.Node);\n\n if (!candidate) {\n break;\n }\n\n const gapText = sourceCode.text.slice(candidate.range[1], groupFirst.range[0]);\n\n if (gapText.trim()) {\n break;\n }\n\n groupFirst = candidate;\n }\n\n return {\n canFix: declaration.declarations.length === 1,\n groupFirst,\n groupLast: statement as TSESTree.Node,\n index: groupFirst.range[0]\n };\n };\n /**\n * Builds a single fix function that reorders definitions to a desired sequence.\n * This function validates that a safe, contiguous replacement can be made.\n * It returns null when the fix would be unsafe or unnecessary.\n *\n * @param current The current ordered definitions.\n * @param desired The desired ordered definitions.\n * @returns A fixer callback or null if no fix is possible.\n *\n * @example\n * ```tsx\n * const fix = buildReorderFix(current, desired);\n * ```\n */\n const buildReorderFix = (current: DefinitionInfo[], desired: DefinitionInfo[]) => {\n if (current.length !== desired.length) {\n return null;\n }\n\n if (current.every((definition, index) => definition === desired[index])) {\n return null;\n }\n\n if (current.some(definition => !definition.canFix)) {\n return null;\n }\n\n if (current.some(definition => sourceCode.getCommentsBefore(definition.groupFirst).length > 0)) {\n return null;\n }\n\n const parent = current[0]?.groupFirst.parent;\n\n if (!parent || current.some(definition => definition.groupFirst.parent !== parent)) {\n return null;\n }\n\n if (!('body' in parent) || !Array.isArray(parent.body)) {\n return null;\n }\n\n const body = parent.body as TSESTree.Node[];\n const groupEntries = current.map(definition => {\n const startIndex = body.indexOf(definition.groupFirst);\n const endIndex = body.indexOf(definition.groupLast);\n\n if (startIndex === -1 || endIndex === -1 || startIndex > endIndex) {\n return null;\n }\n\n return {\n definition,\n endIndex,\n startIndex\n };\n });\n\n if (groupEntries.some(entry => !entry)) {\n return null;\n }\n\n const ranges = groupEntries;\n const minIndex = Math.min(...ranges.map(entry => entry!.startIndex));\n const maxIndex = Math.max(...ranges.map(entry => entry!.endIndex));\n const covered = new Set<number>();\n\n ranges.forEach(entry => {\n for (let i = entry!.startIndex; i <= entry!.endIndex; i += 1) {\n covered.add(i);\n }\n });\n\n for (let i = minIndex; i <= maxIndex; i += 1) {\n if (!covered.has(i)) {\n return null;\n }\n }\n\n const minRange = Math.min(...current.map(definition => definition.groupFirst.range[0]));\n const maxRange = Math.max(...current.map(definition => definition.groupLast.range[1]));\n const desiredText = desired\n .map(definition => sourceCode.text.slice(definition.groupFirst.range[0], definition.groupLast.range[1]))\n .join('\\n\\n');\n\n return (fixer: TSESLint.RuleFixer) => [\n fixer.replaceTextRange([minRange, maxRange], desiredText)\n ];\n };\n\n /**\n * Records a styled component definition and its dependencies for later validation.\n * This function ignores non-styled or duplicate definitions.\n * It stores grouping and index data required for reporting and fixes.\n *\n * @param node The variable declarator to inspect.\n *\n * @example\n * ```tsx\n * recordDefinition(node);\n * ```\n */\n const recordDefinition = (node: TSESTree.VariableDeclarator) => {\n if (node.id.type !== 'Identifier') {\n return;\n }\n\n if (node.init?.type !== 'TaggedTemplateExpression') {\n return;\n }\n\n const tag = unwrapExpression(node.init.tag);\n\n if (!isStyledBase(tag)) {\n return;\n }\n\n const {name} = node.id;\n const statementInfo = getStatementInfo(node);\n\n if (!statementInfo) {\n return;\n }\n\n if (definitions.has(name)) {\n return;\n }\n\n definitions.set(name, {\n canFix: statementInfo.canFix,\n dependencies: getDependencyNames(node.init.quasi),\n groupFirst: statementInfo.groupFirst,\n groupLast: statementInfo.groupLast,\n id: node.id,\n index: statementInfo.index,\n name\n });\n };\n\n const listeners: TSESLint.RuleListener = {\n 'Program:exit': () => {\n const orderedDefinitions = Array.from(definitions.values()).sort((a, b) => a.index - b.index);\n const definitionIndex = new Map<string, number>();\n\n orderedDefinitions.forEach((definition, index) => {\n definitionIndex.set(definition.name, index);\n });\n\n const dependencyMap = new Map<string, Set<string>>();\n\n const renderIndex = new Map(renderOrder.map((name, index) => [name, index] as const));\n const graph = new Map<string, Set<string>>();\n const inDegree = new Map<string, number>();\n\n orderedDefinitions.forEach(definition => {\n graph.set(definition.name, new Set());\n inDegree.set(definition.name, 0);\n });\n\n orderedDefinitions.forEach(definition => {\n const deps = new Set(\n definition.dependencies\n .map(dep => dep.name)\n .filter(dep => definitionIndex.has(dep))\n );\n\n if (deps.size > 0) {\n dependencyMap.set(definition.name, deps);\n }\n\n deps.forEach(dep => {\n if (!graph.has(dep)) {\n graph.set(dep, new Set());\n }\n\n graph.get(dep)!.add(definition.name);\n inDegree.set(definition.name, (inDegree.get(definition.name) ?? 0) + 1);\n });\n });\n\n /**\n * Computes a tuple used to prioritize definitions during sorting.\n * This combines render order position with source order.\n * It returns a tuple that is stable and deterministic.\n *\n * @param definition The definition to prioritize.\n * @returns The priority tuple.\n *\n * @example\n * ```tsx\n * const priority = priorityFor(definition);\n * ```\n */\n const priorityFor = (definition: DefinitionInfo) => {\n const renderPos = renderIndex.get(definition.name);\n\n return [renderPos ?? Number.POSITIVE_INFINITY, definition.index] as const;\n };\n\n /**\n * Compares two definitions using their computed priority. This ensures render order wins over source order when available. It returns a standard sort comparator value.\n *\n * @param left The first definition to compare.\n * @param right The second definition to compare.\n * @returns A comparator number for sorting.\n *\n * @example\n * ```tsx\n * const result = byPriority(a, b);\n * ```\n */\n const byPriority = (left: DefinitionInfo, right: DefinitionInfo) => {\n const [leftRender, leftIndex] = priorityFor(left);\n const [rightRender, rightIndex] = priorityFor(right);\n\n if (leftRender !== rightRender) {\n return leftRender - rightRender;\n }\n\n return leftIndex - rightIndex;\n };\n\n const pending = orderedDefinitions.filter(definition => (inDegree.get(definition.name) ?? 0) === 0);\n const desiredOrder: DefinitionInfo[] = [];\n\n while (pending.length > 0) {\n compareBy(pending, byPriority);\n const next = pending.shift()!;\n\n desiredOrder.push(next);\n\n graph.get(next.name)?.forEach(dependent => {\n const nextDegree = (inDegree.get(dependent) ?? 0) - 1;\n\n inDegree.set(dependent, nextDegree);\n\n if (nextDegree === 0) {\n const dependentDefinition = definitions.get(dependent);\n\n if (dependentDefinition) {\n pending.push(dependentDefinition);\n }\n }\n });\n }\n\n const renderNames = renderOrder.filter(name => definitionIndex.has(name));\n const needsRenderOrder = renderNames.length > 0;\n const reorderFix = desiredOrder.length === orderedDefinitions.length\n ? buildReorderFix(orderedDefinitions, desiredOrder)\n : null;\n let fixUsed = false;\n\n /**\n * Attaches a fix only once, ensuring deterministic and safe fixes.\n * This function prevents multiple reports from emitting the same fixer.\n * It returns undefined when a fix cannot be attached.\n *\n * @param fix The candidate fix to attach.\n * @returns The fix or undefined.\n *\n * @example\n * ```tsx\n * const fix = attachFix(reorderFix);\n * ```\n */\n const attachFix = (fix: ReturnType<typeof buildReorderFix>) => {\n if (!fix || fixUsed) {\n return undefined;\n }\n\n fixUsed = true;\n\n return fix;\n };\n\n orderedDefinitions.forEach(definition => {\n const currentIndex = definitionIndex.get(definition.name);\n\n if (currentIndex === undefined) {\n return;\n }\n\n definition.dependencies.forEach(dep => {\n const depIndex = definitionIndex.get(dep.name);\n\n if (depIndex !== undefined && depIndex > currentIndex) {\n context.report({\n data: {\n component: definition.name,\n dependency: dep.name\n },\n fix: attachFix(reorderFix),\n messageId: 'dependencyOrder',\n node: dep.node\n });\n }\n });\n });\n\n const earlierRendered: string[] = [];\n let maxDefIndex = -1;\n let maxDefName = '';\n\n renderNames.forEach(name => {\n const currentIndex = definitionIndex.get(name);\n\n if (currentIndex === undefined) {\n return;\n }\n\n if (currentIndex < maxDefIndex) {\n const isDependencyForEarlier = earlierRendered\n .some(earlier => dependencyMap.get(earlier)?.has(name));\n\n if (!isDependencyForEarlier) {\n const definition = definitions.get(name);\n\n if (definition) {\n context.report({\n data: {\n name,\n previous: maxDefName\n },\n fix: needsRenderOrder ? attachFix(reorderFix) : undefined,\n messageId: 'renderOrder',\n node: definition.id\n });\n }\n }\n }\n\n if (currentIndex > maxDefIndex) {\n maxDefIndex = currentIndex;\n maxDefName = name;\n }\n\n earlierRendered.push(name);\n });\n },\n VariableDeclarator: recordDefinition,\n /**\n * Tracks JSX opening elements to derive render order.\n * This function records each component name once in first-seen order.\n * It ignores non-identifier element names.\n *\n * @param node The JSX opening element node.\n *\n * @example\n * ```tsx\n * listeners.JSXOpeningElement(node);\n * ```\n */\n JSXOpeningElement(node) {\n if (node.name.type !== 'JSXIdentifier') {\n return;\n }\n\n const {name} = node.name;\n\n if (!renderSet.has(name)) {\n renderSet.add(name);\n renderOrder.push(name);\n }\n }\n };\n\n return listeners;\n }\n});"],"names":["createRule","ESLintUtils","RuleCreator","name","styledComponentsOrder","defaultOptions","meta","docs","description","fixable","messages","dependencyOrder","renderOrder","schema","type","create","context","sourceCode","definitions","Map","renderSet","Set","getStatementInfo","node","parent","declaration","statement","parentNode","body","Array","isArray","statementIndex","indexOf","groupFirst","i","candidate","unwrapTypeStatement","gapText","text","slice","range","trim","canFix","declarations","length","groupLast","index","buildReorderFix","current","desired","every","definition","some","getCommentsBefore","groupEntries","map","startIndex","endIndex","entry","ranges","minIndex","Math","min","maxIndex","max","covered","forEach","add","has","minRange","maxRange","desiredText","join","fixer","replaceTextRange","recordDefinition","id","init","tag","unwrapExpression","isStyledBase","statementInfo","set","dependencies","getDependencyNames","quasi","listeners","Program:exit","orderedDefinitions","from","values","sort","a","b","definitionIndex","dependencyMap","renderIndex","graph","inDegree","deps","dep","filter","size","get","priorityFor","renderPos","Number","POSITIVE_INFINITY","byPriority","left","right","leftRender","leftIndex","rightRender","rightIndex","pending","desiredOrder","compareBy","next","shift","push","dependent","nextDegree","dependentDefinition","renderNames","needsRenderOrder","reorderFix","fixUsed","attachFix","fix","undefined","currentIndex","depIndex","report","data","component","dependency","messageId","earlierRendered","maxDefIndex","maxDefName","isDependencyForEarlier","earlier","previous","VariableDeclarator","JSXOpeningElement"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"styled-components-order.js","sources":["../../../../src/rules/custom/styled-components-order.ts"],"sourcesContent":["import {ESLintUtils} from '@typescript-eslint/utils';\n\nimport {\n compareBy,\n getDependencyNames,\n getTagDependencies,\n isStyledBase,\n unwrapExpression,\n unwrapTypeStatement\n} from './utils/styled-components-order-utils';\n\nimport type {TSESLint, TSESTree} from '@typescript-eslint/utils';\n\nconst createRule = ESLintUtils.RuleCreator(\n name => `https://github.com/nfqde/eslint-config-nfq/blob/master/docs/rules/${name}.md`\n);\n\ntype MessageIds = 'dependencyOrder' | 'renderOrder';\n\ntype DefinitionInfo = {\n canFix: boolean;\n dependencies: {name: string; node: TSESTree.Identifier}[];\n groupFirst: TSESTree.Node;\n groupLast: TSESTree.Node;\n id: TSESTree.Identifier;\n index: number;\n name: string;\n};\n\nexport const styledComponentsOrder = createRule<[], MessageIds>({\n defaultOptions: [],\n meta: {\n docs: {description: 'Ensure styled component definitions follow their JSX render order.'},\n fixable: 'code',\n messages: {\n dependencyOrder: 'Define {{dependency}} before {{component}} because it is used in its styles.',\n renderOrder: 'Define {{name}} after {{previous}} to match JSX render order.'\n },\n schema: [],\n type: 'suggestion'\n },\n name: 'styled-components-order',\n /**\n * Creates the rule visitor set and initializes all tracking state.\n * This function wires together definition collection and render-order analysis.\n * It returns the listener map that ESLint uses to walk the AST.\n *\n * @param context The rule context provided by ESLint.\n * @returns The rule listener map for this rule.\n *\n * @example\n * ```tsx\n * const listeners = create(context);\n * ```\n */\n // eslint-disable-next-line max-lines-per-function\n create(context) {\n const {sourceCode} = context;\n const definitions = new Map<string, DefinitionInfo>();\n const renderOrder: string[] = [];\n const renderSet = new Set<string>();\n /**\n * Computes statement grouping and placement information for a variable declarator.\n * This helps keep related statements together when producing fixes.\n * It returns null when the node cannot be safely handled.\n *\n * @param node The variable declarator to analyze.\n * @returns The statement info or null if unavailable.\n *\n * @example\n * ```tsx\n * const info = getStatementInfo(node);\n * ```\n */\n const getStatementInfo = (node: TSESTree.VariableDeclarator) => {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (node.parent?.type !== 'VariableDeclaration') {\n return null;\n }\n\n const declaration = node.parent;\n const statement = declaration.parent.type === 'ExportNamedDeclaration'\n ? declaration.parent\n : declaration;\n\n const parentNode = statement.parent;\n const body = 'body' in parentNode && Array.isArray(parentNode.body)\n ? parentNode.body\n : null;\n\n if (!body) {\n return null;\n }\n\n // @ts-expect-error\n const statementIndex = body.indexOf(statement);\n\n if (statementIndex === -1) {\n return null;\n }\n\n let groupFirst: TSESTree.Node = statement as TSESTree.Node;\n\n for (let i = statementIndex - 1; i >= 0; i -= 1) {\n const candidate = unwrapTypeStatement(body[i] as TSESTree.Node);\n\n if (!candidate) {\n break;\n }\n\n const gapText = sourceCode.text.slice(candidate.range[1], groupFirst.range[0]);\n\n if (gapText.trim()) {\n break;\n }\n\n groupFirst = candidate;\n }\n\n return {\n canFix: declaration.declarations.length === 1,\n groupFirst,\n groupLast: statement as TSESTree.Node,\n index: groupFirst.range[0]\n };\n };\n /**\n * Builds a single fix function that reorders definitions to a desired sequence.\n * This function validates that a safe, contiguous replacement can be made.\n * It returns null when the fix would be unsafe or unnecessary.\n *\n * @param current The current ordered definitions.\n * @param desired The desired ordered definitions.\n * @returns A fixer callback or null if no fix is possible.\n *\n * @example\n * ```tsx\n * const fix = buildReorderFix(current, desired);\n * ```\n */\n const buildReorderFix = (current: DefinitionInfo[], desired: DefinitionInfo[]) => {\n if (current.length !== desired.length) {\n return null;\n }\n\n if (current.every((definition, index) => definition === desired[index])) {\n return null;\n }\n\n if (current.some(definition => !definition.canFix)) {\n return null;\n }\n\n if (current.some(definition => sourceCode.getCommentsBefore(definition.groupFirst).length > 0)) {\n return null;\n }\n\n const parent = current[0]?.groupFirst.parent;\n\n if (!parent || current.some(definition => definition.groupFirst.parent !== parent)) {\n return null;\n }\n\n if (!('body' in parent) || !Array.isArray(parent.body)) {\n return null;\n }\n\n const body = parent.body as TSESTree.Node[];\n const groupEntries = current.map(definition => {\n const startIndex = body.indexOf(definition.groupFirst);\n const endIndex = body.indexOf(definition.groupLast);\n\n if (startIndex === -1 || endIndex === -1 || startIndex > endIndex) {\n return null;\n }\n\n return {\n definition,\n endIndex,\n startIndex\n };\n });\n\n if (groupEntries.some(entry => !entry)) {\n return null;\n }\n\n const ranges = groupEntries;\n const minIndex = Math.min(...ranges.map(entry => entry!.startIndex));\n const maxIndex = Math.max(...ranges.map(entry => entry!.endIndex));\n const covered = new Set<number>();\n\n ranges.forEach(entry => {\n for (let i = entry!.startIndex; i <= entry!.endIndex; i += 1) {\n covered.add(i);\n }\n });\n\n for (let i = minIndex; i <= maxIndex; i += 1) {\n if (!covered.has(i)) {\n return null;\n }\n }\n\n const minRange = Math.min(...current.map(definition => definition.groupFirst.range[0]));\n const maxRange = Math.max(...current.map(definition => definition.groupLast.range[1]));\n const desiredText = desired\n .map(definition => sourceCode.text.slice(definition.groupFirst.range[0], definition.groupLast.range[1]))\n .join('\\n\\n');\n\n return (fixer: TSESLint.RuleFixer) => [\n fixer.replaceTextRange([minRange, maxRange], desiredText)\n ];\n };\n\n /**\n * Records a styled component definition and its dependencies for later validation.\n * This function ignores non-styled or duplicate definitions.\n * It stores grouping and index data required for reporting and fixes.\n *\n * @param node The variable declarator to inspect.\n *\n * @example\n * ```tsx\n * recordDefinition(node);\n * ```\n */\n const recordDefinition = (node: TSESTree.VariableDeclarator) => {\n if (node.id.type !== 'Identifier') {\n return;\n }\n\n if (node.init?.type !== 'TaggedTemplateExpression') {\n return;\n }\n\n const tag = unwrapExpression(node.init.tag);\n\n if (!isStyledBase(tag)) {\n return;\n }\n\n const {name} = node.id;\n const statementInfo = getStatementInfo(node);\n\n if (!statementInfo) {\n return;\n }\n\n if (definitions.has(name)) {\n return;\n }\n\n definitions.set(name, {\n canFix: statementInfo.canFix,\n dependencies: [...getTagDependencies(node.init.tag), ...getDependencyNames(node.init.quasi)],\n groupFirst: statementInfo.groupFirst,\n groupLast: statementInfo.groupLast,\n id: node.id,\n index: statementInfo.index,\n name\n });\n };\n\n const listeners: TSESLint.RuleListener = {\n 'Program:exit': () => {\n const orderedDefinitions = Array.from(definitions.values()).sort((a, b) => a.index - b.index);\n const definitionIndex = new Map<string, number>();\n\n orderedDefinitions.forEach((definition, index) => {\n definitionIndex.set(definition.name, index);\n });\n\n const dependencyMap = new Map<string, Set<string>>();\n\n const renderIndex = new Map(renderOrder.map((name, index) => [name, index] as const));\n const graph = new Map<string, Set<string>>();\n const inDegree = new Map<string, number>();\n\n orderedDefinitions.forEach(definition => {\n graph.set(definition.name, new Set());\n inDegree.set(definition.name, 0);\n });\n\n orderedDefinitions.forEach(definition => {\n const deps = new Set(\n definition.dependencies\n .map(dep => dep.name)\n .filter(dep => definitionIndex.has(dep))\n );\n\n if (deps.size > 0) {\n dependencyMap.set(definition.name, deps);\n }\n\n deps.forEach(dep => {\n if (!graph.has(dep)) {\n graph.set(dep, new Set());\n }\n\n graph.get(dep)!.add(definition.name);\n inDegree.set(definition.name, (inDegree.get(definition.name) ?? 0) + 1);\n });\n });\n\n /**\n * Computes a tuple used to prioritize definitions during sorting.\n * This combines render order position with source order.\n * It returns a tuple that is stable and deterministic.\n *\n * @param definition The definition to prioritize.\n * @returns The priority tuple.\n *\n * @example\n * ```tsx\n * const priority = priorityFor(definition);\n * ```\n */\n const priorityFor = (definition: DefinitionInfo) => {\n const renderPos = renderIndex.get(definition.name);\n\n return [renderPos ?? Number.POSITIVE_INFINITY, definition.index] as const;\n };\n\n /**\n * Compares two definitions using their computed priority. This ensures render order wins over source order when available. It returns a standard sort comparator value.\n *\n * @param left The first definition to compare.\n * @param right The second definition to compare.\n * @returns A comparator number for sorting.\n *\n * @example\n * ```tsx\n * const result = byPriority(a, b);\n * ```\n */\n const byPriority = (left: DefinitionInfo, right: DefinitionInfo) => {\n const [leftRender, leftIndex] = priorityFor(left);\n const [rightRender, rightIndex] = priorityFor(right);\n\n if (leftRender !== rightRender) {\n return leftRender - rightRender;\n }\n\n return leftIndex - rightIndex;\n };\n\n const pending = orderedDefinitions.filter(definition => (inDegree.get(definition.name) ?? 0) === 0);\n const desiredOrder: DefinitionInfo[] = [];\n\n while (pending.length > 0) {\n compareBy(pending, byPriority);\n const next = pending.shift()!;\n\n desiredOrder.push(next);\n\n graph.get(next.name)?.forEach(dependent => {\n const nextDegree = (inDegree.get(dependent) ?? 0) - 1;\n\n inDegree.set(dependent, nextDegree);\n\n if (nextDegree === 0) {\n const dependentDefinition = definitions.get(dependent);\n\n if (dependentDefinition) {\n pending.push(dependentDefinition);\n }\n }\n });\n }\n\n const renderNames = renderOrder.filter(name => definitionIndex.has(name));\n const needsRenderOrder = renderNames.length > 0;\n const reorderFix = desiredOrder.length === orderedDefinitions.length\n ? buildReorderFix(orderedDefinitions, desiredOrder)\n : null;\n let fixUsed = false;\n\n /**\n * Attaches a fix only once, ensuring deterministic and safe fixes.\n * This function prevents multiple reports from emitting the same fixer.\n * It returns undefined when a fix cannot be attached.\n *\n * @param fix The candidate fix to attach.\n * @returns The fix or undefined.\n *\n * @example\n * ```tsx\n * const fix = attachFix(reorderFix);\n * ```\n */\n const attachFix = (fix: ReturnType<typeof buildReorderFix>) => {\n if (!fix || fixUsed) {\n return undefined;\n }\n\n fixUsed = true;\n\n return fix;\n };\n\n orderedDefinitions.forEach(definition => {\n const currentIndex = definitionIndex.get(definition.name);\n\n if (currentIndex === undefined) {\n return;\n }\n\n definition.dependencies.forEach(dep => {\n const depIndex = definitionIndex.get(dep.name);\n\n if (depIndex !== undefined && depIndex > currentIndex) {\n context.report({\n data: {\n component: definition.name,\n dependency: dep.name\n },\n fix: attachFix(reorderFix),\n messageId: 'dependencyOrder',\n node: dep.node\n });\n }\n });\n });\n\n const transitiveDeps = new Map<string, Set<string>>();\n\n /**\n * Computes the full set of transitive dependencies for a component. It recursively\n * follows direct dependencies, caching results to avoid redundant work. It returns\n * a set containing all direct and indirect dependency names.\n *\n * @param name The component name to resolve transitive deps for.\n * @returns The set of all transitive dependency names.\n */\n const getTransitiveDeps = (name: string): Set<string> => {\n if (transitiveDeps.has(name)) {\n return transitiveDeps.get(name)!;\n }\n\n const result = new Set<string>();\n\n transitiveDeps.set(name, result);\n\n const direct = dependencyMap.get(name);\n\n if (direct) {\n for (const dep of direct) {\n result.add(dep);\n\n for (const transitive of getTransitiveDeps(dep)) {\n result.add(transitive);\n }\n }\n }\n\n return result;\n };\n\n const earlierRendered: string[] = [];\n let maxDefIndex = -1;\n let maxDefName = '';\n\n renderNames.forEach(name => {\n const currentIndex = definitionIndex.get(name);\n\n if (currentIndex === undefined) {\n return;\n }\n\n if (currentIndex < maxDefIndex) {\n const isDependencyForEarlier = earlierRendered\n .some(earlier => getTransitiveDeps(earlier).has(name));\n\n if (!isDependencyForEarlier) {\n const definition = definitions.get(name);\n\n if (definition) {\n context.report({\n data: {\n name,\n previous: maxDefName\n },\n fix: needsRenderOrder ? attachFix(reorderFix) : undefined,\n messageId: 'renderOrder',\n node: definition.id\n });\n }\n }\n }\n\n if (currentIndex > maxDefIndex) {\n maxDefIndex = currentIndex;\n maxDefName = name;\n }\n\n earlierRendered.push(name);\n });\n },\n VariableDeclarator: recordDefinition,\n /**\n * Tracks JSX opening elements to derive render order.\n * This function records each component name once in first-seen order.\n * It ignores non-identifier element names.\n *\n * @param node The JSX opening element node.\n *\n * @example\n * ```tsx\n * listeners.JSXOpeningElement(node);\n * ```\n */\n JSXOpeningElement(node) {\n if (node.name.type !== 'JSXIdentifier') {\n return;\n }\n\n const {name} = node.name;\n\n if (!renderSet.has(name)) {\n renderSet.add(name);\n renderOrder.push(name);\n }\n }\n };\n\n return listeners;\n }\n});"],"names":["createRule","ESLintUtils","RuleCreator","name","styledComponentsOrder","defaultOptions","meta","docs","description","fixable","messages","dependencyOrder","renderOrder","schema","type","create","context","sourceCode","definitions","Map","renderSet","Set","getStatementInfo","node","parent","declaration","statement","parentNode","body","Array","isArray","statementIndex","indexOf","groupFirst","i","candidate","unwrapTypeStatement","gapText","text","slice","range","trim","canFix","declarations","length","groupLast","index","buildReorderFix","current","desired","every","definition","some","getCommentsBefore","groupEntries","map","startIndex","endIndex","entry","ranges","minIndex","Math","min","maxIndex","max","covered","forEach","add","has","minRange","maxRange","desiredText","join","fixer","replaceTextRange","recordDefinition","id","init","tag","unwrapExpression","isStyledBase","statementInfo","set","dependencies","getTagDependencies","getDependencyNames","quasi","listeners","Program:exit","orderedDefinitions","from","values","sort","a","b","definitionIndex","dependencyMap","renderIndex","graph","inDegree","deps","dep","filter","size","get","priorityFor","renderPos","Number","POSITIVE_INFINITY","byPriority","left","right","leftRender","leftIndex","rightRender","rightIndex","pending","desiredOrder","compareBy","next","shift","push","dependent","nextDegree","dependentDefinition","renderNames","needsRenderOrder","reorderFix","fixUsed","attachFix","fix","undefined","currentIndex","depIndex","report","data","component","dependency","messageId","transitiveDeps","getTransitiveDeps","result","direct","transitive","earlierRendered","maxDefIndex","maxDefName","isDependencyForEarlier","earlier","previous","VariableDeclarator","JSXOpeningElement"],"mappings":"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"}
|
|
@@ -24,6 +24,31 @@ const getDependencyNames = template => template.expressions.map(expression => un
|
|
|
24
24
|
name: identifier.name,
|
|
25
25
|
node: identifier
|
|
26
26
|
}));
|
|
27
|
+
const getTagDependencies = tag => {
|
|
28
|
+
const deps = [];
|
|
29
|
+
let current = unwrapExpression(tag);
|
|
30
|
+
while (current.type === 'MemberExpression') {
|
|
31
|
+
current = unwrapExpression(current.object);
|
|
32
|
+
}
|
|
33
|
+
while (current.type === 'CallExpression') {
|
|
34
|
+
for (const arg of current.arguments) {
|
|
35
|
+
if (arg.type !== 'SpreadElement') {
|
|
36
|
+
const unwrapped = unwrapExpression(arg);
|
|
37
|
+
if (ASTUtils.isIdentifier(unwrapped)) {
|
|
38
|
+
deps.push({
|
|
39
|
+
name: unwrapped.name,
|
|
40
|
+
node: unwrapped
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
current = unwrapExpression(current.callee);
|
|
46
|
+
if (current.type === 'MemberExpression') {
|
|
47
|
+
current = unwrapExpression(current.object);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return deps;
|
|
51
|
+
};
|
|
27
52
|
const unwrapTypeStatement = node => {
|
|
28
53
|
if (node.type === 'TSInterfaceDeclaration' || node.type === 'TSTypeAliasDeclaration') {
|
|
29
54
|
return node;
|
|
@@ -40,5 +65,5 @@ const unwrapTypeStatement = node => {
|
|
|
40
65
|
};
|
|
41
66
|
const compareBy = (items, compare) => items.sort(compare);
|
|
42
67
|
|
|
43
|
-
export { compareBy, getDependencyNames, isStyledBase, unwrapExpression, unwrapTypeStatement };
|
|
68
|
+
export { compareBy, getDependencyNames, getTagDependencies, isStyledBase, unwrapExpression, unwrapTypeStatement };
|
|
44
69
|
//# sourceMappingURL=styled-components-order-utils.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"styled-components-order-utils.js","sources":["../../../../../src/rules/custom/utils/styled-components-order-utils.ts"],"sourcesContent":["import {ASTUtils} from '@typescript-eslint/utils';\n\nimport type {TSESTree} from '@typescript-eslint/utils';\n\n/**\n * Unwraps nested TypeScript expression wrappers until the underlying expression is reached.\n * It repeatedly removes chain, type assertion, and non-null wrapper nodes so downstream logic can analyze the actual\n * target. This helps ensure consistent behavior when expressions are wrapped by optional chaining or type-related syntax.\n *\n * @param expression The expression to unwrap.\n * @returns The innermost unwrapped expression.\n *\n * @example\n * ```tsx\n * const base = unwrapExpression(someExpression);\n * ```\n */\nexport const unwrapExpression = (expression: TSESTree.Expression): TSESTree.Expression => {\n let current = expression;\n\n while (\n current.type === 'ChainExpression'\n || current.type === 'TSAsExpression'\n || current.type === 'TSNonNullExpression'\n ) {\n current = current.expression;\n }\n\n return current;\n};\n\n/**\n * Determines whether an expression ultimately resolves to the styled base identifier.\n * It walks through member access and call expressions to reach the root value. This allows the rule logic to\n * treat chained or called styled usages as coming from the same base.\n *\n * @param expression The expression to inspect.\n * @returns True when the expression resolves to the styled base.\n *\n * @example\n * ```tsx\n * const isBase = isStyledBase(styled.div);\n * ```\n */\nexport const isStyledBase = (expression: TSESTree.Expression): boolean => {\n const node = unwrapExpression(expression);\n\n if (ASTUtils.isIdentifier(node)) {\n return node.name === 'styled';\n }\n\n if (node.type === 'MemberExpression') {\n return isStyledBase(node.object);\n }\n\n if (node.type === 'CallExpression') {\n return isStyledBase(node.callee);\n }\n\n return false;\n};\n\n/**\n * Collects identifier dependencies used inside a template literal. It unwraps each expression\n * to its base and keeps only identifiers for easier analysis. This provides both the name and the\n * identifier node for each dependency.\n *\n * @param template The template literal to analyze.\n * @returns A list of dependency names with their identifier nodes.\n *\n * @example\n * ```tsx\n * const deps = getDependencyNames(templateLiteral);\n * ```\n */\nexport const getDependencyNames = (\n template: TSESTree.TemplateLiteral\n): {name: string; node: TSESTree.Identifier}[] => (\n template.expressions\n .map(expression => unwrapExpression(expression))\n .filter(ASTUtils.isIdentifier)\n .map(identifier => ({\n name: identifier.name,\n node: identifier\n }))\n);\n\n/**\n * Returns a type statement node when the given node represents a type declaration. It supports direct type\n * declarations and named export declarations that contain them. This helps callers normalize type statement\n * handling in a consistent way.\n *\n * @param node The node to inspect.\n * @returns The type statement node when found, otherwise null.\n *\n * @example\n * ```tsx\n * const typeNode = unwrapTypeStatement(node);\n * ```\n */\nexport const unwrapTypeStatement = (node: TSESTree.Node): TSESTree.Node | null => {\n if (node.type === 'TSInterfaceDeclaration' || node.type === 'TSTypeAliasDeclaration') {\n return node;\n }\n\n if (node.type === 'ExportNamedDeclaration' && node.declaration) {\n const {declaration} = node;\n\n if (declaration.type === 'TSInterfaceDeclaration' || declaration.type === 'TSTypeAliasDeclaration') {\n return node;\n }\n }\n\n return null;\n};\n\n/**\n * Sorts a list of items using a provided comparison function. It delegates to the native sort algorithm to\n * produce the ordering. This utility keeps comparison logic centralized while returning the sorted array.\n *\n * @param items The items to sort.\n * @param compare The comparison function used for sorting.\n * @returns The sorted items array.\n *\n * @example\n * ```tsx\n * const sorted = compareBy(items, (a, b) => a.value - b.value);\n * ```\n */\nexport const compareBy = <T>(items: T[], compare: (left: T, right: T) => number) => (\n items.sort(compare)\n);"],"names":["unwrapExpression","expression","current","type","isStyledBase","node","ASTUtils","isIdentifier","name","object","callee","getDependencyNames","template","expressions","map","filter","identifier","unwrapTypeStatement","declaration","compareBy","items","compare","sort"],"mappings":";;AAiBO,MAAMA,gBAAgB,GAAIC,UAA+B,IAA0B;EACtF,IAAIC,OAAO,GAAGD,UAAU;AAExB,EAAA,OACIC,OAAO,CAACC,IAAI,KAAK,iBAAiB,IAC/BD,OAAO,CAACC,IAAI,KAAK,gBAAgB,IACjCD,OAAO,CAACC,IAAI,KAAK,qBAAqB,EAC3C;IACED,OAAO,GAAGA,OAAO,CAACD,UAAU;AAChC,EAAA;AAEA,EAAA,OAAOC,OAAO;AAClB;AAeO,MAAME,YAAY,GAAIH,UAA+B,IAAc;AACtE,EAAA,MAAMI,IAAI,GAAGL,gBAAgB,CAACC,UAAU,CAAC;AAEzC,EAAA,IAAIK,QAAQ,CAACC,YAAY,CAACF,IAAI,CAAC,EAAE;AAC7B,IAAA,OAAOA,IAAI,CAACG,IAAI,KAAK,QAAQ;AACjC,EAAA;AAEA,EAAA,IAAIH,IAAI,CAACF,IAAI,KAAK,kBAAkB,EAAE;AAClC,IAAA,OAAOC,YAAY,CAACC,IAAI,CAACI,MAAM,CAAC;AACpC,EAAA;AAEA,EAAA,IAAIJ,IAAI,CAACF,IAAI,KAAK,gBAAgB,EAAE;AAChC,IAAA,OAAOC,YAAY,CAACC,IAAI,CAACK,MAAM,CAAC;AACpC,EAAA;AAEA,EAAA,OAAO,KAAK;AAChB;AAeO,MAAMC,kBAAkB,GAC3BC,QAAkC,IAElCA,QAAQ,CAACC,WAAW,CACfC,GAAG,CAACb,UAAU,IAAID,gBAAgB,CAACC,UAAU,CAAC,CAAC,CAC/Cc,MAAM,CAACT,QAAQ,CAACC,YAAY,CAAC,CAC7BO,GAAG,CAACE,UAAU,KAAK;EAChBR,IAAI,EAAEQ,UAAU,CAACR,IAAI;AACrBH,EAAAA,IAAI,EAAEW;AACV,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"styled-components-order-utils.js","sources":["../../../../../src/rules/custom/utils/styled-components-order-utils.ts"],"sourcesContent":["import {ASTUtils} from '@typescript-eslint/utils';\n\nimport type {TSESTree} from '@typescript-eslint/utils';\n\n/**\n * Unwraps nested TypeScript expression wrappers until the underlying expression is reached.\n * It repeatedly removes chain, type assertion, and non-null wrapper nodes so downstream logic can analyze the actual\n * target. This helps ensure consistent behavior when expressions are wrapped by optional chaining or type-related syntax.\n *\n * @param expression The expression to unwrap.\n * @returns The innermost unwrapped expression.\n *\n * @example\n * ```tsx\n * const base = unwrapExpression(someExpression);\n * ```\n */\nexport const unwrapExpression = (expression: TSESTree.Expression): TSESTree.Expression => {\n let current = expression;\n\n while (\n current.type === 'ChainExpression'\n || current.type === 'TSAsExpression'\n || current.type === 'TSNonNullExpression'\n ) {\n current = current.expression;\n }\n\n return current;\n};\n\n/**\n * Determines whether an expression ultimately resolves to the styled base identifier.\n * It walks through member access and call expressions to reach the root value. This allows the rule logic to\n * treat chained or called styled usages as coming from the same base.\n *\n * @param expression The expression to inspect.\n * @returns True when the expression resolves to the styled base.\n *\n * @example\n * ```tsx\n * const isBase = isStyledBase(styled.div);\n * ```\n */\nexport const isStyledBase = (expression: TSESTree.Expression): boolean => {\n const node = unwrapExpression(expression);\n\n if (ASTUtils.isIdentifier(node)) {\n return node.name === 'styled';\n }\n\n if (node.type === 'MemberExpression') {\n return isStyledBase(node.object);\n }\n\n if (node.type === 'CallExpression') {\n return isStyledBase(node.callee);\n }\n\n return false;\n};\n\n/**\n * Collects identifier dependencies used inside a template literal. It unwraps each expression\n * to its base and keeps only identifiers for easier analysis. This provides both the name and the\n * identifier node for each dependency.\n *\n * @param template The template literal to analyze.\n * @returns A list of dependency names with their identifier nodes.\n *\n * @example\n * ```tsx\n * const deps = getDependencyNames(templateLiteral);\n * ```\n */\nexport const getDependencyNames = (\n template: TSESTree.TemplateLiteral\n): {name: string; node: TSESTree.Identifier}[] => (\n template.expressions\n .map(expression => unwrapExpression(expression))\n .filter(ASTUtils.isIdentifier)\n .map(identifier => ({\n name: identifier.name,\n node: identifier\n }))\n);\n\n/**\n * Extracts component identifier dependencies from a styled tag expression. It walks call\n * expressions in the tag chain and collects identifier arguments that represent base\n * components. This captures dependencies like `styled(TableCell)` that are not inside\n * the template literal.\n *\n * @param tag The tag expression from a TaggedTemplateExpression.\n * @returns A list of dependency names with their identifier nodes.\n *\n * @example\n * ```tsx\n * const deps = getTagDependencies(node.init.tag);\n * ```\n */\nexport const getTagDependencies = (\n tag: TSESTree.Expression\n): {name: string; node: TSESTree.Identifier}[] => {\n const deps: {name: string; node: TSESTree.Identifier}[] = [];\n let current: TSESTree.Expression = unwrapExpression(tag);\n\n while (current.type === 'MemberExpression') {\n current = unwrapExpression(current.object);\n }\n\n while (current.type === 'CallExpression') {\n for (const arg of current.arguments) {\n if (arg.type !== 'SpreadElement') {\n const unwrapped = unwrapExpression(arg);\n\n if (ASTUtils.isIdentifier(unwrapped)) {\n deps.push({name: unwrapped.name, node: unwrapped});\n }\n }\n }\n\n current = unwrapExpression(current.callee);\n\n if (current.type === 'MemberExpression') {\n current = unwrapExpression(current.object);\n }\n }\n\n return deps;\n};\n\n/**\n * Returns a type statement node when the given node represents a type declaration. It supports direct type\n * declarations and named export declarations that contain them. This helps callers normalize type statement\n * handling in a consistent way.\n *\n * @param node The node to inspect.\n * @returns The type statement node when found, otherwise null.\n *\n * @example\n * ```tsx\n * const typeNode = unwrapTypeStatement(node);\n * ```\n */\nexport const unwrapTypeStatement = (node: TSESTree.Node): TSESTree.Node | null => {\n if (node.type === 'TSInterfaceDeclaration' || node.type === 'TSTypeAliasDeclaration') {\n return node;\n }\n\n if (node.type === 'ExportNamedDeclaration' && node.declaration) {\n const {declaration} = node;\n\n if (declaration.type === 'TSInterfaceDeclaration' || declaration.type === 'TSTypeAliasDeclaration') {\n return node;\n }\n }\n\n return null;\n};\n\n/**\n * Sorts a list of items using a provided comparison function. It delegates to the native sort algorithm to\n * produce the ordering. This utility keeps comparison logic centralized while returning the sorted array.\n *\n * @param items The items to sort.\n * @param compare The comparison function used for sorting.\n * @returns The sorted items array.\n *\n * @example\n * ```tsx\n * const sorted = compareBy(items, (a, b) => a.value - b.value);\n * ```\n */\nexport const compareBy = <T>(items: T[], compare: (left: T, right: T) => number) => (\n items.sort(compare)\n);"],"names":["unwrapExpression","expression","current","type","isStyledBase","node","ASTUtils","isIdentifier","name","object","callee","getDependencyNames","template","expressions","map","filter","identifier","getTagDependencies","tag","deps","arg","arguments","unwrapped","push","unwrapTypeStatement","declaration","compareBy","items","compare","sort"],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -4603,6 +4603,31 @@ const getDependencyNames = template => template.expressions.map(expression => un
|
|
|
4603
4603
|
name: identifier.name,
|
|
4604
4604
|
node: identifier
|
|
4605
4605
|
}));
|
|
4606
|
+
const getTagDependencies = tag => {
|
|
4607
|
+
const deps = [];
|
|
4608
|
+
let current = unwrapExpression(tag);
|
|
4609
|
+
while (current.type === 'MemberExpression') {
|
|
4610
|
+
current = unwrapExpression(current.object);
|
|
4611
|
+
}
|
|
4612
|
+
while (current.type === 'CallExpression') {
|
|
4613
|
+
for (const arg of current.arguments) {
|
|
4614
|
+
if (arg.type !== 'SpreadElement') {
|
|
4615
|
+
const unwrapped = unwrapExpression(arg);
|
|
4616
|
+
if (utils.ASTUtils.isIdentifier(unwrapped)) {
|
|
4617
|
+
deps.push({
|
|
4618
|
+
name: unwrapped.name,
|
|
4619
|
+
node: unwrapped
|
|
4620
|
+
});
|
|
4621
|
+
}
|
|
4622
|
+
}
|
|
4623
|
+
}
|
|
4624
|
+
current = unwrapExpression(current.callee);
|
|
4625
|
+
if (current.type === 'MemberExpression') {
|
|
4626
|
+
current = unwrapExpression(current.object);
|
|
4627
|
+
}
|
|
4628
|
+
}
|
|
4629
|
+
return deps;
|
|
4630
|
+
};
|
|
4606
4631
|
const unwrapTypeStatement = node => {
|
|
4607
4632
|
if (node.type === 'TSInterfaceDeclaration' || node.type === 'TSTypeAliasDeclaration') {
|
|
4608
4633
|
return node;
|
|
@@ -4754,7 +4779,7 @@ const styledComponentsOrder = createRule({
|
|
|
4754
4779
|
}
|
|
4755
4780
|
definitions.set(name, {
|
|
4756
4781
|
canFix: statementInfo.canFix,
|
|
4757
|
-
dependencies: getDependencyNames(node.init.quasi),
|
|
4782
|
+
dependencies: [...getTagDependencies(node.init.tag), ...getDependencyNames(node.init.quasi)],
|
|
4758
4783
|
groupFirst: statementInfo.groupFirst,
|
|
4759
4784
|
groupLast: statementInfo.groupLast,
|
|
4760
4785
|
id: node.id,
|
|
@@ -4850,6 +4875,24 @@ const styledComponentsOrder = createRule({
|
|
|
4850
4875
|
}
|
|
4851
4876
|
});
|
|
4852
4877
|
});
|
|
4878
|
+
const transitiveDeps = new Map();
|
|
4879
|
+
const getTransitiveDeps = name => {
|
|
4880
|
+
if (transitiveDeps.has(name)) {
|
|
4881
|
+
return transitiveDeps.get(name);
|
|
4882
|
+
}
|
|
4883
|
+
const result = new Set();
|
|
4884
|
+
transitiveDeps.set(name, result);
|
|
4885
|
+
const direct = dependencyMap.get(name);
|
|
4886
|
+
if (direct) {
|
|
4887
|
+
for (const dep of direct) {
|
|
4888
|
+
result.add(dep);
|
|
4889
|
+
for (const transitive of getTransitiveDeps(dep)) {
|
|
4890
|
+
result.add(transitive);
|
|
4891
|
+
}
|
|
4892
|
+
}
|
|
4893
|
+
}
|
|
4894
|
+
return result;
|
|
4895
|
+
};
|
|
4853
4896
|
const earlierRendered = [];
|
|
4854
4897
|
let maxDefIndex = -1;
|
|
4855
4898
|
let maxDefName = '';
|
|
@@ -4859,7 +4902,7 @@ const styledComponentsOrder = createRule({
|
|
|
4859
4902
|
return;
|
|
4860
4903
|
}
|
|
4861
4904
|
if (currentIndex < maxDefIndex) {
|
|
4862
|
-
const isDependencyForEarlier = earlierRendered.some(earlier =>
|
|
4905
|
+
const isDependencyForEarlier = earlierRendered.some(earlier => getTransitiveDeps(earlier).has(name));
|
|
4863
4906
|
if (!isDependencyForEarlier) {
|
|
4864
4907
|
const definition = definitions.get(name);
|
|
4865
4908
|
if (definition) {
|