routie dev init since i didn't adhere to any proper guidance up until now

This commit is contained in:
2026-04-29 22:27:29 -06:00
commit e1dabb71e2
15301 changed files with 3562618 additions and 0 deletions
@@ -0,0 +1,185 @@
import { getNewlinesBetweenOption } from './get-newlines-between-option.js'
import { getLinesBetween } from './get-lines-between.js'
import { getGroupIndex } from './get-group-index.js'
import { getNodeRange } from './get-node-range.js'
/**
* Generates fixes for adjusting newlines between groups of sorted elements.
*
* Processes pairs of adjacent nodes to ensure the correct number of newlines
* between them based on their group membership and configuration. The
* function:
*
* - Skips nodes in different partitions (they're sorted independently)
* - Skips cases where group order would be violated
* - Respects 'ignore' settings that preserve existing spacing
* - Calculates required newlines based on group configuration
* - Applies custom newlines getter if provided.
*
* @example
*
* ```ts
* // Configuration with newlines between groups
* const options = {
* groups: ['imports', 'types', 'functions'],
* newlinesBetween: 1, // 1 newline between groups
* }
*
* // Original: imports and types with no separation
* // After fix: adds 1 blank line between import and type groups
* ```
*
* @example
*
* ```ts
* // Custom newlines getter
* const newlinesBetweenValueGetter = ({
* left,
* right,
* computedNewlinesBetween,
* }) => {
* // Add extra newline before main function
* if (right.name === 'main') {
* return computedNewlinesBetween + 1
* }
* return computedNewlinesBetween
* }
* ```
*
* @template T - Type of sorting node.
* @param params - Parameters for generating newlines fixes.
* @returns Array of ESLint fix operations to adjust spacing.
*/
function makeNewlinesBetweenFixes({
newlinesBetweenValueGetter,
sortedNodes,
sourceCode,
options,
fixer,
nodes,
}) {
let fixes = []
for (let i = 0; i < sortedNodes.length - 1; i++) {
let sortingNode = nodes.at(i)
let nextSortingNode = nodes.at(i + 1)
let sortedSortingNode = sortedNodes.at(i)
let nextSortedSortingNode = sortedNodes.at(i + 1)
if (sortedSortingNode.partitionId !== nextSortedSortingNode.partitionId) {
continue
}
let nodeGroupIndex = getGroupIndex(options.groups, sortedSortingNode)
let nextNodeGroupIndex = getGroupIndex(
options.groups,
nextSortedSortingNode,
)
if (nodeGroupIndex > nextNodeGroupIndex) {
continue
}
let newlinesBetween = getNewlinesBetweenOption({
nextNodeGroupIndex,
nodeGroupIndex,
options,
})
newlinesBetween =
newlinesBetweenValueGetter?.({
computedNewlinesBetween: newlinesBetween,
right: nextSortedSortingNode,
left: sortedSortingNode,
}) ?? newlinesBetween
if (newlinesBetween === 'ignore') {
continue
}
let currentNodeRange = getNodeRange({
node: sortingNode.node,
sourceCode,
})
let nextNodeRangeStart = getNodeRange({
node: nextSortingNode.node,
sourceCode,
}).at(0)
if (
getLinesBetween(sourceCode, sortingNode, nextSortingNode) ===
newlinesBetween
) {
continue
}
let rangeToReplace = [currentNodeRange.at(1), nextNodeRangeStart]
let textBetweenNodes = sourceCode.text.slice(
currentNodeRange.at(1),
nextNodeRangeStart,
)
let rangeReplacement = computeRangeReplacement({
isOnSameLine:
sortingNode.node.loc.end.line === nextSortingNode.node.loc.start.line,
textBetweenNodes,
newlinesBetween,
})
fixes.push(fixer.replaceTextRange(rangeToReplace, rangeReplacement))
}
return fixes
}
/**
* Computes the replacement text for adjusting newlines between nodes.
*
* Handles the logic of adding or removing newlines while preserving necessary
* content like comments and semicolons. Special handling for:
*
* - Removing excessive newlines when fewer are needed
* - Adding newlines when more are needed
* - Preserving inline placement when nodes are on the same line.
*
* @param params - Parameters for computing replacement.
* @param params.textBetweenNodes - Original text between the two nodes.
* @param params.newlinesBetween - Number of newlines required (0 or more).
* @param params.isOnSameLine - Whether nodes are currently on the same line.
* @returns Replacement text with correct newlines, or undefined if no change
* needed.
*/
function computeRangeReplacement({
textBetweenNodes,
newlinesBetween,
isOnSameLine,
}) {
let textBetweenNodesWithoutInvalidNewlines =
getStringWithoutInvalidNewlines(textBetweenNodes)
if (newlinesBetween === 0) {
return textBetweenNodesWithoutInvalidNewlines
}
let rangeReplacement = textBetweenNodesWithoutInvalidNewlines
for (let index = 0; index < newlinesBetween; index++) {
rangeReplacement = addNewlineBeforeFirstNewline(rangeReplacement)
}
if (!isOnSameLine) {
return rangeReplacement
}
return addNewlineBeforeFirstNewline(rangeReplacement)
}
/**
* Adds a newline before the first existing newline or at the end of string.
*
* Used to incrementally add newlines while preserving existing content. If no
* newline exists, appends one at the end. Otherwise, inserts before the first
* newline to maintain proper spacing.
*
* @param value - String to add a newline to.
* @returns String with an additional newline.
*/
function addNewlineBeforeFirstNewline(value) {
let firstNewlineIndex = value.indexOf('\n')
if (firstNewlineIndex === -1) {
return `${value}\n`
}
return `${value.slice(0, firstNewlineIndex)}\n${value.slice(firstNewlineIndex)}`
}
/**
* Removes excessive newlines from a string.
*
* Normalizes spacing by collapsing multiple consecutive newlines into single
* newlines and removing empty lines that contain only whitespace.
*
* @param value - String potentially containing excessive newlines.
* @returns String with normalized newlines.
*/
function getStringWithoutInvalidNewlines(value) {
return value.replaceAll(/\n\s*\n/gu, '\n').replaceAll(/\n+/gu, '\n')
}
export { makeNewlinesBetweenFixes }