mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 16:02:32 +00:00
#14397 split `shared/types.ts` into 46 per-domain modules but kept the path as a re-export barrel so the import sites did not have to change. This removes the barrel: every consumer now imports from the module that actually declares the type, and `src/shared/types.ts` is deleted. Barrels hide where a type lives, make every consumer look like it depends on the whole domain, and let an unrelated edit invalidate a module that ~2,000 files transitively import. 2,323 import declarations across 2,321 files. Rewritten mechanically: each specifier was resolved to an absolute path via the TypeScript AST and recomputed, rather than string-substituted, so alias forms (`@/../../shared/ types`) and per-specifier `type` modifiers survive. Four cases the mechanical pass had to handle, each found by a gate rather than by reading the diff: - Modules inside `src/shared` import the barrel as `./types`, not `shared/types`. A pre-filter on the latter string skipped 176 of them and left imports dangling at a deleted file, which surfaced as confusing `Property 'x' is optional in type 'Repo' but required in Pick<Repo, ...>` errors rather than "module not found". - The barrel RENAMED one type on the way through (`WorkspaceSource as WorkspaceCreateTelemetrySource`), so the original name in the owning module has to be re-aliased at each consumer. - Three test files put `;(globalThis as ...)` on the line after the import. TypeScript parses that `;` as the import statement's terminator, so replacing through `statement.getEnd()` deletes it and breaks ASI. The rewrite now stops at the module specifier. - A file that already imported directly from a module got a SECOND import from it, because the barrel re-exported those same names — which trips `import/no-duplicates` under `--deny-warnings`. A post-pass merges declarations sharing a specifier and type-only-ness; the `import type` plus `import` pair from one module is left alone, since that form is allowed. Splitting one barrel import into several genuinely adds lines, which pushed `terminal-layout-pty-ownership.ts` to 301 counted lines: its 107-character import must wrap, and neither local type collapses onto one line (101 and 116 characters). Rather than contort a type declaration to fit a line budget, `collectLeafIds` and `pruneLeaves` move to `terminal-pane-layout-tree.ts` — they are pure structural operations on the layout tree and independent of PTY ownership. `visible-worktrees.ts` similarly loses its own mini-barrel re-export of `isDefaultBranchWorkspace`, with the four real consumers repointed at the declaring module. No `max-lines` bypass added. Verified: cold `tsc --noEmit` green on node, cli, and web (buildinfo deleted first — these projects are `composite: true` and reuse stale caches); the full `pnpm lint` green, not just bare oxlint — the narrower local check is what let the duplicate imports reach CI; max-lines ratchet OK at 344.
161 lines
4.7 KiB
TypeScript
161 lines
4.7 KiB
TypeScript
import { Pressable, StyleSheet, Text, View } from 'react-native'
|
|
import { MessageSquare } from 'lucide-react-native'
|
|
import type { DiffComment } from '../../../src/shared/diff-comment-types'
|
|
import type { MobileDiffLine } from '../session/mobile-diff-lines'
|
|
import type { MobileHighlightedDiffLine } from '../session/mobile-file-syntax'
|
|
import { mobileDiffLineNumber, mobileDiffLinePrefix } from '../source-control/mobile-diff-format'
|
|
import { colors, spacing, typography } from '../theme/mobile-theme'
|
|
import { MobileSyntaxSegments } from './MobileSyntaxSegments'
|
|
|
|
type Props = {
|
|
line: MobileHighlightedDiffLine<MobileDiffLine>
|
|
comments: readonly DiffComment[]
|
|
staleCommentIds: ReadonlySet<string>
|
|
active: boolean
|
|
onAddNote: (lineNumber: number) => void
|
|
onEditNote: (comment: DiffComment) => void
|
|
}
|
|
|
|
function accessibilityLabelForLine(line: MobileDiffLine): string {
|
|
const number = mobileDiffLineNumber(line)
|
|
const label = line.kind === 'add' ? 'Added' : line.kind === 'delete' ? 'Deleted' : 'Context'
|
|
return number ? `${label} line ${number}` : `${label} line`
|
|
}
|
|
|
|
function canCommentOnLine(line: MobileDiffLine): boolean {
|
|
return line.kind !== 'delete' && line.newLineNumber !== undefined
|
|
}
|
|
|
|
export function MobileDiffReviewLine({
|
|
line,
|
|
comments,
|
|
staleCommentIds,
|
|
active,
|
|
onAddNote,
|
|
onEditNote
|
|
}: Props) {
|
|
const lineNumber = mobileDiffLineNumber(line)
|
|
const canComment = canCommentOnLine(line)
|
|
|
|
return (
|
|
<View
|
|
style={[
|
|
styles.row,
|
|
line.kind === 'add' && styles.addedRow,
|
|
line.kind === 'delete' && styles.deletedRow,
|
|
active && styles.activeRow
|
|
]}
|
|
accessible
|
|
accessibilityLabel={accessibilityLabelForLine(line)}
|
|
>
|
|
<Text style={styles.prefix}>{mobileDiffLinePrefix(line.kind)}</Text>
|
|
<Text style={styles.lineNumber}>{lineNumber ? String(lineNumber) : ''}</Text>
|
|
<Pressable
|
|
style={({ pressed }) => [styles.code, pressed && canComment && styles.codePressed]}
|
|
disabled={!canComment}
|
|
onPress={() => {
|
|
if (canComment && line.newLineNumber !== undefined) {
|
|
onAddNote(line.newLineNumber)
|
|
}
|
|
}}
|
|
accessibilityRole={canComment ? 'button' : 'text'}
|
|
accessibilityLabel={
|
|
canComment && line.newLineNumber !== undefined
|
|
? `Add note on line ${line.newLineNumber}`
|
|
: accessibilityLabelForLine(line)
|
|
}
|
|
>
|
|
<Text style={styles.codeText}>
|
|
<MobileSyntaxSegments segments={line.segments} />
|
|
</Text>
|
|
</Pressable>
|
|
{comments.length > 0 ? (
|
|
<View style={styles.notes}>
|
|
{comments.map((comment) => (
|
|
<Pressable
|
|
key={comment.id}
|
|
style={({ pressed }) => [styles.noteButton, pressed && styles.noteButtonPressed]}
|
|
onPress={() => onEditNote(comment)}
|
|
accessibilityRole="button"
|
|
accessibilityLabel={`Edit note on line ${comment.lineNumber}`}
|
|
>
|
|
<MessageSquare
|
|
size={13}
|
|
color={staleCommentIds.has(comment.id) ? colors.statusAmber : colors.textSecondary}
|
|
strokeWidth={2}
|
|
/>
|
|
</Pressable>
|
|
))}
|
|
</View>
|
|
) : null}
|
|
</View>
|
|
)
|
|
}
|
|
|
|
// Row height comes from the 18px code lineHeight alone (no vertical padding or
|
|
// minHeight) so mobile diff density matches the desktop diff editor (STA-1239).
|
|
const styles = StyleSheet.create({
|
|
row: {
|
|
flexDirection: 'row',
|
|
alignItems: 'stretch',
|
|
borderBottomWidth: StyleSheet.hairlineWidth,
|
|
borderBottomColor: colors.borderSubtle
|
|
},
|
|
addedRow: {
|
|
backgroundColor: colors.diffAddedBg
|
|
},
|
|
deletedRow: {
|
|
backgroundColor: colors.diffDeletedBg
|
|
},
|
|
activeRow: {
|
|
borderLeftWidth: 2,
|
|
borderLeftColor: colors.accentBlue
|
|
},
|
|
prefix: {
|
|
width: 18,
|
|
textAlign: 'center',
|
|
color: colors.textMuted,
|
|
fontFamily: typography.monoFamily,
|
|
fontSize: typography.metaSize,
|
|
lineHeight: 18
|
|
},
|
|
lineNumber: {
|
|
width: 44,
|
|
paddingRight: spacing.xs,
|
|
textAlign: 'right',
|
|
color: colors.textMuted,
|
|
fontFamily: typography.monoFamily,
|
|
fontSize: typography.metaSize,
|
|
lineHeight: 18
|
|
},
|
|
code: {
|
|
flex: 1,
|
|
minWidth: 0,
|
|
paddingHorizontal: spacing.sm
|
|
},
|
|
codePressed: {
|
|
backgroundColor: colors.bgRaised
|
|
},
|
|
codeText: {
|
|
color: colors.textPrimary,
|
|
fontFamily: typography.monoFamily,
|
|
fontSize: 12,
|
|
lineHeight: 18
|
|
},
|
|
notes: {
|
|
width: 40,
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
gap: 2
|
|
},
|
|
noteButton: {
|
|
minWidth: 32,
|
|
minHeight: 28,
|
|
alignItems: 'center',
|
|
justifyContent: 'center'
|
|
},
|
|
noteButtonPressed: {
|
|
opacity: 0.72
|
|
}
|
|
})
|